mirror of
https://github.com/hanzoai/esbuild.git
synced 2026-09-24 16:58:50 +00:00
remove the deno package and tests
This commit is contained in:
@@ -115,11 +115,6 @@ jobs:
|
||||
with:
|
||||
node-version: 18
|
||||
|
||||
- name: Setup Deno 1.40.0
|
||||
uses: denoland/setup-deno@main
|
||||
with:
|
||||
deno-version: v1.40.0
|
||||
|
||||
- name: go test
|
||||
env:
|
||||
WT_SESSION: 1 # Ensure that FormatMessages output on Windows matches macOS
|
||||
@@ -128,14 +123,6 @@ jobs:
|
||||
- name: go vet
|
||||
run: go vet ./cmd/... ./internal/... ./pkg/...
|
||||
|
||||
- name: Deno Tests (non-Windows)
|
||||
if: matrix.os != 'windows-latest'
|
||||
run: make test-deno
|
||||
|
||||
- name: Deno Tests (Windows)
|
||||
if: matrix.os == 'windows-latest'
|
||||
run: make test-deno-windows
|
||||
|
||||
- name: Test for path/filepath
|
||||
if: matrix.os == 'ubuntu-latest'
|
||||
run: make no-filepath
|
||||
@@ -245,88 +232,3 @@ jobs:
|
||||
|
||||
- name: go test
|
||||
run: go test ./internal/...
|
||||
|
||||
esbuild-old-deno-version:
|
||||
name: esbuild CI (old Deno version)
|
||||
runs-on: ${{ matrix.os }}
|
||||
strategy:
|
||||
matrix:
|
||||
# Note: I'm excluding "macos-latest" here because GitHub recently
|
||||
# changed their macOS CI VMs from x86_64 to aarch64 (i.e. from Intel
|
||||
# to ARM) and it looks like old Deno versions have WASM bugs on ARM.
|
||||
# Specifically, this test now crashes like this when run on macOS:
|
||||
#
|
||||
# #
|
||||
# # Fatal error in , line 0
|
||||
# # Check failed: RwxMemoryWriteScope::IsAllowed().
|
||||
# #
|
||||
# #
|
||||
# #
|
||||
# #FailureMessage Object: 0x16f282368
|
||||
# ==== C stack trace ===============================
|
||||
#
|
||||
# 0 deno 0x0000000101bb8e78 v8::base::debug::StackTrace::StackTrace() + 24
|
||||
# 1 deno 0x0000000101bbda84 v8::platform::(anonymous namespace)::PrintStackTrace() + 24
|
||||
# 2 deno 0x0000000101bb6230 V8_Fatal(char const*, ...) + 268
|
||||
# 3 deno 0x000000010227e468 v8::internal::wasm::WasmCodeManager::MemoryProtectionKeysEnabled() const + 0
|
||||
# 4 deno 0x0000000102299994 v8::internal::wasm::WasmEngine::InitializeOncePerProcess() + 44
|
||||
# 5 deno 0x0000000101e78fd0 v8::internal::V8::Initialize() + 1576
|
||||
# 6 deno 0x0000000101c3b7d8 v8::V8::Initialize(int) + 32
|
||||
# 7 deno 0x00000001011833dc _ZN3std4sync4once4Once9call_once28_$u7b$$u7b$closure$u7d$$u7d$17h2bbe74d315ab3e84E + 488
|
||||
# 8 deno 0x00000001017f8854 std::sync::once::Once::call_inner::h70fbdd48fe002a01 + 724
|
||||
# 9 deno 0x000000010115ca80 deno_core::runtime::JsRuntime::new::h9c5f1a9c910f1eed + 192
|
||||
# 10 deno 0x00000001014d3b50 deno_runtime::worker::MainWorker::bootstrap_from_options::h91a0eaac48dfc18e + 4260
|
||||
# 11 deno 0x0000000100ee692c deno::create_main_worker::h0d1622755821ae7f + 1608
|
||||
# 12 deno 0x0000000100f6c688 _ZN97_$LT$core..future..from_generator..GenFuture$LT$T$GT$$u20$as$u20$core..future..future..Future$GT$4poll17h87ddfac9566887c8E + 492
|
||||
# 13 deno 0x0000000100f6ba18 tokio::runtime::task::raw::poll::h7d51f1a7d5a61c15 + 1396
|
||||
# 14 deno 0x0000000101917b98 std::sys_common::backtrace::__rust_begin_short_backtrace::hd384935dcffe6f2d + 332
|
||||
# 15 deno 0x0000000101917954 _ZN4core3ops8function6FnOnce40call_once$u7b$$u7b$vtable.shim$u7d$$u7d$17he2755732d5d29cf0E + 124
|
||||
# 16 deno 0x0000000101829684 std::sys::unix::thread::Thread::new::thread_start::h432bc30153e41f60 + 48
|
||||
# 17 libsystem_pthread.dylib 0x000000018a436f94 _pthread_start + 136
|
||||
# 18 libsystem_pthread.dylib 0x000000018a431d34 thread_start + 8
|
||||
#
|
||||
# Hopefully running this old Deno version on Linux is sufficiently
|
||||
# close to running it on macOS. For reference, I believe this is the
|
||||
# change that GitHub made which broke this test:
|
||||
# https://github.blog/changelog/2023-10-02-github-actions-apple-silicon-m1-macos-runners-are-now-available-in-public-beta/
|
||||
os: [ubuntu-latest, windows-latest]
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Read go.version (non-Windows)
|
||||
if: matrix.os != 'windows-latest'
|
||||
run: |
|
||||
echo "GO_VERSION=$(cat go.version)" >> $GITHUB_ENV
|
||||
|
||||
- name: Read go.version (Windows)
|
||||
if: matrix.os == 'windows-latest'
|
||||
run: |
|
||||
echo "GO_VERSION=$(cat go.version)" >> $Env:GITHUB_ENV
|
||||
|
||||
- name: Set up Go ${{ env.GO_VERSION }}
|
||||
uses: actions/setup-go@v3
|
||||
with:
|
||||
go-version: ${{ env.GO_VERSION }}
|
||||
id: go
|
||||
|
||||
# Make sure esbuild works with old versions of Deno. Note: It's important
|
||||
# to test a version before 1.31.0, which introduced the "Deno.Command" API.
|
||||
- name: Setup Deno 1.24.0
|
||||
uses: denoland/setup-deno@main
|
||||
with:
|
||||
deno-version: v1.24.0
|
||||
|
||||
- name: Setup Node.js environment
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 18
|
||||
|
||||
- name: Deno Tests (non-Windows)
|
||||
if: matrix.os != 'windows-latest'
|
||||
run: make test-deno
|
||||
|
||||
- name: Deno Tests (Windows)
|
||||
if: matrix.os == 'windows-latest'
|
||||
run: make test-deno-windows
|
||||
|
||||
@@ -20,13 +20,6 @@ jobs:
|
||||
with:
|
||||
node-version: 18
|
||||
|
||||
# The version of Deno is pinned because version 1.25.1 was causing test
|
||||
# flakes due to random segfaults.
|
||||
- name: Setup Deno 1.24.0
|
||||
uses: denoland/setup-deno@main
|
||||
with:
|
||||
deno-version: v1.24.0
|
||||
|
||||
- name: Test npm
|
||||
run: |
|
||||
npm i -g npm@next-7
|
||||
@@ -46,7 +39,3 @@ jobs:
|
||||
run: |
|
||||
npm i -g yarn@latest
|
||||
time make test-e2e-yarn-berry
|
||||
|
||||
- name: Test deno
|
||||
run: |
|
||||
time make test-e2e-deno
|
||||
|
||||
@@ -3,11 +3,9 @@
|
||||
.vscode/
|
||||
/bench/
|
||||
/demo/
|
||||
/deno/
|
||||
/esbuild
|
||||
/github/
|
||||
/go/
|
||||
/lib/deno/lib.deno.d.ts
|
||||
/npm/@esbuild/android-arm/esbuild.wasm
|
||||
/npm/@esbuild/android-arm/wasm_exec_node.js
|
||||
/npm/@esbuild/android-arm/wasm_exec.js
|
||||
|
||||
@@ -2,6 +2,10 @@
|
||||
|
||||
## Unreleased
|
||||
|
||||
* Stop publishing to https://deno.land/x/esbuild
|
||||
|
||||
Deno has made the https://deno.land/x package registry read-only, so new versions of esbuild can no longer be published to https://deno.land/x/esbuild. The last published version was [v0.28.1](https://deno.land/x/[email protected]). I have removed the parts of esbuild that publish a Deno-specific package. Instead you can install `npm:esbuild` to use esbuild in Deno (this wasn't the case when esbuild's Deno-specific package was first published).
|
||||
|
||||
* Emit an error when code splitting chunks would be merged ([#4411](https://github.com/evanw/esbuild/issues/4411))
|
||||
|
||||
It's possible to configure esbuild such that separate output files end up with the same output path. For example, you could name all code splitting chunks `chunk` via the `chunkNames` setting, which might generate multiple output files with the same path `chunk.js`. This does not happen by default since by default the chunk names include a hash to make sure they're unique (e.g. named something like `chunk-GX7G2SBE.js` instead).
|
||||
|
||||
@@ -24,7 +24,7 @@ test-common: test-go vet-go no-filepath verify-source-map end-to-end-tests js-ap
|
||||
|
||||
# These tests are for release (the extra tests are not included in "test" because they are pretty slow)
|
||||
test-all:
|
||||
@$(MAKE) --no-print-directory -j6 test-common test-deno ts-type-tests test-wasm-node test-wasm-browser lib-typecheck test-yarnpnp
|
||||
@$(MAKE) --no-print-directory -j6 test-common ts-type-tests test-wasm-node test-wasm-browser lib-typecheck test-yarnpnp
|
||||
|
||||
check-go-version:
|
||||
@go version | grep -F " go$(GO_VERSION) " || (echo 'Please install Go version $(GO_VERSION)' && false)
|
||||
@@ -98,16 +98,6 @@ test-wasm-node: esbuild
|
||||
test-wasm-browser: platform-wasm | scripts/browser/node_modules
|
||||
cd scripts/browser && node browser-tests.js
|
||||
|
||||
test-deno: esbuild platform-deno
|
||||
ESBUILD_BINARY_PATH="$(shell pwd)/esbuild" deno test --allow-run --allow-env --allow-net --allow-read --allow-write --no-check scripts/deno-tests.js
|
||||
@echo '✅ deno tests passed' # I couldn't find a Deno API for telling when tests have failed, so I'm doing this here instead
|
||||
ESBUILD_BINARY_PATH="$(shell pwd)/esbuild" deno eval 'import { transform, stop } from "file://$(shell pwd)/deno/mod.js"; console.log((await transform("1+2")).code); stop()' | grep "1 + 2;"
|
||||
ESBUILD_BINARY_PATH="$(shell pwd)/esbuild" deno eval 'import { transform, stop } from "file://$(shell pwd)/deno/wasm.js"; console.log((await transform("1+2")).code); stop()' | grep "1 + 2;"
|
||||
ESBUILD_BINARY_PATH="$(shell pwd)/esbuild" deno run -A './deno/mod.js' # See: https://github.com/evanw/esbuild/pull/3917
|
||||
|
||||
test-deno-windows: esbuild platform-deno
|
||||
ESBUILD_BINARY_PATH=./esbuild.exe deno test --allow-run --allow-env --allow-net --allow-read --allow-write --no-check scripts/deno-tests.js
|
||||
|
||||
register-test: version-go | scripts/node_modules
|
||||
node scripts/esbuild.js npm/esbuild/package.json --version
|
||||
node scripts/register-test.js
|
||||
@@ -152,7 +142,7 @@ test-old-ts: | require/old-ts/node_modules
|
||||
node-unref-tests: | scripts/node_modules
|
||||
node scripts/node-unref-tests.js
|
||||
|
||||
lib-typecheck: lib-typecheck-node lib-typecheck-node-nolib lib-typecheck-deno
|
||||
lib-typecheck: lib-typecheck-node lib-typecheck-node-nolib
|
||||
|
||||
lib-typecheck-node: | lib/node_modules
|
||||
cd lib && node_modules/.bin/tsc -noEmit -p tsconfig.json
|
||||
@@ -160,14 +150,8 @@ lib-typecheck-node: | lib/node_modules
|
||||
lib-typecheck-node-nolib: | lib/node_modules
|
||||
cd lib && node_modules/.bin/tsc -noEmit -p tsconfig-nolib.json
|
||||
|
||||
lib-typecheck-deno: lib/deno/lib.deno.d.ts | lib/node_modules
|
||||
cd lib && node_modules/.bin/tsc -noEmit -p tsconfig-deno.json
|
||||
|
||||
lib/deno/lib.deno.d.ts:
|
||||
deno types > lib/deno/lib.deno.d.ts
|
||||
|
||||
# End-to-end tests
|
||||
test-e2e: test-e2e-npm test-e2e-pnpm test-e2e-yarn test-e2e-yarn-berry test-e2e-deno
|
||||
test-e2e: test-e2e-npm test-e2e-pnpm test-e2e-yarn test-e2e-yarn-berry
|
||||
|
||||
test-e2e-npm:
|
||||
# Test normal install
|
||||
@@ -296,10 +280,6 @@ test-e2e-yarn-berry:
|
||||
# Clean up
|
||||
rm -fr e2e-yb
|
||||
|
||||
test-e2e-deno:
|
||||
deno eval 'import { transform, stop } from "https://deno.land/x/esbuild@v$(ESBUILD_VERSION)/mod.js"; console.log((await transform("1+2")).code); stop()' | grep "1 + 2;"
|
||||
deno eval 'import { transform, stop } from "https://deno.land/x/esbuild@v$(ESBUILD_VERSION)/wasm.js"; console.log((await transform("1+2")).code); stop()' | grep "1 + 2;"
|
||||
|
||||
test-yarnpnp: platform-wasm
|
||||
node scripts/test-yarnpnp.js
|
||||
|
||||
@@ -320,7 +300,6 @@ version-go:
|
||||
platform-all: \
|
||||
platform-android-arm \
|
||||
platform-android-x64 \
|
||||
platform-deno \
|
||||
platform-neutral \
|
||||
platform-openharmony-arm64 \
|
||||
platform-wasi-preview1 \
|
||||
@@ -463,11 +442,6 @@ platform-wasm: esbuild go-compiler
|
||||
$(GO_COMPILER) "$(NODE)" scripts/esbuild.js ./esbuild --wasm
|
||||
@shasum -a 256 npm/esbuild-wasm/esbuild.wasm
|
||||
|
||||
platform-deno: platform-wasm go-compiler
|
||||
@echo
|
||||
@echo "# Build: deno"
|
||||
$(GO_COMPILER) "$(NODE)" scripts/esbuild.js ./esbuild --deno
|
||||
|
||||
publish-all: check-go-version
|
||||
# Make sure the npm directory is pristine (including .gitignored files) since it will be published
|
||||
rm -fr npm && git checkout npm
|
||||
|
||||
-13
@@ -23,19 +23,6 @@ Pushing a change to [`version.txt`](./version.txt) causes the following:
|
||||
2. Create a tag for the release that looks like `v0.X.Y`
|
||||
3. Publish a [GitHub Release](https://github.com/evanw/esbuild/releases) containing the release notes in [`CHANGELOG.md`](./CHANGELOG.md)
|
||||
|
||||
- The [`release.yml`](https://github.com/esbuild/deno-esbuild/blob/main/.github/workflows/release.yml)
|
||||
workflow in the https://github.com/esbuild/deno-esbuild repo runs
|
||||
occasionally. On the next run, it will notice the version change and:
|
||||
|
||||
1. Clone this repo
|
||||
2. Run `make platform-deno`
|
||||
3. Commit and push the new contents of the `deno` folder to the `deno-esbuild` repo
|
||||
4. Create a tag for the release that looks like `v0.X.Y`
|
||||
5. Post an event to the https://api.deno.land/webhook/gh/esbuild webhook
|
||||
6. Deno will then add a new version to https://deno.land/x/esbuild
|
||||
|
||||
You can also manually trigger this workflow if you want it to happen immediately.
|
||||
|
||||
- The [`release.yml`](https://github.com/esbuild/esbuild.github.io/blob/main/.github/workflows/release.yml)
|
||||
workflow in the https://github.com/esbuild/esbuild.github.io repo runs
|
||||
occasionally. On the next run, it will notice the version change and:
|
||||
|
||||
Vendored
-6
@@ -1,6 +0,0 @@
|
||||
declare module "https://deno.land/x/[email protected]/mod.ts" {
|
||||
export function gunzip(input: Uint8Array): Uint8Array
|
||||
}
|
||||
|
||||
// This is used by "worker.ts"
|
||||
declare let onmessage: (event: any) => void
|
||||
-435
@@ -1,435 +0,0 @@
|
||||
import type * as types from "../shared/types"
|
||||
import * as common from "../shared/common"
|
||||
import * as ourselves from "./mod"
|
||||
import * as denoflate from "https://deno.land/x/[email protected]/mod.ts"
|
||||
|
||||
declare const ESBUILD_VERSION: string
|
||||
declare const ESBUILD_BINARY_HASHES: Record<string, string>
|
||||
|
||||
export let version = ESBUILD_VERSION
|
||||
|
||||
export let build: typeof types.build = (options: types.BuildOptions) =>
|
||||
ensureServiceIsRunning().then(service =>
|
||||
service.build(options))
|
||||
|
||||
export const context: typeof types.context = (options: types.BuildOptions) =>
|
||||
ensureServiceIsRunning().then(service =>
|
||||
service.context(options))
|
||||
|
||||
export const transform: typeof types.transform = (input: string | Uint8Array, options?: types.TransformOptions) =>
|
||||
ensureServiceIsRunning().then(service =>
|
||||
service.transform(input, options))
|
||||
|
||||
export const formatMessages: typeof types.formatMessages = (messages, options) =>
|
||||
ensureServiceIsRunning().then(service =>
|
||||
service.formatMessages(messages, options))
|
||||
|
||||
export const analyzeMetafile: typeof types.analyzeMetafile = (metafile, options) =>
|
||||
ensureServiceIsRunning().then(service =>
|
||||
service.analyzeMetafile(metafile, options))
|
||||
|
||||
export const buildSync: typeof types.buildSync = () => {
|
||||
throw new Error(`The "buildSync" API does not work in Deno`)
|
||||
}
|
||||
|
||||
export const transformSync: typeof types.transformSync = () => {
|
||||
throw new Error(`The "transformSync" API does not work in Deno`)
|
||||
}
|
||||
|
||||
export const formatMessagesSync: typeof types.formatMessagesSync = () => {
|
||||
throw new Error(`The "formatMessagesSync" API does not work in Deno`)
|
||||
}
|
||||
|
||||
export const analyzeMetafileSync: typeof types.analyzeMetafileSync = () => {
|
||||
throw new Error(`The "analyzeMetafileSync" API does not work in Deno`)
|
||||
}
|
||||
|
||||
export const stop = async () => {
|
||||
if (stopService) await stopService()
|
||||
}
|
||||
|
||||
let initializeWasCalled = false
|
||||
|
||||
export const initialize: typeof types.initialize = async (options) => {
|
||||
options = common.validateInitializeOptions(options || {})
|
||||
if (options.wasmURL) throw new Error(`The "wasmURL" option only works in the browser`)
|
||||
if (options.wasmModule) throw new Error(`The "wasmModule" option only works in the browser`)
|
||||
if (options.worker) throw new Error(`The "worker" option only works in the browser`)
|
||||
if (initializeWasCalled) throw new Error('Cannot call "initialize" more than once')
|
||||
await ensureServiceIsRunning()
|
||||
initializeWasCalled = true
|
||||
}
|
||||
|
||||
async function binaryIntegrityCheck(pkg: string, subpath: string, bytes: Uint8Array): Promise<void> {
|
||||
const hashBuffer = await crypto.subtle.digest('SHA-256', bytes as Uint8Array<ArrayBuffer>)
|
||||
const hash = Array.from(new Uint8Array(hashBuffer)).map(b => b.toString(16).padStart(2, '0')).join('')
|
||||
const key = `${pkg}/${subpath}`
|
||||
const expected = ESBUILD_BINARY_HASHES[key]
|
||||
if (!expected) throw new Error(`Missing hash for "${key}"`)
|
||||
if (hash !== expected) throw new Error(`"${hash.slice(0, 8)}..." doesn't match "${expected.slice(0, 8)}..." for "${pkg}"`)
|
||||
}
|
||||
|
||||
async function installFromNPM(name: string, subpath: string): Promise<string> {
|
||||
const { finalPath, finalDir } = getCachePath(name)
|
||||
try {
|
||||
await Deno.stat(finalPath)
|
||||
return finalPath
|
||||
} catch (e) {
|
||||
}
|
||||
|
||||
const npmRegistry = Deno.env.get("NPM_CONFIG_REGISTRY") || "https://registry.npmjs.org"
|
||||
const url = `${npmRegistry}/${name}/-/${name.replace("@esbuild/", "")}-${version}.tgz`
|
||||
const buffer = await fetch(url).then(r => r.arrayBuffer())
|
||||
const executable = extractFileFromTarGzip(new Uint8Array(buffer), subpath)
|
||||
await binaryIntegrityCheck(name, subpath, executable)
|
||||
|
||||
await Deno.mkdir(finalDir, {
|
||||
recursive: true,
|
||||
mode: 0o700, // https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html
|
||||
})
|
||||
|
||||
await Deno.writeFile(finalPath, executable, { mode: 0o755 })
|
||||
return finalPath
|
||||
}
|
||||
|
||||
function getCachePath(name: string): { finalPath: string, finalDir: string } {
|
||||
let baseDir: string | undefined
|
||||
|
||||
switch (Deno.build.os) {
|
||||
case 'darwin':
|
||||
baseDir = Deno.env.get('HOME')
|
||||
if (baseDir) baseDir += '/Library/Caches'
|
||||
break
|
||||
|
||||
case 'windows':
|
||||
baseDir = Deno.env.get('LOCALAPPDATA')
|
||||
if (!baseDir) {
|
||||
baseDir = Deno.env.get('USERPROFILE')
|
||||
if (baseDir) baseDir += '/AppData/Local'
|
||||
}
|
||||
if (baseDir) baseDir += '/Cache'
|
||||
break
|
||||
|
||||
case 'linux':
|
||||
// https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html
|
||||
const xdg = Deno.env.get('XDG_CACHE_HOME')
|
||||
if (xdg && xdg[0] === '/') baseDir = xdg
|
||||
break
|
||||
}
|
||||
|
||||
if (!baseDir) {
|
||||
baseDir = Deno.env.get('HOME')
|
||||
if (baseDir) baseDir += '/.cache'
|
||||
}
|
||||
|
||||
if (!baseDir) throw new Error('Failed to find cache directory')
|
||||
const finalDir = baseDir + `/esbuild/bin`
|
||||
const finalPath = finalDir + `/${name.replace('/', '-')}@${version}`
|
||||
return { finalPath, finalDir }
|
||||
}
|
||||
|
||||
function extractFileFromTarGzip(buffer: Uint8Array, file: string): Uint8Array {
|
||||
try {
|
||||
buffer = denoflate.gunzip(buffer)
|
||||
} catch (err: any) {
|
||||
throw new Error(`Invalid gzip data in archive: ${err && err.message || err}`)
|
||||
}
|
||||
let str = (i: number, n: number) => String.fromCharCode(...buffer.subarray(i, i + n)).replace(/\0.*$/, '')
|
||||
let offset = 0
|
||||
file = `package/${file}`
|
||||
while (offset < buffer.length) {
|
||||
let name = str(offset, 100)
|
||||
let size = parseInt(str(offset + 124, 12), 8)
|
||||
offset += 512
|
||||
if (!isNaN(size) && size >= 0) {
|
||||
if (name === file) return buffer.subarray(offset, offset + size)
|
||||
offset += (size + 511) & ~511
|
||||
}
|
||||
}
|
||||
throw new Error(`Could not find ${JSON.stringify(file)} in archive`)
|
||||
}
|
||||
|
||||
async function install(): Promise<string> {
|
||||
const overridePath = Deno.env.get('ESBUILD_BINARY_PATH')
|
||||
if (overridePath) return overridePath
|
||||
|
||||
const platformKey = Deno.build.target
|
||||
const knownWindowsPackages: Record<string, string> = {
|
||||
'x86_64-pc-windows-msvc': '@esbuild/win32-x64',
|
||||
}
|
||||
const knownUnixlikePackages: Record<string, string> = {
|
||||
// These are the only platforms that Deno supports
|
||||
'aarch64-apple-darwin': '@esbuild/darwin-arm64',
|
||||
'aarch64-unknown-linux-gnu': '@esbuild/linux-arm64',
|
||||
'x86_64-apple-darwin': '@esbuild/darwin-x64',
|
||||
'x86_64-unknown-linux-gnu': '@esbuild/linux-x64',
|
||||
|
||||
// These platforms are not supported by Deno
|
||||
'aarch64-linux-android': '@esbuild/android-arm64',
|
||||
'x86_64-unknown-freebsd': '@esbuild/freebsd-x64',
|
||||
"x86_64-alpine-linux-musl": '@esbuild/linux-x64',
|
||||
}
|
||||
|
||||
// Pick a package to install
|
||||
if (platformKey in knownWindowsPackages) {
|
||||
return await installFromNPM(knownWindowsPackages[platformKey], 'esbuild.exe')
|
||||
} else if (platformKey in knownUnixlikePackages) {
|
||||
return await installFromNPM(knownUnixlikePackages[platformKey], 'bin/esbuild')
|
||||
} else {
|
||||
throw new Error(`Unsupported platform: ${platformKey}`)
|
||||
}
|
||||
}
|
||||
|
||||
interface Service {
|
||||
build: typeof types.build
|
||||
context: typeof types.context
|
||||
transform: typeof types.transform
|
||||
formatMessages: typeof types.formatMessages
|
||||
analyzeMetafile: typeof types.analyzeMetafile
|
||||
}
|
||||
|
||||
let defaultWD = Deno.cwd()
|
||||
let longLivedService: Promise<Service> | undefined
|
||||
let stopService: (() => Promise<void>) | undefined
|
||||
|
||||
// Declare a common subprocess API for the two implementations below
|
||||
type SpawnFn = (cmd: string, options: {
|
||||
args: string[]
|
||||
stdin: 'piped' | 'inherit'
|
||||
stdout: 'piped' | 'inherit'
|
||||
stderr: 'inherit'
|
||||
}) => {
|
||||
write(bytes: Uint8Array): void
|
||||
read(): Promise<Uint8Array | null>
|
||||
close(): Promise<void> | void
|
||||
status(): Promise<{ code: number }>
|
||||
}
|
||||
|
||||
// Deno ≥1.40
|
||||
const spawnNew: SpawnFn = (cmd, { args, stdin, stdout, stderr }) => {
|
||||
const child = new Deno.Command(cmd, {
|
||||
args,
|
||||
cwd: defaultWD,
|
||||
stdin,
|
||||
stdout,
|
||||
stderr,
|
||||
}).spawn()
|
||||
// Note: Need to check for "piped" in Deno ≥1.31.0 to avoid a crash
|
||||
const writer = stdin === 'piped' ? child.stdin.getWriter() : null
|
||||
const reader = stdout === 'piped' ? child.stdout.getReader() : null
|
||||
return {
|
||||
write: writer ? bytes => writer.write(bytes) : () => Promise.resolve(),
|
||||
read: reader ? () => reader.read().then(x => x.value || null) : () => Promise.resolve(null),
|
||||
close: async () => {
|
||||
// We can't call "kill()" because it doesn't seem to work. Tests will
|
||||
// still fail with "A child process was opened during the test, but not
|
||||
// closed during the test" even though we kill the child process.
|
||||
//
|
||||
// And we can't call both "writer.close()" and "kill()" because then
|
||||
// there's a race as the child process exits when stdin is closed, and
|
||||
// "kill()" fails when the child process has already been killed.
|
||||
//
|
||||
// So instead we just call "writer.close()" and then hope that this
|
||||
// causes the child process to exit. It won't work if the stdin consumer
|
||||
// thread in the child process is hung or busy, but that may be the best
|
||||
// we can do.
|
||||
//
|
||||
// See this for more info: https://github.com/evanw/esbuild/pull/3611
|
||||
if (writer) await writer.close()
|
||||
if (reader) await reader.cancel()
|
||||
|
||||
// Wait for the process to exit. The new "kill()" API doesn't flag the
|
||||
// process as having exited because processes can technically ignore the
|
||||
// kill signal. Without this, Deno will fail tests that use esbuild with
|
||||
// an error because the test spawned a process but didn't wait for it.
|
||||
await child.status
|
||||
},
|
||||
status: () => child.status,
|
||||
}
|
||||
}
|
||||
|
||||
// Deno <1.40
|
||||
const spawnOld: SpawnFn = (cmd, { args, stdin, stdout, stderr }) => {
|
||||
const child = Deno.run({
|
||||
cmd: [cmd].concat(args),
|
||||
cwd: defaultWD,
|
||||
stdin,
|
||||
stdout,
|
||||
stderr,
|
||||
})
|
||||
const stdoutBuffer = new Uint8Array(4 * 1024 * 1024)
|
||||
let writeQueue: Uint8Array[] = []
|
||||
let isQueueLocked = false
|
||||
|
||||
// We need to keep calling "write()" until it actually writes the data
|
||||
const startWriteFromQueueWorker = () => {
|
||||
if (isQueueLocked || writeQueue.length === 0) return
|
||||
isQueueLocked = true
|
||||
child.stdin!.write(writeQueue[0]).then(bytesWritten => {
|
||||
isQueueLocked = false
|
||||
if (bytesWritten === writeQueue[0].length) writeQueue.shift()
|
||||
else writeQueue[0] = writeQueue[0].subarray(bytesWritten)
|
||||
startWriteFromQueueWorker()
|
||||
})
|
||||
}
|
||||
|
||||
return {
|
||||
write: bytes => {
|
||||
writeQueue.push(bytes)
|
||||
startWriteFromQueueWorker()
|
||||
},
|
||||
read: () => child.stdout!.read(stdoutBuffer).then(n => n === null ? null : stdoutBuffer.subarray(0, n)),
|
||||
close: () => {
|
||||
child.stdin!.close()
|
||||
child.stdout!.close()
|
||||
child.close()
|
||||
},
|
||||
status: () => child.status(),
|
||||
}
|
||||
}
|
||||
|
||||
// This is a shim for "Deno.run" for newer versions of Deno
|
||||
const spawn: SpawnFn = Deno.Command ? spawnNew : spawnOld
|
||||
|
||||
const ensureServiceIsRunning = (): Promise<Service> => {
|
||||
if (!longLivedService) {
|
||||
longLivedService = (async (): Promise<Service> => {
|
||||
const binPath = await install()
|
||||
const isTTY = Deno.stderr.isTerminal
|
||||
? Deno.stderr.isTerminal() // Deno ≥1.40
|
||||
: Deno.isatty(Deno.stderr.rid) // Deno <1.40
|
||||
|
||||
const child = spawn(binPath, {
|
||||
args: [`--service=${version}`],
|
||||
stdin: 'piped',
|
||||
stdout: 'piped',
|
||||
stderr: 'inherit',
|
||||
})
|
||||
|
||||
stopService = async () => {
|
||||
// Close all resources related to the subprocess.
|
||||
await child.close()
|
||||
initializeWasCalled = false
|
||||
longLivedService = undefined
|
||||
stopService = undefined
|
||||
}
|
||||
|
||||
const { readFromStdout, afterClose, service } = common.createChannel({
|
||||
writeToStdin(bytes) {
|
||||
child.write(bytes)
|
||||
},
|
||||
isSync: false,
|
||||
hasFS: true,
|
||||
esbuild: ourselves,
|
||||
})
|
||||
|
||||
const readMoreStdout = () => child.read().then(buffer => {
|
||||
if (buffer === null) {
|
||||
afterClose(null)
|
||||
} else {
|
||||
readFromStdout(buffer)
|
||||
readMoreStdout()
|
||||
}
|
||||
}).catch(e => {
|
||||
if (e instanceof Deno.errors.Interrupted || e instanceof Deno.errors.BadResource) {
|
||||
// ignore the error if read was interrupted (stdout was closed)
|
||||
afterClose(e)
|
||||
} else {
|
||||
throw e
|
||||
}
|
||||
})
|
||||
readMoreStdout()
|
||||
|
||||
return {
|
||||
build: (options: types.BuildOptions) =>
|
||||
new Promise<types.BuildResult>((resolve, reject) => {
|
||||
service.buildOrContext({
|
||||
callName: 'build',
|
||||
refs: null,
|
||||
options,
|
||||
isTTY,
|
||||
defaultWD,
|
||||
callback: (err, res) => err ? reject(err) : resolve(res as types.BuildResult),
|
||||
})
|
||||
}),
|
||||
|
||||
context: (options: types.BuildOptions) =>
|
||||
new Promise<types.BuildContext>((resolve, reject) =>
|
||||
service.buildOrContext({
|
||||
callName: 'context',
|
||||
refs: null,
|
||||
options,
|
||||
isTTY,
|
||||
defaultWD,
|
||||
callback: (err, res) => err ? reject(err) : resolve(res as types.BuildContext),
|
||||
})),
|
||||
|
||||
transform: (input: string | Uint8Array, options?: types.TransformOptions) =>
|
||||
new Promise<types.TransformResult>((resolve, reject) =>
|
||||
service.transform({
|
||||
callName: 'transform',
|
||||
refs: null,
|
||||
input,
|
||||
options: options || {},
|
||||
isTTY,
|
||||
fs: {
|
||||
readFile(tempFile, callback) {
|
||||
Deno.readFile(tempFile).then(
|
||||
bytes => {
|
||||
let text = new TextDecoder().decode(bytes)
|
||||
try {
|
||||
Deno.remove(tempFile)
|
||||
} catch (e) {
|
||||
}
|
||||
callback(null, text)
|
||||
},
|
||||
err => callback(err, null),
|
||||
)
|
||||
},
|
||||
writeFile(contents, callback) {
|
||||
Deno.makeTempFile().then(
|
||||
tempFile => Deno.writeFile(tempFile, typeof contents === 'string' ? new TextEncoder().encode(contents) : contents).then(
|
||||
() => callback(tempFile),
|
||||
() => callback(null)),
|
||||
() => callback(null))
|
||||
},
|
||||
},
|
||||
callback: (err, res) => err ? reject(err) : resolve(res!),
|
||||
})),
|
||||
|
||||
formatMessages: (messages, options) =>
|
||||
new Promise((resolve, reject) =>
|
||||
service.formatMessages({
|
||||
callName: 'formatMessages',
|
||||
refs: null,
|
||||
messages,
|
||||
options,
|
||||
callback: (err, res) => err ? reject(err) : resolve(res!),
|
||||
})),
|
||||
|
||||
analyzeMetafile: (metafile, options) =>
|
||||
new Promise((resolve, reject) =>
|
||||
service.analyzeMetafile({
|
||||
callName: 'analyzeMetafile',
|
||||
refs: null,
|
||||
metafile: typeof metafile === 'string' ? metafile : JSON.stringify(metafile),
|
||||
options,
|
||||
callback: (err, res) => err ? reject(err) : resolve(res!),
|
||||
})),
|
||||
}
|
||||
})()
|
||||
}
|
||||
return longLivedService
|
||||
}
|
||||
|
||||
// If we're called as the main script, forward the CLI to the underlying executable
|
||||
if (import.meta.main) {
|
||||
spawn(await install(), {
|
||||
args: Deno.args,
|
||||
stdin: 'inherit',
|
||||
stdout: 'inherit',
|
||||
stderr: 'inherit',
|
||||
}).status().then(({ code }) => {
|
||||
Deno.exit(code)
|
||||
})
|
||||
}
|
||||
@@ -1,203 +0,0 @@
|
||||
import type * as types from "../shared/types"
|
||||
import * as common from "../shared/common"
|
||||
import * as ourselves from "./wasm"
|
||||
|
||||
interface Go {
|
||||
_scheduledTimeouts: Map<number, ReturnType<typeof setTimeout>>
|
||||
}
|
||||
|
||||
declare const ESBUILD_VERSION: string
|
||||
declare let WEB_WORKER_SOURCE_CODE: string
|
||||
declare let WEB_WORKER_FUNCTION: (postMessage: (data: Uint8Array) => void) => (event: { data: Uint8Array | ArrayBuffer | WebAssembly.Module }) => Go
|
||||
|
||||
export let version = ESBUILD_VERSION
|
||||
|
||||
export let build: typeof types.build = (options: types.BuildOptions) =>
|
||||
ensureServiceIsRunning().then(service =>
|
||||
service.build(options))
|
||||
|
||||
export const context: typeof types.context = (options: types.BuildOptions) =>
|
||||
ensureServiceIsRunning().then(service =>
|
||||
service.context(options))
|
||||
|
||||
export const transform: typeof types.transform = (input: string | Uint8Array, options?: types.TransformOptions) =>
|
||||
ensureServiceIsRunning().then(service =>
|
||||
service.transform(input, options))
|
||||
|
||||
export const formatMessages: typeof types.formatMessages = (messages, options) =>
|
||||
ensureServiceIsRunning().then(service =>
|
||||
service.formatMessages(messages, options))
|
||||
|
||||
export const analyzeMetafile: typeof types.analyzeMetafile = (metafile, options) =>
|
||||
ensureServiceIsRunning().then(service =>
|
||||
service.analyzeMetafile(metafile, options))
|
||||
|
||||
export const buildSync: typeof types.buildSync = () => {
|
||||
throw new Error(`The "buildSync" API does not work in Deno`)
|
||||
}
|
||||
|
||||
export const transformSync: typeof types.transformSync = () => {
|
||||
throw new Error(`The "transformSync" API does not work in Deno`)
|
||||
}
|
||||
|
||||
export const formatMessagesSync: typeof types.formatMessagesSync = () => {
|
||||
throw new Error(`The "formatMessagesSync" API does not work in Deno`)
|
||||
}
|
||||
|
||||
export const analyzeMetafileSync: typeof types.analyzeMetafileSync = () => {
|
||||
throw new Error(`The "analyzeMetafileSync" API does not work in Deno`)
|
||||
}
|
||||
|
||||
export const stop = () => {
|
||||
if (stopService) stopService()
|
||||
return Promise.resolve()
|
||||
}
|
||||
|
||||
interface Service {
|
||||
build: typeof types.build
|
||||
context: typeof types.context
|
||||
transform: typeof types.transform
|
||||
formatMessages: typeof types.formatMessages
|
||||
analyzeMetafile: typeof types.analyzeMetafile
|
||||
}
|
||||
|
||||
let initializePromise: Promise<Service> | undefined
|
||||
let stopService: (() => void) | undefined
|
||||
|
||||
let ensureServiceIsRunning = (): Promise<Service> => {
|
||||
return initializePromise || startRunningService('esbuild.wasm', undefined, true)
|
||||
}
|
||||
|
||||
export const initialize: typeof types.initialize = async (options) => {
|
||||
options = common.validateInitializeOptions(options || {})
|
||||
let wasmURL = options.wasmURL
|
||||
let wasmModule = options.wasmModule
|
||||
let useWorker = options.worker !== false
|
||||
if (initializePromise) throw new Error('Cannot call "initialize" more than once')
|
||||
initializePromise = startRunningService(wasmURL || 'esbuild.wasm', wasmModule, useWorker)
|
||||
initializePromise.catch(() => {
|
||||
// Let the caller try again if this fails
|
||||
initializePromise = void 0
|
||||
})
|
||||
await initializePromise
|
||||
}
|
||||
|
||||
const startRunningService = async (wasmURL: string | URL, wasmModule: WebAssembly.Module | undefined, useWorker: boolean): Promise<Service> => {
|
||||
let worker: {
|
||||
onmessage?: ((event: any) => void) | null | undefined
|
||||
postMessage: (data: Uint8Array | ArrayBuffer | WebAssembly.Module) => void
|
||||
terminate: () => void
|
||||
}
|
||||
|
||||
if (useWorker) {
|
||||
// Run esbuild off the main thread
|
||||
let blob = new Blob([`onmessage=${WEB_WORKER_SOURCE_CODE}(postMessage)`], { type: 'text/javascript' })
|
||||
worker = new Worker(URL.createObjectURL(blob), { type: 'module' })
|
||||
} else {
|
||||
// Run esbuild on the main thread
|
||||
let onmessage = WEB_WORKER_FUNCTION((data: Uint8Array) => worker.onmessage!({ data }))
|
||||
let go: Go | undefined
|
||||
worker = {
|
||||
onmessage: null,
|
||||
postMessage: data => setTimeout(() => go = onmessage({ data })),
|
||||
terminate() {
|
||||
if (go)
|
||||
for (let timeout of go._scheduledTimeouts.values())
|
||||
clearTimeout(timeout)
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
let firstMessageResolve: (value: void) => void
|
||||
let firstMessageReject: (error: any) => void
|
||||
|
||||
const firstMessagePromise = new Promise((resolve, reject) => {
|
||||
firstMessageResolve = resolve
|
||||
firstMessageReject = reject
|
||||
})
|
||||
|
||||
worker.onmessage = ({ data: error }) => {
|
||||
worker.onmessage = ({ data }) => readFromStdout(data)
|
||||
if (error) firstMessageReject(error)
|
||||
else firstMessageResolve()
|
||||
}
|
||||
|
||||
worker.postMessage(wasmModule || new URL(wasmURL, import.meta.url).toString())
|
||||
|
||||
let { readFromStdout, service } = common.createChannel({
|
||||
writeToStdin(bytes) {
|
||||
worker.postMessage(bytes)
|
||||
},
|
||||
isSync: false,
|
||||
hasFS: false,
|
||||
esbuild: ourselves,
|
||||
})
|
||||
|
||||
// This will throw if WebAssembly module instantiation fails
|
||||
await firstMessagePromise
|
||||
|
||||
stopService = () => {
|
||||
worker.terminate()
|
||||
initializePromise = undefined
|
||||
stopService = undefined
|
||||
}
|
||||
|
||||
return {
|
||||
build: (options: types.BuildOptions) =>
|
||||
new Promise<types.BuildResult>((resolve, reject) =>
|
||||
service.buildOrContext({
|
||||
callName: 'build',
|
||||
refs: null,
|
||||
options,
|
||||
isTTY: false,
|
||||
defaultWD: '/',
|
||||
callback: (err, res) => err ? reject(err) : resolve(res as types.BuildResult),
|
||||
})),
|
||||
|
||||
context: (options: types.BuildOptions) =>
|
||||
new Promise<types.BuildContext>((resolve, reject) =>
|
||||
service.buildOrContext({
|
||||
callName: 'context',
|
||||
refs: null,
|
||||
options,
|
||||
isTTY: false,
|
||||
defaultWD: '/',
|
||||
callback: (err, res) => err ? reject(err) : resolve(res as types.BuildContext),
|
||||
})),
|
||||
|
||||
transform: (input: string | Uint8Array, options?: types.TransformOptions) =>
|
||||
new Promise<types.TransformResult>((resolve, reject) =>
|
||||
service.transform({
|
||||
callName: 'transform',
|
||||
refs: null,
|
||||
input,
|
||||
options: options || {},
|
||||
isTTY: false,
|
||||
fs: {
|
||||
readFile(_, callback) { callback(new Error('Internal error'), null); },
|
||||
writeFile(_, callback) { callback(null); },
|
||||
},
|
||||
callback: (err, res) => err ? reject(err) : resolve(res!),
|
||||
})),
|
||||
|
||||
formatMessages: (messages, options) =>
|
||||
new Promise((resolve, reject) =>
|
||||
service.formatMessages({
|
||||
callName: 'formatMessages',
|
||||
refs: null,
|
||||
messages,
|
||||
options,
|
||||
callback: (err, res) => err ? reject(err) : resolve(res!),
|
||||
})),
|
||||
|
||||
analyzeMetafile: (metafile, options) =>
|
||||
new Promise((resolve, reject) =>
|
||||
service.analyzeMetafile({
|
||||
callName: 'analyzeMetafile',
|
||||
refs: null,
|
||||
metafile: typeof metafile === 'string' ? metafile : JSON.stringify(metafile),
|
||||
options,
|
||||
callback: (err, res) => err ? reject(err) : resolve(res!),
|
||||
})),
|
||||
}
|
||||
}
|
||||
+2
-11
@@ -686,23 +686,14 @@ export let version: string
|
||||
// In node this happens automatically before the parent node process exits. So
|
||||
// you only need to call this if you know you will not make any more esbuild
|
||||
// API calls and you want to clean up resources.
|
||||
//
|
||||
// Unlike node, Deno lacks the necessary APIs to clean up child processes
|
||||
// automatically. You must manually call stop() in Deno when you're done
|
||||
// using esbuild or Deno will continue running forever.
|
||||
//
|
||||
// Another reason you might want to call this is if you are using esbuild from
|
||||
// within a Deno test. Deno fails tests that create a child process without
|
||||
// killing it before the test ends, so you have to call this function (and
|
||||
// await the returned promise) in every Deno test that uses esbuild.
|
||||
export declare function stop(): Promise<void>
|
||||
|
||||
// Note: These declarations exist to avoid type errors when you omit "dom" from
|
||||
// "lib" in your "tsconfig.json" file. TypeScript confusingly declares the
|
||||
// global "WebAssembly" type in "lib.dom.d.ts" even though it has nothing to do
|
||||
// with the browser DOM and is present in many non-browser JavaScript runtimes
|
||||
// (e.g. node and deno). Declaring it here allows esbuild's API to be used in
|
||||
// these scenarios.
|
||||
// (e.g. node). Declaring it here allows esbuild's API to be used in these
|
||||
// scenarios.
|
||||
//
|
||||
// There's an open issue about getting this problem corrected (although these
|
||||
// declarations will need to remain even if this is fixed for backward
|
||||
|
||||
@@ -8,7 +8,4 @@
|
||||
"node"
|
||||
],
|
||||
},
|
||||
"exclude": [
|
||||
"deno",
|
||||
],
|
||||
}
|
||||
|
||||
@@ -1,181 +0,0 @@
|
||||
// To run this, you must first build the Deno package with "make platform-deno"
|
||||
import * as esbuildNative from '../deno/mod.js'
|
||||
import * as esbuildWASM from '../deno/wasm.js'
|
||||
import * as path from 'https://deno.land/[email protected]/path/mod.ts'
|
||||
import * as asserts from 'https://deno.land/[email protected]/testing/asserts.ts'
|
||||
|
||||
const __dirname = path.dirname(path.fromFileUrl(import.meta.url))
|
||||
const rootTestDir = path.join(__dirname, '.deno-tests')
|
||||
const wasmModule = await WebAssembly.compile(await Deno.readFile(path.join(__dirname, '..', 'deno', 'esbuild.wasm')))
|
||||
|
||||
try {
|
||||
Deno.removeSync(rootTestDir, { recursive: true })
|
||||
} catch {
|
||||
}
|
||||
Deno.mkdirSync(rootTestDir, { recursive: true })
|
||||
|
||||
function test(name, backends, fn) {
|
||||
// Note: Do not try to add a timeout for the tests below. It turns out that
|
||||
// calling "setTimeout" from within "Deno.test" changes how Deno waits for
|
||||
// promises in a way that masks problems that would otherwise occur. We want
|
||||
// test coverage for the way that people will likely be using these API calls.
|
||||
//
|
||||
// Specifically tests that Deno would otherwise have failed with "error:
|
||||
// Promise resolution is still pending but the event loop has already
|
||||
// resolved" were being allowed to pass instead. See this issue for more
|
||||
// information: https://github.com/evanw/esbuild/issues/3682
|
||||
|
||||
for (const backend of backends) {
|
||||
switch (backend) {
|
||||
case 'native':
|
||||
Deno.test(name + '-native', async () => {
|
||||
let testDir = path.join(rootTestDir, name + '-native')
|
||||
await Deno.mkdir(testDir, { recursive: true })
|
||||
try {
|
||||
await fn({ esbuild: esbuildNative, testDir })
|
||||
await Deno.remove(testDir, { recursive: true }).catch(() => null)
|
||||
} finally {
|
||||
await esbuildNative.stop()
|
||||
}
|
||||
})
|
||||
break
|
||||
|
||||
case 'wasm-main':
|
||||
Deno.test(name + '-wasm-main', async () => {
|
||||
let testDir = path.join(rootTestDir, name + '-wasm-main')
|
||||
await esbuildWASM.initialize({ wasmModule, worker: false })
|
||||
await Deno.mkdir(testDir, { recursive: true })
|
||||
try {
|
||||
await fn({ esbuild: esbuildWASM, testDir })
|
||||
await Deno.remove(testDir, { recursive: true }).catch(() => null)
|
||||
} finally {
|
||||
await esbuildWASM.stop()
|
||||
}
|
||||
})
|
||||
break
|
||||
|
||||
case 'wasm-worker':
|
||||
Deno.test(name + '-wasm-worker', async () => {
|
||||
let testDir = path.join(rootTestDir, name + '-wasm-worker')
|
||||
await esbuildWASM.initialize({ wasmModule, worker: true })
|
||||
await Deno.mkdir(testDir, { recursive: true })
|
||||
try {
|
||||
await fn({ esbuild: esbuildWASM, testDir })
|
||||
await Deno.remove(testDir, { recursive: true }).catch(() => null)
|
||||
} finally {
|
||||
await esbuildWASM.stop()
|
||||
}
|
||||
})
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
addEventListener("unload", (e) => {
|
||||
try {
|
||||
Deno.removeSync(rootTestDir, { recursive: true })
|
||||
} catch {
|
||||
// root test dir possibly already removed, so ignore
|
||||
}
|
||||
})
|
||||
|
||||
// This test doesn't run in WebAssembly because it requires file system access
|
||||
test("basicBuild", ['native'], async ({ esbuild, testDir }) => {
|
||||
const input = path.join(testDir, 'in.ts')
|
||||
const dep = path.join(testDir, 'dep.ts')
|
||||
const output = path.join(testDir, 'out.ts')
|
||||
await Deno.writeTextFile(input, 'import dep from "./dep.ts"; export default dep === 123')
|
||||
await Deno.writeTextFile(dep, 'export default 123')
|
||||
await esbuild.build({
|
||||
entryPoints: [input],
|
||||
bundle: true,
|
||||
outfile: output,
|
||||
format: 'esm',
|
||||
})
|
||||
const result = await import(path.toFileUrl(output))
|
||||
asserts.assertStrictEquals(result.default, true)
|
||||
})
|
||||
|
||||
test("basicContext", ['native'], async ({ esbuild, testDir }) => {
|
||||
const input = path.join(testDir, 'in.ts')
|
||||
const dep = path.join(testDir, 'dep.ts')
|
||||
const output = path.join(testDir, 'out.ts')
|
||||
await Deno.writeTextFile(input, 'import dep from "./dep.ts"; export default dep === 123')
|
||||
await Deno.writeTextFile(dep, 'export default 123')
|
||||
const ctx = await esbuild.context({
|
||||
entryPoints: ['in.ts'],
|
||||
bundle: true,
|
||||
outfile: output,
|
||||
format: 'esm',
|
||||
absWorkingDir: testDir,
|
||||
})
|
||||
const { errors, warnings } = await ctx.rebuild()
|
||||
asserts.assertStrictEquals(errors.length, 0)
|
||||
asserts.assertStrictEquals(warnings.length, 0)
|
||||
await ctx.dispose()
|
||||
const result = await import(path.toFileUrl(output))
|
||||
asserts.assertStrictEquals(result.default, true)
|
||||
})
|
||||
|
||||
test("basicPlugin", ['native', 'wasm-main', 'wasm-worker'], async ({ esbuild }) => {
|
||||
const build = await esbuild.build({
|
||||
entryPoints: ['<entry>'],
|
||||
bundle: true,
|
||||
format: 'esm',
|
||||
write: false,
|
||||
plugins: [{
|
||||
name: 'plug',
|
||||
setup(build) {
|
||||
build.onResolve({ filter: /^<.*>$/ }, args => ({ path: args.path, namespace: '<>' }))
|
||||
build.onLoad({ filter: /^<entry>$/ }, () => ({ contents: `import dep from "<dep>"; export default dep === 123` }))
|
||||
build.onLoad({ filter: /^<dep>$/ }, () => ({ contents: `export default 123` }))
|
||||
},
|
||||
}],
|
||||
})
|
||||
const result = await import('data:application/javascript;base64,' + btoa(build.outputFiles[0].text))
|
||||
asserts.assertStrictEquals(result.default, true)
|
||||
})
|
||||
|
||||
test("basicTransform", ['native', 'wasm-main', 'wasm-worker'], async ({ esbuild }) => {
|
||||
const ts = 'let x: number = 1+2'
|
||||
const result = await esbuild.transform(ts, { loader: 'ts' })
|
||||
asserts.assertStrictEquals(result.code, 'let x = 1 + 2;\n')
|
||||
})
|
||||
|
||||
// This test doesn't run in WebAssembly because of a stack overflow
|
||||
test("largeTransform", ['native'], async ({ esbuild }) => {
|
||||
// This should be large enough to be bigger than Deno's write buffer
|
||||
let x = '0'
|
||||
for (let i = 0; i < 1000; i++) x += '+' + i
|
||||
x += ','
|
||||
let y = 'return['
|
||||
for (let i = 0; i < 1000; i++) y += x
|
||||
y += ']'
|
||||
const result = await esbuild.build({
|
||||
stdin: {
|
||||
contents: y,
|
||||
},
|
||||
write: false,
|
||||
minifyWhitespace: true,
|
||||
})
|
||||
asserts.assertStrictEquals(result.outputFiles[0].text, y.slice(0, -2) + '];\n')
|
||||
})
|
||||
|
||||
test("analyzeMetafile", ['native', 'wasm-main', 'wasm-worker'], async ({ esbuild }) => {
|
||||
const result = await esbuild.analyzeMetafile({
|
||||
outputs: {
|
||||
'out.js': {
|
||||
bytes: 4096,
|
||||
inputs: {
|
||||
'in.js': {
|
||||
bytesInOutput: 1024,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
asserts.assertStrictEquals(result, `
|
||||
out.js 4.0kb 100.0%
|
||||
└ in.js 1.0kb 25.0%
|
||||
`)
|
||||
})
|
||||
@@ -5,11 +5,9 @@ const fs = require('fs')
|
||||
const os = require('os')
|
||||
|
||||
const repoDir = path.dirname(__dirname)
|
||||
const denoDir = path.join(repoDir, 'deno')
|
||||
const npmDir = path.join(repoDir, 'npm', 'esbuild')
|
||||
const version = fs.readFileSync(path.join(repoDir, 'version.txt'), 'utf8').trim()
|
||||
const nodeTarget = 'node10'; // See: https://nodejs.org/en/about/releases/
|
||||
const denoTarget = 'deno1'; // See: https://docs.deno.com/runtime/fundamentals/stability_and_releases/
|
||||
const umdBrowserTarget = 'es2015'; // Transpiles "async"
|
||||
const esmBrowserTarget = 'es2017'; // Preserves "async"
|
||||
|
||||
@@ -271,46 +269,6 @@ exports.buildWasmLib = async (esbuildPath) => {
|
||||
}
|
||||
}
|
||||
|
||||
const buildDenoLib = async (esbuildPath) => {
|
||||
// Generate "deno/mod.js"
|
||||
const packageJSON = JSON.parse(fs.readFileSync(path.join(npmDir, 'package.json'), 'utf8'))
|
||||
childProcess.execFileSync(esbuildPath, [
|
||||
path.join(repoDir, 'lib', 'deno', 'mod.ts'),
|
||||
'--bundle',
|
||||
'--outfile=' + path.join(denoDir, 'mod.js'),
|
||||
'--target=' + denoTarget,
|
||||
'--define:ESBUILD_VERSION=' + JSON.stringify(version),
|
||||
'--define:ESBUILD_BINARY_HASHES=' + JSON.stringify(packageJSON['esbuild.binaryHashes'], null, 2),
|
||||
'--platform=neutral',
|
||||
'--log-level=warning',
|
||||
'--banner:js=/// <reference types="./mod.d.ts" />',
|
||||
], { cwd: repoDir })
|
||||
|
||||
// Generate "deno/wasm.js"
|
||||
const GOROOT = childProcess.execFileSync('go', ['env', 'GOROOT']).toString().trim()
|
||||
let wasm_exec_js = fs.readFileSync(path.join(GOROOT, 'lib', 'wasm', 'wasm_exec.js'), 'utf8')
|
||||
const wasmWorkerCode = await generateWorkerCode({ esbuildPath, wasm_exec_js, minify: true, target: denoTarget })
|
||||
const modWASM = childProcess.execFileSync(esbuildPath, [
|
||||
path.join(repoDir, 'lib', 'deno', 'wasm.ts'),
|
||||
'--bundle',
|
||||
'--target=' + denoTarget,
|
||||
'--define:ESBUILD_VERSION=' + JSON.stringify(version),
|
||||
'--define:WEB_WORKER_SOURCE_CODE=' + JSON.stringify(wasmWorkerCode),
|
||||
'--platform=neutral',
|
||||
'--log-level=warning',
|
||||
'--banner:js=/// <reference types="./wasm.d.ts" />',
|
||||
], { cwd: repoDir }).toString().replace('WEB_WORKER_FUNCTION', wasmWorkerCode)
|
||||
fs.writeFileSync(path.join(denoDir, 'wasm.js'), modWASM)
|
||||
|
||||
// Generate "deno/mod.d.ts"
|
||||
const types_ts = fs.readFileSync(path.join(repoDir, 'lib', 'shared', 'types.ts'), 'utf8')
|
||||
fs.writeFileSync(path.join(denoDir, 'mod.d.ts'), types_ts)
|
||||
fs.writeFileSync(path.join(denoDir, 'wasm.d.ts'), types_ts)
|
||||
|
||||
// And copy the WebAssembly file over to the Deno library as well
|
||||
fs.copyFileSync(path.join(repoDir, 'npm', 'esbuild-wasm', 'esbuild.wasm'), path.join(repoDir, 'deno', 'esbuild.wasm'))
|
||||
}
|
||||
|
||||
// Writing a file atomically is important for watch mode tests since we don't
|
||||
// want to read the file after it has been truncated but before the new contents
|
||||
// have been written.
|
||||
@@ -402,7 +360,6 @@ exports.dirname = __dirname
|
||||
// The main Makefile invokes this script before publishing
|
||||
if (require.main === module) {
|
||||
if (process.argv.indexOf('--wasm') >= 0) exports.buildWasmLib(process.argv[2])
|
||||
else if (process.argv.indexOf('--deno') >= 0) buildDenoLib(process.argv[2])
|
||||
else if (process.argv.indexOf('--version') >= 0) updateVersionPackageJSON(process.argv[2])
|
||||
else if (process.argv.indexOf('--neutral') >= 0) buildNeutralLib(process.argv[2])
|
||||
else if (process.argv.indexOf('--update-version-go') >= 0) updateVersionGo()
|
||||
|
||||
Reference in New Issue
Block a user