@volter/tabnode 0.2.14-volter.88
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +22 -0
- package/README.md +78 -0
- package/THIRD-PARTY-NOTICES.md +12 -0
- package/dist/__sw__.js +526 -0
- package/dist/assets/runtime-worker-4MKaHFVb.js +75221 -0
- package/dist/assets/runtime-worker-4MKaHFVb.js.map +1 -0
- package/dist/code-transforms.d.ts +21 -0
- package/dist/code-transforms.d.ts.map +1 -0
- package/dist/config/cdn.d.ts +12 -0
- package/dist/config/cdn.d.ts.map +1 -0
- package/dist/create-runtime.d.ts +22 -0
- package/dist/create-runtime.d.ts.map +1 -0
- package/dist/host-globals.d.ts +62 -0
- package/dist/host-globals.d.ts.map +1 -0
- package/dist/index.cjs +36021 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.ts +127 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.mjs +36020 -0
- package/dist/index.mjs.map +1 -0
- package/dist/node-internals.d.ts +68 -0
- package/dist/node-internals.d.ts.map +1 -0
- package/dist/node-lib/binding/blob.d.ts +12 -0
- package/dist/node-lib/binding/blob.d.ts.map +1 -0
- package/dist/node-lib/binding/buffer.d.ts +144 -0
- package/dist/node-lib/binding/buffer.d.ts.map +1 -0
- package/dist/node-lib/binding/cares_wrap.d.ts +14 -0
- package/dist/node-lib/binding/cares_wrap.d.ts.map +1 -0
- package/dist/node-lib/binding/fds.d.ts +30 -0
- package/dist/node-lib/binding/fds.d.ts.map +1 -0
- package/dist/node-lib/binding/fs.d.ts +157 -0
- package/dist/node-lib/binding/fs.d.ts.map +1 -0
- package/dist/node-lib/binding/handles.d.ts +81 -0
- package/dist/node-lib/binding/handles.d.ts.map +1 -0
- package/dist/node-lib/binding/http_parser.d.ts +122 -0
- package/dist/node-lib/binding/http_parser.d.ts.map +1 -0
- package/dist/node-lib/binding/index.d.ts +3 -0
- package/dist/node-lib/binding/index.d.ts.map +1 -0
- package/dist/node-lib/binding/llhttp-wasm.d.ts +22 -0
- package/dist/node-lib/binding/llhttp-wasm.d.ts.map +1 -0
- package/dist/node-lib/binding/misc.d.ts +123 -0
- package/dist/node-lib/binding/misc.d.ts.map +1 -0
- package/dist/node-lib/binding/pipe_wrap.d.ts +84 -0
- package/dist/node-lib/binding/pipe_wrap.d.ts.map +1 -0
- package/dist/node-lib/binding/process_wrap.d.ts +173 -0
- package/dist/node-lib/binding/process_wrap.d.ts.map +1 -0
- package/dist/node-lib/binding/spawn_sync.d.ts +30 -0
- package/dist/node-lib/binding/spawn_sync.d.ts.map +1 -0
- package/dist/node-lib/binding/stream_wrap.d.ts +191 -0
- package/dist/node-lib/binding/stream_wrap.d.ts.map +1 -0
- package/dist/node-lib/binding/stubs.d.ts +23 -0
- package/dist/node-lib/binding/stubs.d.ts.map +1 -0
- package/dist/node-lib/binding/tcp_wrap.d.ts +98 -0
- package/dist/node-lib/binding/tcp_wrap.d.ts.map +1 -0
- package/dist/node-lib/binding/tty_wrap.d.ts +36 -0
- package/dist/node-lib/binding/tty_wrap.d.ts.map +1 -0
- package/dist/node-lib/binding/util.d.ts +126 -0
- package/dist/node-lib/binding/util.d.ts.map +1 -0
- package/dist/node-lib/binding/uv.d.ts +32 -0
- package/dist/node-lib/binding/uv.d.ts.map +1 -0
- package/dist/node-lib/binding/zlib-pako.d.ts +22 -0
- package/dist/node-lib/binding/zlib-pako.d.ts.map +1 -0
- package/dist/node-lib/binding/zlib.d.ts +38 -0
- package/dist/node-lib/binding/zlib.d.ts.map +1 -0
- package/dist/node-lib/buffer-module.d.ts +51 -0
- package/dist/node-lib/buffer-module.d.ts.map +1 -0
- package/dist/node-lib/child-process-module.d.ts +26 -0
- package/dist/node-lib/child-process-module.d.ts.map +1 -0
- package/dist/node-lib/events-module.d.ts +58 -0
- package/dist/node-lib/events-module.d.ts.map +1 -0
- package/dist/node-lib/fs-module.d.ts +5 -0
- package/dist/node-lib/fs-module.d.ts.map +1 -0
- package/dist/node-lib/http-bridge.d.ts +43 -0
- package/dist/node-lib/http-bridge.d.ts.map +1 -0
- package/dist/node-lib/http-module.d.ts +35 -0
- package/dist/node-lib/http-module.d.ts.map +1 -0
- package/dist/node-lib/internals/addresses.d.ts +40 -0
- package/dist/node-lib/internals/addresses.d.ts.map +1 -0
- package/dist/node-lib/internals/buffer-and-streams.d.ts +96 -0
- package/dist/node-lib/internals/buffer-and-streams.d.ts.map +1 -0
- package/dist/node-lib/internals/child-process.d.ts +27 -0
- package/dist/node-lib/internals/child-process.d.ts.map +1 -0
- package/dist/node-lib/internals/events-util.d.ts +83 -0
- package/dist/node-lib/internals/events-util.d.ts.map +1 -0
- package/dist/node-lib/internals/index.d.ts +2 -0
- package/dist/node-lib/internals/index.d.ts.map +1 -0
- package/dist/node-lib/internals/modules.d.ts +67 -0
- package/dist/node-lib/internals/modules.d.ts.map +1 -0
- package/dist/node-lib/internals/readline-access.d.ts +2 -0
- package/dist/node-lib/internals/readline-access.d.ts.map +1 -0
- package/dist/node-lib/internals/runtime.d.ts +150 -0
- package/dist/node-lib/internals/runtime.d.ts.map +1 -0
- package/dist/node-lib/internals/util.d.ts +33 -0
- package/dist/node-lib/internals/util.d.ts.map +1 -0
- package/dist/node-lib/lazy.d.ts +31 -0
- package/dist/node-lib/lazy.d.ts.map +1 -0
- package/dist/node-lib/load.d.ts +27 -0
- package/dist/node-lib/load.d.ts.map +1 -0
- package/dist/node-lib/module-hooks.d.ts +89 -0
- package/dist/node-lib/module-hooks.d.ts.map +1 -0
- package/dist/node-lib/net-module.d.ts +181 -0
- package/dist/node-lib/net-module.d.ts.map +1 -0
- package/dist/node-lib/node-versions.d.ts +27 -0
- package/dist/node-lib/node-versions.d.ts.map +1 -0
- package/dist/node-lib/public-modules.d.ts +2 -0
- package/dist/node-lib/public-modules.d.ts.map +1 -0
- package/dist/node-lib/require-hook.d.ts +15 -0
- package/dist/node-lib/require-hook.d.ts.map +1 -0
- package/dist/node-lib/small-modules.d.ts +16 -0
- package/dist/node-lib/small-modules.d.ts.map +1 -0
- package/dist/node-lib/sources.d.ts +4 -0
- package/dist/node-lib/sources.d.ts.map +1 -0
- package/dist/node-lib/stream-module.d.ts +77 -0
- package/dist/node-lib/stream-module.d.ts.map +1 -0
- package/dist/node-lib/timers.d.ts +19 -0
- package/dist/node-lib/timers.d.ts.map +1 -0
- package/dist/node-lib/util-module.d.ts +76 -0
- package/dist/node-lib/util-module.d.ts.map +1 -0
- package/dist/node-resolution.d.ts +50 -0
- package/dist/node-resolution.d.ts.map +1 -0
- package/dist/node-resolver.d.ts +7 -0
- package/dist/node-resolver.d.ts.map +1 -0
- package/dist/npm/index.d.ts +73 -0
- package/dist/npm/index.d.ts.map +1 -0
- package/dist/npm/registry.d.ts +111 -0
- package/dist/npm/registry.d.ts.map +1 -0
- package/dist/npm/resolver.d.ts +79 -0
- package/dist/npm/resolver.d.ts.map +1 -0
- package/dist/npm/tarball.d.ts +28 -0
- package/dist/npm/tarball.d.ts.map +1 -0
- package/dist/process-tokens.d.ts +77 -0
- package/dist/process-tokens.d.ts.map +1 -0
- package/dist/punycode-source.d.ts +3 -0
- package/dist/punycode-source.d.ts.map +1 -0
- package/dist/runtime-interface.d.ts +74 -0
- package/dist/runtime-interface.d.ts.map +1 -0
- package/dist/runtime.d.ts +144 -0
- package/dist/runtime.d.ts.map +1 -0
- package/dist/server-bridge.d.ts +147 -0
- package/dist/server-bridge.d.ts.map +1 -0
- package/dist/shims/async_hooks.d.ts +50 -0
- package/dist/shims/async_hooks.d.ts.map +1 -0
- package/dist/shims/child_process.d.ts +104 -0
- package/dist/shims/child_process.d.ts.map +1 -0
- package/dist/shims/cluster.d.ts +52 -0
- package/dist/shims/cluster.d.ts.map +1 -0
- package/dist/shims/command-line.d.ts +43 -0
- package/dist/shims/command-line.d.ts.map +1 -0
- package/dist/shims/constants.d.ts +222 -0
- package/dist/shims/constants.d.ts.map +1 -0
- package/dist/shims/crypto-constants.d.ts +12 -0
- package/dist/shims/crypto-constants.d.ts.map +1 -0
- package/dist/shims/crypto.d.ts +144 -0
- package/dist/shims/crypto.d.ts.map +1 -0
- package/dist/shims/dgram.d.ts +34 -0
- package/dist/shims/dgram.d.ts.map +1 -0
- package/dist/shims/dns.d.ts +91 -0
- package/dist/shims/dns.d.ts.map +1 -0
- package/dist/shims/domain.d.ts +25 -0
- package/dist/shims/domain.d.ts.map +1 -0
- package/dist/shims/esbuild.d.ts +205 -0
- package/dist/shims/esbuild.d.ts.map +1 -0
- package/dist/shims/fs.d.ts +25 -0
- package/dist/shims/fs.d.ts.map +1 -0
- package/dist/shims/http2.d.ts +81 -0
- package/dist/shims/http2.d.ts.map +1 -0
- package/dist/shims/inspector.d.ts +25 -0
- package/dist/shims/inspector.d.ts.map +1 -0
- package/dist/shims/module.d.ts +22 -0
- package/dist/shims/module.d.ts.map +1 -0
- package/dist/shims/os.d.ts +159 -0
- package/dist/shims/os.d.ts.map +1 -0
- package/dist/shims/path.d.ts +52 -0
- package/dist/shims/path.d.ts.map +1 -0
- package/dist/shims/perf_hooks.d.ts +50 -0
- package/dist/shims/perf_hooks.d.ts.map +1 -0
- package/dist/shims/process.d.ts +226 -0
- package/dist/shims/process.d.ts.map +1 -0
- package/dist/shims/rollup.d.ts +71 -0
- package/dist/shims/rollup.d.ts.map +1 -0
- package/dist/shims/string_decoder.d.ts +41 -0
- package/dist/shims/string_decoder.d.ts.map +1 -0
- package/dist/shims/sync-child.d.ts +64 -0
- package/dist/shims/sync-child.d.ts.map +1 -0
- package/dist/shims/tls.d.ts +53 -0
- package/dist/shims/tls.d.ts.map +1 -0
- package/dist/shims/url.d.ts +84 -0
- package/dist/shims/url.d.ts.map +1 -0
- package/dist/shims/v8.d.ts +73 -0
- package/dist/shims/v8.d.ts.map +1 -0
- package/dist/shims/vfs-adapter.d.ts +126 -0
- package/dist/shims/vfs-adapter.d.ts.map +1 -0
- package/dist/shims/vm.d.ts +52 -0
- package/dist/shims/vm.d.ts.map +1 -0
- package/dist/shims/wasi.d.ts +78 -0
- package/dist/shims/wasi.d.ts.map +1 -0
- package/dist/shims/worker_threads.d.ts +66 -0
- package/dist/shims/worker_threads.d.ts.map +1 -0
- package/dist/shims/zlib-constants.d.ts +66 -0
- package/dist/shims/zlib-constants.d.ts.map +1 -0
- package/dist/shims/zlib.d.ts +102 -0
- package/dist/shims/zlib.d.ts.map +1 -0
- package/dist/transform.d.ts +24 -0
- package/dist/transform.d.ts.map +1 -0
- package/dist/types/package-json.d.ts +18 -0
- package/dist/types/package-json.d.ts.map +1 -0
- package/dist/utils/binary-encoding.d.ts +13 -0
- package/dist/utils/binary-encoding.d.ts.map +1 -0
- package/dist/utils/glob.d.ts +19 -0
- package/dist/utils/glob.d.ts.map +1 -0
- package/dist/utils/hash.d.ts +6 -0
- package/dist/utils/hash.d.ts.map +1 -0
- package/dist/virtual-fs.d.ts +259 -0
- package/dist/virtual-fs.d.ts.map +1 -0
- package/dist/vite-plugin.cjs +50 -0
- package/dist/vite-plugin.cjs.map +1 -0
- package/dist/vite-plugin.d.ts +36 -0
- package/dist/vite-plugin.d.ts.map +1 -0
- package/dist/vite-plugin.mjs +31 -0
- package/dist/vite-plugin.mjs.map +1 -0
- package/dist/worker/runtime-worker.d.ts +8 -0
- package/dist/worker/runtime-worker.d.ts.map +1 -0
- package/dist/worker-runtime.d.ts +50 -0
- package/dist/worker-runtime.d.ts.map +1 -0
- package/package.json +88 -0
- package/src/code-transforms.ts +560 -0
- package/src/config/cdn.ts +13 -0
- package/src/create-runtime.ts +89 -0
- package/src/host-globals.ts +121 -0
- package/src/index.ts +235 -0
- package/src/node-internals.ts +283 -0
- package/src/node-lib/LICENSE +47 -0
- package/src/node-lib/_http_agent.js +547 -0
- package/src/node-lib/_http_client.js +996 -0
- package/src/node-lib/_http_common.js +269 -0
- package/src/node-lib/_http_incoming.js +453 -0
- package/src/node-lib/_http_outgoing.js +1262 -0
- package/src/node-lib/_http_server.js +1230 -0
- package/src/node-lib/assert/strict.js +3 -0
- package/src/node-lib/assert.js +844 -0
- package/src/node-lib/binding/blob.ts +35 -0
- package/src/node-lib/binding/buffer.ts +465 -0
- package/src/node-lib/binding/cares_wrap.ts +57 -0
- package/src/node-lib/binding/fds.ts +80 -0
- package/src/node-lib/binding/fs.ts +857 -0
- package/src/node-lib/binding/handles.ts +187 -0
- package/src/node-lib/binding/http_parser.ts +536 -0
- package/src/node-lib/binding/index.ts +77 -0
- package/src/node-lib/binding/llhttp-wasm.ts +670 -0
- package/src/node-lib/binding/misc.ts +252 -0
- package/src/node-lib/binding/pipe_wrap.ts +166 -0
- package/src/node-lib/binding/process_wrap.ts +371 -0
- package/src/node-lib/binding/spawn_sync.ts +141 -0
- package/src/node-lib/binding/stream_wrap.ts +413 -0
- package/src/node-lib/binding/stubs.ts +19 -0
- package/src/node-lib/binding/tcp_wrap.ts +254 -0
- package/src/node-lib/binding/tty_wrap.ts +56 -0
- package/src/node-lib/binding/util.ts +274 -0
- package/src/node-lib/binding/uv.ts +102 -0
- package/src/node-lib/binding/zlib-pako.ts +50 -0
- package/src/node-lib/binding/zlib.ts +259 -0
- package/src/node-lib/buffer-module.ts +70 -0
- package/src/node-lib/buffer.js +1373 -0
- package/src/node-lib/child-process-module.ts +58 -0
- package/src/node-lib/child_process.js +1046 -0
- package/src/node-lib/constants.js +41 -0
- package/src/node-lib/diagnostics_channel.js +438 -0
- package/src/node-lib/events-module.ts +80 -0
- package/src/node-lib/events.js +1223 -0
- package/src/node-lib/fs-module.ts +43 -0
- package/src/node-lib/fs.js +3377 -0
- package/src/node-lib/http-bridge.ts +299 -0
- package/src/node-lib/http-module.ts +53 -0
- package/src/node-lib/http.js +198 -0
- package/src/node-lib/https.js +429 -0
- package/src/node-lib/internal/assert/assertion_error.js +417 -0
- package/src/node-lib/internal/assert/calltracker.js +153 -0
- package/src/node-lib/internal/assert/myers_diff.js +177 -0
- package/src/node-lib/internal/assert/utils.js +278 -0
- package/src/node-lib/internal/buffer.js +1120 -0
- package/src/node-lib/internal/child_process/serialization.js +169 -0
- package/src/node-lib/internal/child_process.js +1135 -0
- package/src/node-lib/internal/constants.js +56 -0
- package/src/node-lib/internal/deps/minimatch/index.js +1628 -0
- package/src/node-lib/internal/errors.js +1912 -0
- package/src/node-lib/internal/events/abort_listener.js +54 -0
- package/src/node-lib/internal/events/symbols.js +11 -0
- package/src/node-lib/internal/fixed_queue.js +119 -0
- package/src/node-lib/internal/freelist.js +30 -0
- package/src/node-lib/internal/fs/cp/cp-sync.js +242 -0
- package/src/node-lib/internal/fs/cp/cp.js +382 -0
- package/src/node-lib/internal/fs/dir.js +369 -0
- package/src/node-lib/internal/fs/glob.js +763 -0
- package/src/node-lib/internal/fs/promises.js +1312 -0
- package/src/node-lib/internal/fs/read/context.js +129 -0
- package/src/node-lib/internal/fs/recursive_watch.js +275 -0
- package/src/node-lib/internal/fs/rimraf.js +311 -0
- package/src/node-lib/internal/fs/streams.js +571 -0
- package/src/node-lib/internal/fs/sync_write_stream.js +49 -0
- package/src/node-lib/internal/fs/utils.js +987 -0
- package/src/node-lib/internal/fs/watchers.js +418 -0
- package/src/node-lib/internal/http.js +62 -0
- package/src/node-lib/internal/mime.js +389 -0
- package/src/node-lib/internal/modules/customization_hooks.js +406 -0
- package/src/node-lib/internal/net.js +95 -0
- package/src/node-lib/internal/querystring.js +119 -0
- package/src/node-lib/internal/readline/callbacks.js +132 -0
- package/src/node-lib/internal/readline/emitKeypressEvents.js +99 -0
- package/src/node-lib/internal/readline/interface.js +1418 -0
- package/src/node-lib/internal/readline/promises.js +144 -0
- package/src/node-lib/internal/readline/utils.js +405 -0
- package/src/node-lib/internal/socket_list.js +108 -0
- package/src/node-lib/internal/stream_base_commons.js +280 -0
- package/src/node-lib/internal/streams/add-abort-signal.js +60 -0
- package/src/node-lib/internal/streams/compose.js +257 -0
- package/src/node-lib/internal/streams/destroy.js +361 -0
- package/src/node-lib/internal/streams/duplex.js +203 -0
- package/src/node-lib/internal/streams/duplexify.js +379 -0
- package/src/node-lib/internal/streams/duplexpair.js +62 -0
- package/src/node-lib/internal/streams/end-of-stream.js +331 -0
- package/src/node-lib/internal/streams/from.js +208 -0
- package/src/node-lib/internal/streams/lazy_transform.js +57 -0
- package/src/node-lib/internal/streams/legacy.js +125 -0
- package/src/node-lib/internal/streams/operators.js +436 -0
- package/src/node-lib/internal/streams/passthrough.js +47 -0
- package/src/node-lib/internal/streams/pipeline.js +465 -0
- package/src/node-lib/internal/streams/readable.js +1762 -0
- package/src/node-lib/internal/streams/state.js +51 -0
- package/src/node-lib/internal/streams/transform.js +204 -0
- package/src/node-lib/internal/streams/utils.js +363 -0
- package/src/node-lib/internal/streams/writable.js +1163 -0
- package/src/node-lib/internal/tty.js +260 -0
- package/src/node-lib/internal/util/colors.js +40 -0
- package/src/node-lib/internal/util/comparisons.js +1028 -0
- package/src/node-lib/internal/util/debuglog.js +524 -0
- package/src/node-lib/internal/util/inspect.js +2535 -0
- package/src/node-lib/internal/util/parse_args/parse_args.js +412 -0
- package/src/node-lib/internal/util/parse_args/utils.js +197 -0
- package/src/node-lib/internal/util.js +1003 -0
- package/src/node-lib/internal/validators.js +654 -0
- package/src/node-lib/internals/addresses.ts +159 -0
- package/src/node-lib/internals/buffer-and-streams.ts +224 -0
- package/src/node-lib/internals/child-process.ts +64 -0
- package/src/node-lib/internals/events-util.ts +105 -0
- package/src/node-lib/internals/index.ts +66 -0
- package/src/node-lib/internals/modules.ts +117 -0
- package/src/node-lib/internals/readline-access.ts +16 -0
- package/src/node-lib/internals/runtime.ts +277 -0
- package/src/node-lib/internals/util.ts +98 -0
- package/src/node-lib/lazy.ts +158 -0
- package/src/node-lib/load.ts +390 -0
- package/src/node-lib/module-hooks.ts +281 -0
- package/src/node-lib/net-module.ts +248 -0
- package/src/node-lib/net.js +2540 -0
- package/src/node-lib/node-versions.ts +34 -0
- package/src/node-lib/os.js +356 -0
- package/src/node-lib/path.js +1694 -0
- package/src/node-lib/primordials.js +743 -0
- package/src/node-lib/public-modules.ts +109 -0
- package/src/node-lib/punycode.js +455 -0
- package/src/node-lib/querystring.js +484 -0
- package/src/node-lib/readline/promises.js +73 -0
- package/src/node-lib/readline.js +523 -0
- package/src/node-lib/require-hook.ts +27 -0
- package/src/node-lib/small-modules.ts +35 -0
- package/src/node-lib/sources.ts +200 -0
- package/src/node-lib/stream/promises.js +44 -0
- package/src/node-lib/stream-module.ts +101 -0
- package/src/node-lib/stream.js +152 -0
- package/src/node-lib/timers.ts +33 -0
- package/src/node-lib/tty.js +168 -0
- package/src/node-lib/util-module.ts +104 -0
- package/src/node-lib/util.js +689 -0
- package/src/node-lib/wasi.js +179 -0
- package/src/node-lib/zlib.js +1036 -0
- package/src/node-resolution.ts +241 -0
- package/src/node-resolver.ts +33 -0
- package/src/npm/index.ts +425 -0
- package/src/npm/registry.ts +235 -0
- package/src/npm/resolver.ts +589 -0
- package/src/npm/tarball.ts +246 -0
- package/src/process-tokens.ts +156 -0
- package/src/punycode-source.ts +6 -0
- package/src/runtime-interface.ts +85 -0
- package/src/runtime.ts +3073 -0
- package/src/server-bridge.ts +971 -0
- package/src/shims/async_hooks.ts +181 -0
- package/src/shims/child_process.ts +1591 -0
- package/src/shims/cluster.ts +79 -0
- package/src/shims/command-line.ts +79 -0
- package/src/shims/constants.ts +68 -0
- package/src/shims/crypto-constants.ts +11 -0
- package/src/shims/crypto.ts +1061 -0
- package/src/shims/dgram.ts +47 -0
- package/src/shims/dns.ts +185 -0
- package/src/shims/domain.ts +58 -0
- package/src/shims/esbuild.ts +1638 -0
- package/src/shims/fs.ts +82 -0
- package/src/shims/http2.ts +96 -0
- package/src/shims/inspector.ts +30 -0
- package/src/shims/module.ts +86 -0
- package/src/shims/os.ts +195 -0
- package/src/shims/path.ts +246 -0
- package/src/shims/perf_hooks.ts +92 -0
- package/src/shims/process.ts +804 -0
- package/src/shims/rollup.ts +149 -0
- package/src/shims/string_decoder.ts +396 -0
- package/src/shims/sync-child.ts +469 -0
- package/src/shims/tls.ts +94 -0
- package/src/shims/url.ts +217 -0
- package/src/shims/v8.ts +113 -0
- package/src/shims/vfs-adapter.ts +408 -0
- package/src/shims/vm.ts +132 -0
- package/src/shims/wasi.ts +1440 -0
- package/src/shims/worker_threads.ts +114 -0
- package/src/shims/zlib-constants.ts +65 -0
- package/src/shims/zlib.ts +228 -0
- package/src/transform.ts +324 -0
- package/src/types/external.d.ts +55 -0
- package/src/types/package-json.ts +17 -0
- package/src/types/pako-zlib.d.ts +30 -0
- package/src/types/sha.js.d.ts +14 -0
- package/src/utils/binary-encoding.ts +43 -0
- package/src/utils/glob.ts +54 -0
- package/src/utils/hash.ts +12 -0
- package/src/virtual-fs.ts +1048 -0
- package/src/vite-plugin.ts +76 -0
- package/src/worker/runtime-worker.ts +128 -0
- package/src/worker-runtime.ts +145 -0
|
@@ -0,0 +1,1638 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* esbuild shim - Uses esbuild-wasm for transforms in the browser
|
|
3
|
+
* Provides VFS integration for file access
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { heldWork } from '../host-globals';
|
|
7
|
+
import type { VirtualFS } from '../virtual-fs';
|
|
8
|
+
import { ESBUILD_WASM_BINARY_CDN, ESBUILD_WASM_BROWSER_CDN } from '../config/cdn';
|
|
9
|
+
import { __nodeResolverFor } from '../node-resolver';
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Node.js built-in module names. Used by the VFS plugin to provide empty stubs
|
|
13
|
+
* for builtins that leak as transitive deps (e.g., `path` from `@vercel/oidc`).
|
|
14
|
+
*/
|
|
15
|
+
const NODE_BUILTINS = new Set([
|
|
16
|
+
'assert', 'buffer', 'child_process', 'cluster', 'crypto', 'dgram', 'dns',
|
|
17
|
+
'events', 'fs', 'http', 'http2', 'https', 'net', 'os', 'path', 'perf_hooks',
|
|
18
|
+
'querystring', 'readline', 'stream', 'string_decoder', 'timers', 'tls',
|
|
19
|
+
'url', 'util', 'v8', 'vm', 'worker_threads', 'zlib', 'async_hooks',
|
|
20
|
+
'inspector', 'module', 'process', 'console', 'constants', 'domain',
|
|
21
|
+
'punycode', 'sys', 'tty',
|
|
22
|
+
]);
|
|
23
|
+
|
|
24
|
+
// ============================================================================
|
|
25
|
+
// Type Definitions
|
|
26
|
+
// ============================================================================
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Represents a package.json exports map entry.
|
|
30
|
+
* Can be a direct path string or a conditional exports object with nested conditions.
|
|
31
|
+
*
|
|
32
|
+
* @example Direct string entry:
|
|
33
|
+
* ```json
|
|
34
|
+
* { "exports": "./dist/index.js" }
|
|
35
|
+
* ```
|
|
36
|
+
*
|
|
37
|
+
* @example Conditional exports:
|
|
38
|
+
* ```json
|
|
39
|
+
* {
|
|
40
|
+
* "exports": {
|
|
41
|
+
* ".": {
|
|
42
|
+
* "import": "./dist/esm/index.js",
|
|
43
|
+
* "require": "./dist/cjs/index.js"
|
|
44
|
+
* }
|
|
45
|
+
* }
|
|
46
|
+
* }
|
|
47
|
+
* ```
|
|
48
|
+
*
|
|
49
|
+
* @example Nested conditions (e.g., convex package):
|
|
50
|
+
* ```json
|
|
51
|
+
* {
|
|
52
|
+
* "exports": {
|
|
53
|
+
* "./server": {
|
|
54
|
+
* "convex": {
|
|
55
|
+
* "import": "./dist/server.js"
|
|
56
|
+
* },
|
|
57
|
+
* "default": "./dist/server.js"
|
|
58
|
+
* }
|
|
59
|
+
* }
|
|
60
|
+
* }
|
|
61
|
+
* ```
|
|
62
|
+
*/
|
|
63
|
+
type ExportEntry = string | ExportConditions;
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Conditional exports object mapping condition names to export entries.
|
|
67
|
+
* Conditions can be nested to support complex resolution scenarios.
|
|
68
|
+
*/
|
|
69
|
+
interface ExportConditions {
|
|
70
|
+
[condition: string]: ExportEntry;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Result of resolving a node module import.
|
|
75
|
+
*/
|
|
76
|
+
interface NodeModuleResolution {
|
|
77
|
+
/** The resolved absolute path to the module file */
|
|
78
|
+
path: string;
|
|
79
|
+
/** Plugin data to pass to the onLoad handler */
|
|
80
|
+
pluginData: { fromVFS: boolean };
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// esbuild-wasm types
|
|
84
|
+
export interface TransformOptions {
|
|
85
|
+
loader?: 'js' | 'jsx' | 'ts' | 'tsx' | 'json' | 'css';
|
|
86
|
+
format?: 'iife' | 'cjs' | 'esm';
|
|
87
|
+
target?: string | string[];
|
|
88
|
+
minify?: boolean;
|
|
89
|
+
sourcemap?: boolean | 'inline' | 'external';
|
|
90
|
+
jsx?: 'transform' | 'preserve';
|
|
91
|
+
jsxFactory?: string;
|
|
92
|
+
jsxFragment?: string;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/** A message esbuild returned, as much of it as the formatter reads. */
|
|
96
|
+
export interface EsbuildMessage {
|
|
97
|
+
text?: string;
|
|
98
|
+
location?: { file: string; line: number; column: number } | null;
|
|
99
|
+
notes?: Array<{ text: string }>;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/** A build's metafile, as much of it as the summary reads. */
|
|
103
|
+
export interface EsbuildMetafile {
|
|
104
|
+
outputs?: Record<string, { bytes?: number }>;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
export interface TransformResult {
|
|
108
|
+
code: string;
|
|
109
|
+
map: string;
|
|
110
|
+
warnings: unknown[];
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
export interface BuildOptions {
|
|
114
|
+
/**
|
|
115
|
+
* esbuild's two entry forms: a list of files, and the named form
|
|
116
|
+
* `{ out: "in.ts" }` that gives each output its own name. Only the list is
|
|
117
|
+
* made absolute against the working directory; the named form is passed on
|
|
118
|
+
* as it was written.
|
|
119
|
+
*/
|
|
120
|
+
entryPoints?: string[] | Record<string, string>;
|
|
121
|
+
stdin?: { contents: string; resolveDir?: string; loader?: 'js' | 'jsx' | 'ts' | 'tsx' | 'json' | 'css' };
|
|
122
|
+
bundle?: boolean;
|
|
123
|
+
outdir?: string;
|
|
124
|
+
outfile?: string;
|
|
125
|
+
format?: 'iife' | 'cjs' | 'esm';
|
|
126
|
+
platform?: 'browser' | 'node' | 'neutral';
|
|
127
|
+
target?: string | string[];
|
|
128
|
+
minify?: boolean;
|
|
129
|
+
sourcemap?: boolean | 'inline' | 'external';
|
|
130
|
+
external?: string[];
|
|
131
|
+
write?: boolean;
|
|
132
|
+
plugins?: unknown[];
|
|
133
|
+
absWorkingDir?: string;
|
|
134
|
+
/** Path of a tsconfig, read from the engine's filesystem and handed to esbuild as `tsconfigRaw`. */
|
|
135
|
+
tsconfig?: string;
|
|
136
|
+
tsconfigRaw?: string | TsconfigJson;
|
|
137
|
+
/** Where a workspace member's sources are, as tsconfig paths with absolute targets. */
|
|
138
|
+
workspacePaths?: Record<string, string[]>;
|
|
139
|
+
/**
|
|
140
|
+
* The packages this build is not of: an import of one is left to whoever
|
|
141
|
+
* builds it, external under the specifier it was written with, rather than
|
|
142
|
+
* bundled in. `self` are the specifiers this build IS of, which stay inside
|
|
143
|
+
* it however they are imported. The ones an import actually reached come
|
|
144
|
+
* back as `neighbors` on the result.
|
|
145
|
+
*/
|
|
146
|
+
neighbors?: { names: string[]; self?: string[] };
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
export interface BuildResult {
|
|
150
|
+
errors: unknown[];
|
|
151
|
+
warnings: unknown[];
|
|
152
|
+
/** The specifiers `neighbors` left external, sorted; absent when a build named none. */
|
|
153
|
+
neighbors?: string[];
|
|
154
|
+
outputFiles?: Array<{ path: string; contents: Uint8Array; text: string }>;
|
|
155
|
+
metafile?: { inputs?: Record<string, unknown>; outputs?: Record<string, unknown> };
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
// Window.__esbuild type is declared in src/types/external.d.ts
|
|
159
|
+
|
|
160
|
+
// ============================================================================
|
|
161
|
+
// Export Condition Resolution
|
|
162
|
+
// ============================================================================
|
|
163
|
+
|
|
164
|
+
/**
|
|
165
|
+
* The priority order for export conditions when resolving package exports.
|
|
166
|
+
*
|
|
167
|
+
* Order rationale:
|
|
168
|
+
* 1. "module" - ESM entry point (preferred for modern bundlers)
|
|
169
|
+
* 2. "import" - ESM import condition (standard Node.js condition)
|
|
170
|
+
* 3. "require" - CJS require condition (fallback for CommonJS)
|
|
171
|
+
* 4. "default" - Fallback condition (lowest priority)
|
|
172
|
+
*
|
|
173
|
+
* Packages with custom conditions (e.g. "convex", "react-native") will
|
|
174
|
+
* fall through to one of these standard conditions.
|
|
175
|
+
*/
|
|
176
|
+
const EXPORT_CONDITION_PRIORITY = ['module', 'import', 'require', 'default'] as const;
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* Resolves a package.json exports entry to a file path by evaluating export conditions.
|
|
180
|
+
*
|
|
181
|
+
* This function handles the Node.js package exports map resolution algorithm,
|
|
182
|
+
* supporting both simple string exports and conditional exports with nested structures.
|
|
183
|
+
*
|
|
184
|
+
* @param entry - The exports map entry to resolve. Can be:
|
|
185
|
+
* - A string path (e.g., "./dist/index.js")
|
|
186
|
+
* - A conditional exports object with condition keys
|
|
187
|
+
* - Nested conditional objects for complex packages
|
|
188
|
+
*
|
|
189
|
+
* @returns The resolved file path relative to the package root, or undefined if
|
|
190
|
+
* no matching condition is found.
|
|
191
|
+
*
|
|
192
|
+
* @example Simple string entry:
|
|
193
|
+
* ```ts
|
|
194
|
+
* resolveExportConditions("./dist/index.js")
|
|
195
|
+
* // Returns: "./dist/index.js"
|
|
196
|
+
* ```
|
|
197
|
+
*
|
|
198
|
+
* @example Conditional exports:
|
|
199
|
+
* ```ts
|
|
200
|
+
* resolveExportConditions({
|
|
201
|
+
* import: "./dist/esm/index.js",
|
|
202
|
+
* require: "./dist/cjs/index.js",
|
|
203
|
+
* default: "./dist/index.js"
|
|
204
|
+
* })
|
|
205
|
+
* // Returns: "./dist/esm/index.js" (import has higher priority)
|
|
206
|
+
* ```
|
|
207
|
+
*
|
|
208
|
+
* @example Nested conditions (convex package style):
|
|
209
|
+
* ```ts
|
|
210
|
+
* resolveExportConditions({
|
|
211
|
+
* convex: { import: "./dist/convex.js" },
|
|
212
|
+
* default: "./dist/default.js"
|
|
213
|
+
* })
|
|
214
|
+
* // Returns: "./dist/convex.js" (convex condition with nested import)
|
|
215
|
+
* ```
|
|
216
|
+
*/
|
|
217
|
+
function resolveExportConditions(entry: ExportEntry): string | undefined {
|
|
218
|
+
// Direct string path - return as-is
|
|
219
|
+
if (typeof entry === 'string') {
|
|
220
|
+
return entry;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
// Conditional exports object - evaluate conditions in priority order
|
|
224
|
+
if (typeof entry === 'object' && entry !== null) {
|
|
225
|
+
for (const condition of EXPORT_CONDITION_PRIORITY) {
|
|
226
|
+
const conditionValue = entry[condition];
|
|
227
|
+
if (conditionValue !== undefined) {
|
|
228
|
+
// Recursively resolve nested conditions
|
|
229
|
+
const result = resolveExportConditions(conditionValue);
|
|
230
|
+
if (result) {
|
|
231
|
+
return result;
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
return undefined;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
// ============================================================================
|
|
241
|
+
// Node Modules Resolution
|
|
242
|
+
// ============================================================================
|
|
243
|
+
|
|
244
|
+
/**
|
|
245
|
+
* Resolves a bare import (e.g. "convex/server", "react") to an absolute file
|
|
246
|
+
* path in the VFS, so the browser build bundles the dependency a snapshot of
|
|
247
|
+
* node_modules holds rather than leaving it external with no runtime to load it.
|
|
248
|
+
*
|
|
249
|
+
* The plugin used to carry its own subset of Node's algorithm, as the runtime's
|
|
250
|
+
* require and the simple loader each carried theirs; the three disagreed with
|
|
251
|
+
* each other and with Node, and every app found a new gap. They all ask the
|
|
252
|
+
* shared resolver now (`node-resolution.ts` behind `node-resolver.ts`), this
|
|
253
|
+
* one with the bundler's profile: module and import entries first, TypeScript
|
|
254
|
+
* sources, and the extensions the build was given. The importer's directory is
|
|
255
|
+
* where the walk starts, so a package in a workspace finds its own copy in the
|
|
256
|
+
* node_modules tree nearest the importing file rather than the root's.
|
|
257
|
+
*/
|
|
258
|
+
function resolveNodeModuleImport(
|
|
259
|
+
vfs: VirtualFS,
|
|
260
|
+
importPath: string,
|
|
261
|
+
extensions: string[],
|
|
262
|
+
importer: string = ''
|
|
263
|
+
): NodeModuleResolution | null {
|
|
264
|
+
const __importerDir = importer.startsWith('/') ? (importer.slice(0, importer.lastIndexOf('/')) || '/') : '/';
|
|
265
|
+
const __resolved = __nodeResolverFor(vfs, 'bundler', extensions).resolve(importPath, __importerDir);
|
|
266
|
+
return __resolved ? { path: __resolved, pluginData: { fromVFS: true } } : null;
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
/**
|
|
270
|
+
* Resolves a subpath import (e.g., "convex/server" -> "./server" subpath).
|
|
271
|
+
*
|
|
272
|
+
* Resolution order:
|
|
273
|
+
* 1. Check exports map for "./{subpath}" key with condition resolution
|
|
274
|
+
* 2. Fall back to direct file path resolution with extensions
|
|
275
|
+
*/
|
|
276
|
+
function resolveSubpathImport(
|
|
277
|
+
vfs: VirtualFS,
|
|
278
|
+
packageJson: { exports?: Record<string, ExportEntry> | ExportEntry },
|
|
279
|
+
nodeModulesBase: string,
|
|
280
|
+
subPath: string,
|
|
281
|
+
extensions: string[]
|
|
282
|
+
): string | null {
|
|
283
|
+
// Try exports map first
|
|
284
|
+
if (packageJson.exports && typeof packageJson.exports === 'object') {
|
|
285
|
+
const exportKey = './' + subPath;
|
|
286
|
+
const exportsMap = packageJson.exports as Record<string, ExportEntry>;
|
|
287
|
+
const exportEntry = exportsMap[exportKey];
|
|
288
|
+
|
|
289
|
+
if (exportEntry) {
|
|
290
|
+
const exportPath = resolveExportConditions(exportEntry);
|
|
291
|
+
if (exportPath) {
|
|
292
|
+
const resolvedPath = nodeModulesBase + '/' + exportPath.replace(/^\.\//, '');
|
|
293
|
+
const foundPath = findVFSFile(vfs, resolvedPath, ['', '.js', '.ts', '.mjs']);
|
|
294
|
+
if (foundPath) {
|
|
295
|
+
return foundPath;
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
// Fall back to direct path resolution
|
|
302
|
+
const directPath = nodeModulesBase + '/' + subPath;
|
|
303
|
+
return findVFSFile(vfs, directPath, extensions);
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
/**
|
|
307
|
+
* Resolves the main entry point of a package (e.g., "convex" without subpath).
|
|
308
|
+
*
|
|
309
|
+
* Resolution order:
|
|
310
|
+
* 1. Check exports map "." key with condition resolution
|
|
311
|
+
* 2. Fall back to "module" field (ESM entry)
|
|
312
|
+
* 3. Fall back to "main" field (CJS entry)
|
|
313
|
+
* 4. Default to "index.js"
|
|
314
|
+
*/
|
|
315
|
+
function resolveMainImport(
|
|
316
|
+
vfs: VirtualFS,
|
|
317
|
+
packageJson: {
|
|
318
|
+
exports?: Record<string, ExportEntry> | ExportEntry;
|
|
319
|
+
module?: string;
|
|
320
|
+
main?: string;
|
|
321
|
+
},
|
|
322
|
+
nodeModulesBase: string,
|
|
323
|
+
extensions: string[]
|
|
324
|
+
): string | null {
|
|
325
|
+
// Try exports map first
|
|
326
|
+
if (packageJson.exports) {
|
|
327
|
+
// The main export can be at "." key or be the exports value itself
|
|
328
|
+
const mainExport = typeof packageJson.exports === 'object' && !Array.isArray(packageJson.exports)
|
|
329
|
+
? (packageJson.exports['.'] || packageJson.exports)
|
|
330
|
+
: packageJson.exports;
|
|
331
|
+
|
|
332
|
+
const exportPath = resolveExportConditions(mainExport as ExportEntry);
|
|
333
|
+
if (exportPath) {
|
|
334
|
+
const resolvedPath = nodeModulesBase + '/' + exportPath.replace(/^\.\//, '');
|
|
335
|
+
const foundPath = findVFSFile(vfs, resolvedPath, ['', '.js', '.ts', '.mjs']);
|
|
336
|
+
if (foundPath) {
|
|
337
|
+
return foundPath;
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
// Fall back to module/main fields
|
|
343
|
+
// Prefer "module" (ESM) over "main" (CJS) for better tree-shaking
|
|
344
|
+
const mainField = packageJson.module || packageJson.main || 'index.js';
|
|
345
|
+
const resolvedPath = nodeModulesBase + '/' + mainField.replace(/^\.\//, '');
|
|
346
|
+
return findVFSFile(vfs, resolvedPath, extensions);
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
// ============================================================================
|
|
350
|
+
// Module State
|
|
351
|
+
// ============================================================================
|
|
352
|
+
|
|
353
|
+
// State
|
|
354
|
+
/**
|
|
355
|
+
* The esbuild this realm builds and transforms through: the wasm module
|
|
356
|
+
* loaded here, or a host installed with `useHost`. A realm with a host has
|
|
357
|
+
* one wherever it is, window or no window.
|
|
358
|
+
*/
|
|
359
|
+
let esbuildInstance: typeof import('esbuild-wasm') | null = null;
|
|
360
|
+
|
|
361
|
+
/**
|
|
362
|
+
* The instance, for the lanes outside this module that need it: the module
|
|
363
|
+
* transformer and the dev servers. Exporting the `let` itself put a live
|
|
364
|
+
* binding in the shim's namespace, which is the surface a guest's
|
|
365
|
+
* `require("esbuild")` reads; an accessor keeps that surface a stable
|
|
366
|
+
* function rather than a value that changes under the guest.
|
|
367
|
+
*/
|
|
368
|
+
export function getEsbuildInstance(): typeof import('esbuild-wasm') | null {
|
|
369
|
+
return esbuildInstance;
|
|
370
|
+
}
|
|
371
|
+
let initPromise: Promise<void> | null = null;
|
|
372
|
+
let wasmURL = ESBUILD_WASM_BINARY_CDN;
|
|
373
|
+
let globalVFS: VirtualFS | null = null;
|
|
374
|
+
|
|
375
|
+
/**
|
|
376
|
+
* Where esbuild-wasm is loaded from, so the page can serve it from its own
|
|
377
|
+
* origin instead of a CDN.
|
|
378
|
+
*/
|
|
379
|
+
let esbuildModuleURL = ESBUILD_WASM_BROWSER_CDN;
|
|
380
|
+
export function setModuleURL(url: string): void {
|
|
381
|
+
esbuildModuleURL = url;
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
/** An esbuild that runs elsewhere: a host a realm sends its builds to. */
|
|
385
|
+
export interface EsbuildHost {
|
|
386
|
+
build: (options: BuildOptions) => Promise<BuildResult>;
|
|
387
|
+
transform: (code: string, options?: TransformOptions) => Promise<TransformResult>;
|
|
388
|
+
/** A host that can answer a transform before returning, native esbuild under a Node host, answers `transformSync`. */
|
|
389
|
+
transformSync?: (code: string, options?: TransformOptions) => TransformResult;
|
|
390
|
+
prebundle?: (options: BuildOptions) => Promise<BuildResult>;
|
|
391
|
+
/**
|
|
392
|
+
* The host answers the `neighbors` option itself: a build carrying it
|
|
393
|
+
* crosses with the option in place and no plugin, since a plugin is a
|
|
394
|
+
* function in this realm and cannot cross. A host that does not say so is
|
|
395
|
+
* given the shim's plugin, as esbuild itself would be.
|
|
396
|
+
*/
|
|
397
|
+
neighbors?: boolean;
|
|
398
|
+
}
|
|
399
|
+
let currentHost: EsbuildHost | null = null;
|
|
400
|
+
|
|
401
|
+
let inlineEsbuild: Promise<typeof import('esbuild-wasm')> | null = null;
|
|
402
|
+
function ownEsbuild(): Promise<typeof import('esbuild-wasm')> {
|
|
403
|
+
// A build that brings plugins of its own, a bundler such as tsup does,
|
|
404
|
+
// cannot cross to the host: a plugin is a function in this realm. It
|
|
405
|
+
// runs on esbuild here, loaded once and kept; the host stays for the
|
|
406
|
+
// builds that carry only the filesystem plugin.
|
|
407
|
+
inlineEsbuild ??= import(
|
|
408
|
+
/* @vite-ignore */
|
|
409
|
+
esbuildModuleURL
|
|
410
|
+
).then(async (esbuild) => {
|
|
411
|
+
await esbuild.initialize({ wasmURL });
|
|
412
|
+
return esbuild;
|
|
413
|
+
}).catch((cause) => {
|
|
414
|
+
// A load that failed, a page whose server was away for a moment, is not kept: the next build tries again.
|
|
415
|
+
inlineEsbuild = null;
|
|
416
|
+
throw cause;
|
|
417
|
+
});
|
|
418
|
+
return inlineEsbuild;
|
|
419
|
+
}
|
|
420
|
+
// After a build, a bundler formats the messages esbuild returned and may
|
|
421
|
+
// summarize the metafile; the shim had neither, and tsup fell over the first
|
|
422
|
+
// warning. Both are answered here, in the shape esbuild's own answers take.
|
|
423
|
+
export async function formatMessages(messages: EsbuildMessage[], options?: { kind?: string }): Promise<string[]> {
|
|
424
|
+
const kind = options && options.kind === "error" ? "ERROR" : "WARNING";
|
|
425
|
+
return (messages || []).map((message) => {
|
|
426
|
+
const where = message && message.location ? `${message.location.file}:${message.location.line}:${message.location.column}: ` : "";
|
|
427
|
+
const notes = message && Array.isArray(message.notes) ? message.notes.map((note) => `\n ${note.text}`).join("") : "";
|
|
428
|
+
return `${where}${kind}: ${message && message.text || ""}${notes}\n`;
|
|
429
|
+
});
|
|
430
|
+
}
|
|
431
|
+
export async function analyzeMetafile(metafile: string | EsbuildMetafile, options?: unknown): Promise<string> {
|
|
432
|
+
const parsed = typeof metafile === "string" ? JSON.parse(metafile) : metafile;
|
|
433
|
+
const outputs = parsed && parsed.outputs ? Object.entries(parsed.outputs) : [];
|
|
434
|
+
return outputs.map(([name, output]) => ` ${name} ${output && typeof (output as { bytes?: number }).bytes === "number" ? (output as { bytes: number }).bytes : 0} bytes`).join("\n");
|
|
435
|
+
}
|
|
436
|
+
/**
|
|
437
|
+
* Send this realm's builds and transforms to a host that runs them
|
|
438
|
+
* elsewhere and ends that elsewhere when it is idle. A host receives the
|
|
439
|
+
* shim's own build options, plugins included; the host drops them, and the
|
|
440
|
+
* realm that runs the build adds the filesystem plugin again over its own
|
|
441
|
+
* filesystem.
|
|
442
|
+
*/
|
|
443
|
+
/**
|
|
444
|
+
* The plugins the shim itself puts on a build: the filesystem it reads through,
|
|
445
|
+
* and the externaliser the `neighbors` option becomes. They are the shim's own
|
|
446
|
+
* answer to its own options, and a host receives them the way it receives every
|
|
447
|
+
* other option the shim translated; only a plugin the CALLER wrote is a
|
|
448
|
+
* function of this realm that cannot cross.
|
|
449
|
+
*/
|
|
450
|
+
const SHIM_PLUGINS = new Set(["vfs-loader", "neighbors"]);
|
|
451
|
+
|
|
452
|
+
export function useHost(host: EsbuildHost | null): void {
|
|
453
|
+
currentHost = host;
|
|
454
|
+
// The thread for synchronous calls starts now, while this realm's loop
|
|
455
|
+
// still runs: a realm that installs a host is one guests run in, and a
|
|
456
|
+
// worker created inside a blocked call never starts (its start is the
|
|
457
|
+
// creator's loop's work), which held the execution worker for minutes.
|
|
458
|
+
// A realm without a Worker or shared memory is left as it is; the call
|
|
459
|
+
// says what is missing when it comes.
|
|
460
|
+
if (host && !(typeof host.transformSync === 'function')) { try { __syncServiceStart(); } catch { /* reported at the call */ } }
|
|
461
|
+
if (!host && syncService) __syncServiceDrop(syncService);
|
|
462
|
+
esbuildInstance = (host ? {
|
|
463
|
+
build: (options: BuildOptions) => typeof host.prebundle === "function" && (options.plugins || []).some((plugin) => plugin && (plugin as { name?: string }).name === "vite:dep-pre-bundle")
|
|
464
|
+
? host.prebundle(options)
|
|
465
|
+
: (options.plugins || []).some((plugin) => plugin && !SHIM_PLUGINS.has((plugin as { name?: string }).name ?? ""))
|
|
466
|
+
// Own esbuild takes no `neighbors`; a build that cannot cross for its
|
|
467
|
+
// own plugins loses the option here, which no pack build carries.
|
|
468
|
+
? ownEsbuild().then((esbuild) => { const { neighbors: __n, ...own } = options as BuildOptions & { neighbors?: unknown }; void __n; return esbuild.build(own); })
|
|
469
|
+
: host.build(options),
|
|
470
|
+
transform: (code: string, options?: TransformOptions) => host.transform(code, options)
|
|
471
|
+
} : null) as typeof esbuildInstance;
|
|
472
|
+
if (typeof window !== "undefined") {
|
|
473
|
+
window.__esbuild = esbuildInstance ?? void 0;
|
|
474
|
+
window.__esbuildInitPromise = esbuildInstance ? Promise.resolve() : void 0;
|
|
475
|
+
}
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
/**
|
|
479
|
+
* Set the VirtualFS instance for file access
|
|
480
|
+
*/
|
|
481
|
+
export function setVFS(vfs: VirtualFS): void {
|
|
482
|
+
globalVFS = vfs;
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
/**
|
|
486
|
+
* Set the URL for the esbuild WASM file
|
|
487
|
+
*/
|
|
488
|
+
export function setWasmURL(url: string): void {
|
|
489
|
+
wasmURL = url;
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
/**
|
|
493
|
+
* Initialize esbuild-wasm
|
|
494
|
+
* Must be called before using transform or build
|
|
495
|
+
*/
|
|
496
|
+
export async function initialize(options?: { wasmURL?: string }): Promise<void> {
|
|
497
|
+
if (esbuildInstance) {
|
|
498
|
+
return; // Already initialized
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
// Check for shared esbuild instance from transform.ts
|
|
502
|
+
if (typeof window !== 'undefined' && window.__esbuild) {
|
|
503
|
+
esbuildInstance = window.__esbuild;
|
|
504
|
+
return;
|
|
505
|
+
}
|
|
506
|
+
|
|
507
|
+
// Wait for any in-progress initialization from transform.ts
|
|
508
|
+
if (typeof window !== 'undefined' && window.__esbuildInitPromise) {
|
|
509
|
+
await window.__esbuildInitPromise;
|
|
510
|
+
if (window.__esbuild) {
|
|
511
|
+
esbuildInstance = window.__esbuild;
|
|
512
|
+
return;
|
|
513
|
+
}
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
if (initPromise) {
|
|
517
|
+
return initPromise; // Our initialization in progress
|
|
518
|
+
}
|
|
519
|
+
|
|
520
|
+
initPromise = (async () => {
|
|
521
|
+
try {
|
|
522
|
+
// Dynamically import esbuild-wasm from CDN
|
|
523
|
+
const esbuild = await import(
|
|
524
|
+
/* @vite-ignore */
|
|
525
|
+
esbuildModuleURL
|
|
526
|
+
);
|
|
527
|
+
|
|
528
|
+
await esbuild.initialize({
|
|
529
|
+
wasmURL: options?.wasmURL || wasmURL,
|
|
530
|
+
});
|
|
531
|
+
|
|
532
|
+
esbuildInstance = esbuild;
|
|
533
|
+
} catch (error) {
|
|
534
|
+
initPromise = null;
|
|
535
|
+
throw new Error(`Failed to initialize esbuild-wasm: ${error}`);
|
|
536
|
+
}
|
|
537
|
+
})();
|
|
538
|
+
|
|
539
|
+
return initPromise;
|
|
540
|
+
}
|
|
541
|
+
|
|
542
|
+
/**
|
|
543
|
+
* Check if esbuild is initialized
|
|
544
|
+
*/
|
|
545
|
+
export function isInitialized(): boolean {
|
|
546
|
+
return esbuildInstance !== null;
|
|
547
|
+
}
|
|
548
|
+
|
|
549
|
+
// ============================================================================
|
|
550
|
+
// Transform API
|
|
551
|
+
// ============================================================================
|
|
552
|
+
|
|
553
|
+
/**
|
|
554
|
+
* Transform code using esbuild
|
|
555
|
+
*/
|
|
556
|
+
// A script is not finished while its build is running. The engine ends a
|
|
557
|
+
// `node` run once its output has been quiet for half a second, which is when
|
|
558
|
+
// tsup is in the middle of an esbuild build that prints nothing until it is
|
|
559
|
+
// done: the shell moved on, the next Dockerfile stage copied a `dist` that was
|
|
560
|
+
// still being written, and the runner had no `index.js`. In-flight esbuild work
|
|
561
|
+
// is counted here, and the run loop holds a run for as long as any is pending.
|
|
562
|
+
// The count is shared through `host-globals`, which puts it on the realm only
|
|
563
|
+
// once a guest exists; importing the engine adds no name to a host's global.
|
|
564
|
+
// It is read at each call, never captured at load, so the name a runtime puts
|
|
565
|
+
// up is the one this counts on.
|
|
566
|
+
export async function transform(
|
|
567
|
+
code: string,
|
|
568
|
+
options?: TransformOptions
|
|
569
|
+
): Promise<TransformResult> {
|
|
570
|
+
const __heldWork = heldWork();
|
|
571
|
+
__heldWork.count += 1;
|
|
572
|
+
try { return await __transformHeld(code, options); } finally { __heldWork.count -= 1; }
|
|
573
|
+
}
|
|
574
|
+
async function __transformHeld(
|
|
575
|
+
code: string,
|
|
576
|
+
options?: TransformOptions
|
|
577
|
+
): Promise<TransformResult> {
|
|
578
|
+
if (!esbuildInstance) {
|
|
579
|
+
await initialize();
|
|
580
|
+
}
|
|
581
|
+
|
|
582
|
+
if (!esbuildInstance) {
|
|
583
|
+
throw new Error('esbuild not initialized');
|
|
584
|
+
}
|
|
585
|
+
|
|
586
|
+
return esbuildInstance.transform(code, options);
|
|
587
|
+
}
|
|
588
|
+
|
|
589
|
+
// ============================================================================
|
|
590
|
+
// Synchronous transform
|
|
591
|
+
// ============================================================================
|
|
592
|
+
|
|
593
|
+
/**
|
|
594
|
+
* `transformSync`, as esbuild answers it in Node: the code transformed
|
|
595
|
+
* before the call returns. import-from-string, under bundle-import and
|
|
596
|
+
* vite-plugin-fake-server, transforms the bundle it is about to import that
|
|
597
|
+
* way, and vue-pure-admin's mock API died on the shim's refusal ("transformSync
|
|
598
|
+
* is not available in browser"). esbuild-wasm has no synchronous API in a
|
|
599
|
+
* browser realm, and Node's own esbuild-wasm answers the call the way it is
|
|
600
|
+
* answered here: esbuild runs on another thread, the request crosses to it,
|
|
601
|
+
* and the caller blocks on shared memory (`Atomics.wait`) until the answer
|
|
602
|
+
* has been written there. A host that answers synchronously itself, native
|
|
603
|
+
* esbuild under a Node host, is asked first. A realm that cannot block, a
|
|
604
|
+
* page's main thread, cannot restore this and says so.
|
|
605
|
+
*/
|
|
606
|
+
interface SyncService {
|
|
607
|
+
/** [0] the answer's state: 0 waiting, 1 final chunk written, 2 a chunk written with more to come; [1] the chunk's length; [2] 1 once the thread runs. */
|
|
608
|
+
control: Int32Array;
|
|
609
|
+
data: Uint8Array;
|
|
610
|
+
worker: { postMessage(message: unknown): void; terminate(): unknown; unref?: () => void; on?: (event: string, listener: (value: unknown) => void) => unknown; onerror?: unknown };
|
|
611
|
+
/** esbuild loaded on the thread, after the first call. */
|
|
612
|
+
initialized: boolean;
|
|
613
|
+
/** What the thread reported through its error event, where the realm's loop ran to deliver it. */
|
|
614
|
+
failure?: string;
|
|
615
|
+
}
|
|
616
|
+
let syncService: SyncService | null = null;
|
|
617
|
+
const SYNC_STATE = 0;
|
|
618
|
+
const SYNC_LENGTH = 1;
|
|
619
|
+
const SYNC_STARTED = 2;
|
|
620
|
+
/** The shared window an answer crosses through; a longer answer crosses in chunks. */
|
|
621
|
+
const SYNC_DATA_BYTES = 1 << 20;
|
|
622
|
+
/**
|
|
623
|
+
* How long a call waits for the thread to be running at all. A worker this
|
|
624
|
+
* realm starts is started by this realm's own loop: one created and then
|
|
625
|
+
* waited on in the same synchronous call never starts, and the wait would
|
|
626
|
+
* be a deadlock. The thread is started when a host is installed, while the
|
|
627
|
+
* loop still runs; a call that finds it not yet running waits this long and
|
|
628
|
+
* then says so, rather than holding the realm.
|
|
629
|
+
*/
|
|
630
|
+
const SYNC_START_WAIT_MS = 5_000;
|
|
631
|
+
/** Loading esbuild on the thread, once; the thread reports a failed load at once. */
|
|
632
|
+
const SYNC_INIT_WAIT_MS = 60_000;
|
|
633
|
+
const SYNC_WAIT_MS = 120_000;
|
|
634
|
+
|
|
635
|
+
/**
|
|
636
|
+
* The thread esbuild runs on for synchronous calls: a module worker that
|
|
637
|
+
* loads esbuild from the shim's module URL, takes each request by message
|
|
638
|
+
* and writes its answer into the shared window, chunk by chunk, notifying
|
|
639
|
+
* the caller and waiting for the caller to take each chunk but the last.
|
|
640
|
+
* `control[0]` is the state: 0 waiting, 1 final chunk written, 2 a chunk
|
|
641
|
+
* written with more to come; `control[1]` is the chunk's length.
|
|
642
|
+
*/
|
|
643
|
+
function __syncWorkerSource(): string {
|
|
644
|
+
return `
|
|
645
|
+
const port = typeof self !== 'undefined' && typeof self.postMessage === 'function' ? self : (await import('node:worker_threads')).parentPort;
|
|
646
|
+
const encoder = new TextEncoder();
|
|
647
|
+
let esbuild, control, data;
|
|
648
|
+
function deliver(text) {
|
|
649
|
+
const bytes = encoder.encode(text);
|
|
650
|
+
let offset = 0;
|
|
651
|
+
do {
|
|
652
|
+
const length = Math.min(bytes.length - offset, data.length);
|
|
653
|
+
data.set(bytes.subarray(offset, offset + length));
|
|
654
|
+
offset += length;
|
|
655
|
+
control[1] = length;
|
|
656
|
+
const more = offset < bytes.length;
|
|
657
|
+
Atomics.store(control, 0, more ? 2 : 1);
|
|
658
|
+
Atomics.notify(control, 0);
|
|
659
|
+
if (more) Atomics.wait(control, 0, 2);
|
|
660
|
+
} while (offset < bytes.length);
|
|
661
|
+
}
|
|
662
|
+
function answer(work) {
|
|
663
|
+
work.then(
|
|
664
|
+
(result) => deliver(JSON.stringify({ ok: true, result })),
|
|
665
|
+
(error) => deliver(JSON.stringify({ ok: false, error: { message: String(error && error.message || error), errors: error && error.errors || [], warnings: error && error.warnings || [] } })),
|
|
666
|
+
);
|
|
667
|
+
}
|
|
668
|
+
function receive(message) {
|
|
669
|
+
if (message.type === 'attach') {
|
|
670
|
+
control = new Int32Array(message.control);
|
|
671
|
+
data = new Uint8Array(message.data);
|
|
672
|
+
Atomics.store(control, 2, 1);
|
|
673
|
+
Atomics.notify(control, 2);
|
|
674
|
+
} else if (message.type === 'init') {
|
|
675
|
+
answer(import(message.moduleURL).then(async (module) => { esbuild = module; await esbuild.initialize({ wasmURL: message.wasmURL }); return true; }));
|
|
676
|
+
} else if (message.type === 'transform') {
|
|
677
|
+
answer(esbuild.transform(message.code, message.options));
|
|
678
|
+
}
|
|
679
|
+
}
|
|
680
|
+
if (typeof self !== 'undefined' && port === self) self.onmessage = (event) => receive(event.data);
|
|
681
|
+
else port.on('message', receive);
|
|
682
|
+
`;
|
|
683
|
+
}
|
|
684
|
+
|
|
685
|
+
/**
|
|
686
|
+
* Starts the thread, without waiting on it: the worker is created and the
|
|
687
|
+
* shared window posted to it; the thread marks itself started when it runs.
|
|
688
|
+
* Called when a host is installed, so the thread starts while the realm's
|
|
689
|
+
* loop runs, and by a synchronous call that finds none.
|
|
690
|
+
*/
|
|
691
|
+
function __syncServiceStart(): SyncService {
|
|
692
|
+
if (syncService) return syncService;
|
|
693
|
+
if (typeof SharedArrayBuffer !== 'function' || typeof Atomics === 'undefined') {
|
|
694
|
+
throw new Error('transformSync needs shared memory to wait on esbuild, which this realm has none of (SharedArrayBuffer is absent).');
|
|
695
|
+
}
|
|
696
|
+
const WorkerClass = (globalThis as unknown as { Worker?: new (url: unknown, options?: unknown) => SyncService['worker'] }).Worker;
|
|
697
|
+
if (typeof WorkerClass !== 'function') {
|
|
698
|
+
throw new Error('transformSync needs a thread to run esbuild on, which this realm cannot start (Worker is absent).');
|
|
699
|
+
}
|
|
700
|
+
const control = new Int32Array(new SharedArrayBuffer(16));
|
|
701
|
+
const data = new Uint8Array(new SharedArrayBuffer(SYNC_DATA_BYTES));
|
|
702
|
+
const source = __syncWorkerSource();
|
|
703
|
+
// A browser realm starts the worker from a blob of its own origin; Node
|
|
704
|
+
// takes the module as a data: URL.
|
|
705
|
+
const inBrowser = typeof (globalThis as Record<string, unknown>).WorkerGlobalScope !== 'undefined' || typeof (globalThis as Record<string, unknown>).document !== 'undefined';
|
|
706
|
+
const url = inBrowser && typeof Blob === 'function' && typeof URL.createObjectURL === 'function'
|
|
707
|
+
? URL.createObjectURL(new Blob([source], { type: 'text/javascript' }))
|
|
708
|
+
: new URL(`data:text/javascript,${encodeURIComponent(source)}`);
|
|
709
|
+
const worker = new WorkerClass(url, { type: 'module' });
|
|
710
|
+
const service: SyncService = { control, data, worker, initialized: false };
|
|
711
|
+
const failed = (event: unknown) => { service.failure = String((event as { message?: unknown } | null)?.message ?? event); };
|
|
712
|
+
if (typeof worker.on === 'function') worker.on('error', failed);
|
|
713
|
+
else worker.onerror = failed;
|
|
714
|
+
// A Node host is not held open by the thread.
|
|
715
|
+
if (typeof worker.unref === 'function') worker.unref();
|
|
716
|
+
worker.postMessage({ type: 'attach', control: control.buffer, data: data.buffer });
|
|
717
|
+
syncService = service;
|
|
718
|
+
return service;
|
|
719
|
+
}
|
|
720
|
+
|
|
721
|
+
/** Ends the thread and forgets it, so the next call starts afresh. */
|
|
722
|
+
function __syncServiceDrop(service: SyncService): void {
|
|
723
|
+
try { service.worker.terminate(); } catch { /* already gone */ }
|
|
724
|
+
if (syncService === service) syncService = null;
|
|
725
|
+
}
|
|
726
|
+
|
|
727
|
+
/** Blocks until the thread is running, or throws after the start bound with what is known. */
|
|
728
|
+
function __syncAwaitStarted(service: SyncService): void {
|
|
729
|
+
const { control } = service;
|
|
730
|
+
if (Atomics.load(control, SYNC_STARTED) === 1) return;
|
|
731
|
+
Atomics.wait(control, SYNC_STARTED, 0, SYNC_START_WAIT_MS);
|
|
732
|
+
if (Atomics.load(control, SYNC_STARTED) === 1) return;
|
|
733
|
+
__syncServiceDrop(service);
|
|
734
|
+
throw new Error(`esbuild's thread for synchronous calls did not start within ${SYNC_START_WAIT_MS / 1000} s${service.failure ? ` (${service.failure})` : ''}. A worker this realm starts runs only once this realm's loop has turned since; it is started when esbuild's host is installed, and this call found it not yet running.`);
|
|
735
|
+
}
|
|
736
|
+
|
|
737
|
+
/** Blocks until the thread's answer is in the shared window and returns it, or throws what esbuild threw, or throws at the bound. */
|
|
738
|
+
function __syncAnswer(service: SyncService, waitMs: number, stage: string): unknown {
|
|
739
|
+
const { control, data } = service;
|
|
740
|
+
const chunks: Uint8Array[] = [];
|
|
741
|
+
for (;;) {
|
|
742
|
+
Atomics.wait(control, SYNC_STATE, 0, waitMs);
|
|
743
|
+
const state = Atomics.load(control, SYNC_STATE);
|
|
744
|
+
if (state === 0) {
|
|
745
|
+
__syncServiceDrop(service);
|
|
746
|
+
throw new Error(`esbuild did not answer ${stage} within ${waitMs / 1000} s${service.failure ? ` (${service.failure})` : ''}.`);
|
|
747
|
+
}
|
|
748
|
+
chunks.push(data.slice(0, control[SYNC_LENGTH]!));
|
|
749
|
+
if (state !== 2) break;
|
|
750
|
+
Atomics.store(control, SYNC_STATE, 0);
|
|
751
|
+
Atomics.notify(control, SYNC_STATE);
|
|
752
|
+
}
|
|
753
|
+
Atomics.store(control, SYNC_STATE, 0);
|
|
754
|
+
const joined = new Uint8Array(chunks.reduce((total, chunk) => total + chunk.length, 0));
|
|
755
|
+
let offset = 0;
|
|
756
|
+
for (const chunk of chunks) { joined.set(chunk, offset); offset += chunk.length; }
|
|
757
|
+
const answer = JSON.parse(new TextDecoder().decode(joined)) as { ok: true; result: unknown } | { ok: false; error: { message: string; errors: unknown[]; warnings: unknown[] } };
|
|
758
|
+
if (!answer.ok) throw Object.assign(new Error(answer.error.message), { errors: answer.error.errors, warnings: answer.error.warnings });
|
|
759
|
+
return answer.result;
|
|
760
|
+
}
|
|
761
|
+
|
|
762
|
+
/**
|
|
763
|
+
* `esbuild.stop()`, as Node's esbuild has it: the thread held for
|
|
764
|
+
* synchronous calls is ended; nothing else is held here.
|
|
765
|
+
*/
|
|
766
|
+
export async function stop(): Promise<void> {
|
|
767
|
+
const service = syncService;
|
|
768
|
+
if (service) { __syncServiceDrop(service); }
|
|
769
|
+
}
|
|
770
|
+
|
|
771
|
+
/**
|
|
772
|
+
* Transform code synchronously, as `esbuild.transformSync` does in Node.
|
|
773
|
+
*/
|
|
774
|
+
export function transformSync(
|
|
775
|
+
code: string,
|
|
776
|
+
options?: TransformOptions
|
|
777
|
+
): TransformResult {
|
|
778
|
+
if (currentHost && typeof currentHost.transformSync === 'function') return currentHost.transformSync(code, options);
|
|
779
|
+
const service = syncService ?? __syncServiceStart();
|
|
780
|
+
__syncAwaitStarted(service);
|
|
781
|
+
if (!service.initialized) {
|
|
782
|
+
Atomics.store(service.control, SYNC_STATE, 0);
|
|
783
|
+
service.worker.postMessage({ type: 'init', moduleURL: esbuildModuleURL, wasmURL });
|
|
784
|
+
__syncAnswer(service, SYNC_INIT_WAIT_MS, 'loading esbuild');
|
|
785
|
+
service.initialized = true;
|
|
786
|
+
}
|
|
787
|
+
Atomics.store(service.control, SYNC_STATE, 0);
|
|
788
|
+
service.worker.postMessage({ type: 'transform', code, options });
|
|
789
|
+
return __syncAnswer(service, SYNC_WAIT_MS, 'a transform') as TransformResult;
|
|
790
|
+
}
|
|
791
|
+
|
|
792
|
+
/**
|
|
793
|
+
* Transform ESM to CJS
|
|
794
|
+
*/
|
|
795
|
+
export async function transformToCommonJS(
|
|
796
|
+
code: string,
|
|
797
|
+
options?: { loader?: TransformOptions['loader'] }
|
|
798
|
+
): Promise<string> {
|
|
799
|
+
const result = await transform(code, {
|
|
800
|
+
loader: options?.loader || 'js',
|
|
801
|
+
format: 'cjs',
|
|
802
|
+
target: 'es2020',
|
|
803
|
+
});
|
|
804
|
+
|
|
805
|
+
return result.code;
|
|
806
|
+
}
|
|
807
|
+
|
|
808
|
+
// ============================================================================
|
|
809
|
+
// VFS Path Resolution Helpers
|
|
810
|
+
// ============================================================================
|
|
811
|
+
|
|
812
|
+
/**
|
|
813
|
+
* Apply path remapping for VFS.
|
|
814
|
+
* Currently a passthrough — no remapping needed.
|
|
815
|
+
*/
|
|
816
|
+
function remapVFSPath(path: string): string {
|
|
817
|
+
return path;
|
|
818
|
+
}
|
|
819
|
+
|
|
820
|
+
/**
|
|
821
|
+
* Check if file exists at path or remapped path
|
|
822
|
+
* Returns the original path if found (to preserve output naming)
|
|
823
|
+
*/
|
|
824
|
+
function findVFSFile(vfs: VirtualFS, originalPath: string, extensions: string[]): string | null {
|
|
825
|
+
for (const ext of extensions) {
|
|
826
|
+
const pathWithExt = originalPath + ext;
|
|
827
|
+
// First check original path — must be a file, not a directory
|
|
828
|
+
if (vfs.existsSync(pathWithExt)) {
|
|
829
|
+
try {
|
|
830
|
+
if (!vfs.statSync(pathWithExt).isDirectory()) {
|
|
831
|
+
return pathWithExt;
|
|
832
|
+
}
|
|
833
|
+
} catch {
|
|
834
|
+
return pathWithExt;
|
|
835
|
+
}
|
|
836
|
+
}
|
|
837
|
+
// Then try remapped path
|
|
838
|
+
const remapped = remapVFSPath(pathWithExt);
|
|
839
|
+
if (remapped !== pathWithExt && vfs.existsSync(remapped)) {
|
|
840
|
+
try {
|
|
841
|
+
if (!vfs.statSync(remapped).isDirectory()) {
|
|
842
|
+
return pathWithExt;
|
|
843
|
+
}
|
|
844
|
+
} catch {
|
|
845
|
+
return pathWithExt;
|
|
846
|
+
}
|
|
847
|
+
}
|
|
848
|
+
}
|
|
849
|
+
return null;
|
|
850
|
+
}
|
|
851
|
+
|
|
852
|
+
// ============================================================================
|
|
853
|
+
// VFS Plugin for esbuild
|
|
854
|
+
// ============================================================================
|
|
855
|
+
|
|
856
|
+
/**
|
|
857
|
+
* Create a VFS plugin for esbuild to read files from VirtualFS.
|
|
858
|
+
*
|
|
859
|
+
* This plugin enables esbuild to resolve and load files from the virtual file system,
|
|
860
|
+
* which is essential for browser-based bundling where we don't have access to the
|
|
861
|
+
* real file system.
|
|
862
|
+
*
|
|
863
|
+
* The plugin handles three types of imports:
|
|
864
|
+
* 1. Absolute paths (/project/src/file.ts)
|
|
865
|
+
* 2. Relative paths (./file.ts, ../file.ts)
|
|
866
|
+
* 3. Bare imports (convex/server, react)
|
|
867
|
+
*/
|
|
868
|
+
let __vfsPlatformNode = false;
|
|
869
|
+
/** A `paths` entry of a tsconfig, its targets made absolute. */
|
|
870
|
+
interface PathAlias {
|
|
871
|
+
exact?: string;
|
|
872
|
+
prefix?: string;
|
|
873
|
+
suffix?: string;
|
|
874
|
+
targets: string[];
|
|
875
|
+
}
|
|
876
|
+
|
|
877
|
+
/** As much of a tsconfig as the resolver reads. */
|
|
878
|
+
interface TsconfigJson {
|
|
879
|
+
extends?: string | string[];
|
|
880
|
+
compilerOptions?: { baseUrl?: string; paths?: Record<string, string[]> } & Record<string, unknown>;
|
|
881
|
+
[key: string]: unknown;
|
|
882
|
+
}
|
|
883
|
+
|
|
884
|
+
/**
|
|
885
|
+
* esbuild reads a `tsconfig` it is pointed at with its own filesystem, which
|
|
886
|
+
* in the browser is none: "not implemented on js". A build that names one, as
|
|
887
|
+
* `tsup` does for every TypeScript project, has the file read from the
|
|
888
|
+
* engine's filesystem and handed over as `tsconfigRaw`, which esbuild takes
|
|
889
|
+
* as text. The `paths` that file declares, `@/*` for `./src/*`, are how a
|
|
890
|
+
* project imports its own modules; esbuild applies them with its own
|
|
891
|
+
* resolver, which the filesystem plugin stands in front of, so the plugin
|
|
892
|
+
* applies them: an import that matches a pattern is looked for at each of its
|
|
893
|
+
* targets, from the file's `baseUrl` or its own directory.
|
|
894
|
+
*/
|
|
895
|
+
let __vfsPathAliases: PathAlias[] | null = null;
|
|
896
|
+
function __stripJsonComments(text: string): string {
|
|
897
|
+
let out = "";
|
|
898
|
+
let quote = false;
|
|
899
|
+
for (let index = 0; index < text.length; index += 1) {
|
|
900
|
+
const character = text[index];
|
|
901
|
+
if (quote) {
|
|
902
|
+
out += character;
|
|
903
|
+
if (character === "\\") { out += text[index + 1] ?? ""; index += 1; }
|
|
904
|
+
else if (character === "\"") quote = false;
|
|
905
|
+
continue;
|
|
906
|
+
}
|
|
907
|
+
if (character === "\"") { quote = true; out += character; continue; }
|
|
908
|
+
if (character === "/" && text[index + 1] === "/") { while (index < text.length && text[index] !== "\n") index += 1; out += "\n"; continue; }
|
|
909
|
+
if (character === "/" && text[index + 1] === "*") { const close = text.indexOf("*/", index + 2); index = close < 0 ? text.length : close + 1; continue; }
|
|
910
|
+
out += character;
|
|
911
|
+
}
|
|
912
|
+
return out.replace(/,(\s*[}\]])/g, "$1");
|
|
913
|
+
}
|
|
914
|
+
function __resolveTsconfigParent(directory: string, base: string): string | null {
|
|
915
|
+
const join = (root: string, relative: string): string => {
|
|
916
|
+
const parts = [];
|
|
917
|
+
for (const part of (relative.startsWith("/") ? relative : root + "/" + relative).split("/")) {
|
|
918
|
+
if (part === "..") parts.pop(); else if (part && part !== ".") parts.push(part);
|
|
919
|
+
}
|
|
920
|
+
return "/" + parts.join("/");
|
|
921
|
+
};
|
|
922
|
+
const file = (candidate: string): string | null => {
|
|
923
|
+
const isFile = (p: string) => { try { return globalVFS!.existsSync(p) && !globalVFS!.statSync(p).isDirectory(); } catch { return false; } };
|
|
924
|
+
if (isFile(candidate)) return candidate;
|
|
925
|
+
if (!candidate.endsWith(".json") && isFile(candidate + ".json")) return candidate + ".json";
|
|
926
|
+
// A package directory names its config in package.json, or carries tsconfig.json.
|
|
927
|
+
try {
|
|
928
|
+
const manifest = JSON.parse(globalVFS!.readFileSync(candidate + "/package.json", "utf8"));
|
|
929
|
+
if (typeof manifest.tsconfig === "string" && isFile(join(candidate, manifest.tsconfig))) return join(candidate, manifest.tsconfig);
|
|
930
|
+
} catch {}
|
|
931
|
+
if (isFile(candidate + "/tsconfig.json")) return candidate + "/tsconfig.json";
|
|
932
|
+
return null;
|
|
933
|
+
};
|
|
934
|
+
if (base.startsWith(".") || base.startsWith("/")) return file(join(directory, base));
|
|
935
|
+
let current = directory.replace(/\/$/, "") || "/";
|
|
936
|
+
for (;;) {
|
|
937
|
+
const found = file((current === "/" ? "" : current) + "/node_modules/" + base);
|
|
938
|
+
if (found) return found;
|
|
939
|
+
if (current === "/") return null;
|
|
940
|
+
current = current.slice(0, current.lastIndexOf("/")) || "/";
|
|
941
|
+
}
|
|
942
|
+
}
|
|
943
|
+
export function __flattenTsconfig(raw: string | TsconfigJson, directory: string, seen: Set<string> = new Set()): TsconfigJson {
|
|
944
|
+
const parsed = typeof raw === "string" ? JSON.parse(__stripJsonComments(raw)) : raw;
|
|
945
|
+
if (!parsed || typeof parsed !== "object") return parsed;
|
|
946
|
+
const resolve = (base: string, relative: string): string => {
|
|
947
|
+
const parts = [];
|
|
948
|
+
for (const part of (relative.startsWith("/") ? relative : base + "/" + relative).split("/")) {
|
|
949
|
+
if (part === "..") parts.pop(); else if (part && part !== ".") parts.push(part);
|
|
950
|
+
}
|
|
951
|
+
return "/" + parts.join("/");
|
|
952
|
+
};
|
|
953
|
+
let inherited: TsconfigJson = {};
|
|
954
|
+
// TypeScript takes one base or a list of them, applied in order; each is a
|
|
955
|
+
// relative or absolute path, or a package path found in node_modules on
|
|
956
|
+
// the way up from the config, as a monorepo's shared `tsconfig` package is.
|
|
957
|
+
const bases = Array.isArray(parsed.extends) ? parsed.extends : parsed.extends ? [parsed.extends] : [];
|
|
958
|
+
for (const base of bases) {
|
|
959
|
+
if (typeof base !== "string") throw new Error("Unsupported TypeScript config inheritance at " + directory + ": " + JSON.stringify(base));
|
|
960
|
+
const parent = __resolveTsconfigParent(directory, base);
|
|
961
|
+
// esbuild warns and builds on without a base it cannot find ("Cannot find
|
|
962
|
+
// base config file"), where TypeScript itself errors. A config that names
|
|
963
|
+
// a file a generator has yet to write is ordinary: SvelteKit's
|
|
964
|
+
// `tsconfig.json` extends `./.svelte-kit/tsconfig.json`, which
|
|
965
|
+
// `svelte-kit sync` writes when the dev server starts, so every fresh
|
|
966
|
+
// SvelteKit checkout has a missing base for as long as it takes Vite to
|
|
967
|
+
// load its own config. Throwing here killed `vite dev` before the plugin
|
|
968
|
+
// that writes the file could run.
|
|
969
|
+
if (parent === null) continue;
|
|
970
|
+
if (seen.has(parent) || seen.size >= 20) throw new Error("TypeScript config inheritance cycle at " + parent);
|
|
971
|
+
seen.add(parent);
|
|
972
|
+
const next = __flattenTsconfig(globalVFS!.readFileSync(parent, "utf8"), parent.slice(0,parent.lastIndexOf("/")) || "/", seen);
|
|
973
|
+
inherited = { ...inherited, ...next, compilerOptions: { ...inherited.compilerOptions, ...next.compilerOptions } };
|
|
974
|
+
}
|
|
975
|
+
const { extends: _extends, ...own } = parsed;
|
|
976
|
+
const compiler = own.compilerOptions || {};
|
|
977
|
+
const baseUrl = typeof compiler.baseUrl === "string" ? resolve(directory, compiler.baseUrl) : inherited.compilerOptions && inherited.compilerOptions.baseUrl;
|
|
978
|
+
return { ...inherited, ...own, compilerOptions: { ...inherited.compilerOptions, ...compiler, ...(baseUrl ? { baseUrl } : {}) } };
|
|
979
|
+
}
|
|
980
|
+
function __discoveredPathAliases(cwd: string): PathAlias[] | null {
|
|
981
|
+
if (!globalVFS) return null;
|
|
982
|
+
let directory = cwd.replace(/\/$/, "") || "/";
|
|
983
|
+
for (;;) {
|
|
984
|
+
const candidate = (directory === "/" ? "" : directory) + "/tsconfig.json";
|
|
985
|
+
try {
|
|
986
|
+
if (globalVFS.existsSync(candidate)) {
|
|
987
|
+
const text = globalVFS.readFileSync(candidate, "utf8");
|
|
988
|
+
const aliases = __pathAliasesOf(typeof text === "string" ? text : new TextDecoder().decode(text), directory === "" ? "/" : directory);
|
|
989
|
+
if (aliases) return aliases;
|
|
990
|
+
// A file that extends another may take its paths from there.
|
|
991
|
+
const parsed = JSON.parse(__stripJsonComments(String(text)));
|
|
992
|
+
for (const base of Array.isArray(parsed?.extends) ? parsed.extends : typeof parsed?.extends === "string" ? [parsed.extends] : []) {
|
|
993
|
+
const basePath = __resolveTsconfigParent(directory === "" ? "/" : directory, base);
|
|
994
|
+
if (basePath === null) continue;
|
|
995
|
+
const baseText = globalVFS.readFileSync(basePath, "utf8");
|
|
996
|
+
const inherited = __pathAliasesOf(typeof baseText === "string" ? baseText : new TextDecoder().decode(baseText), basePath.slice(0, basePath.lastIndexOf("/")) || "/");
|
|
997
|
+
if (inherited) return inherited;
|
|
998
|
+
}
|
|
999
|
+
return null;
|
|
1000
|
+
}
|
|
1001
|
+
} catch (error) {
|
|
1002
|
+
return null;
|
|
1003
|
+
}
|
|
1004
|
+
if (directory === "/" || directory === "") return null;
|
|
1005
|
+
directory = directory.slice(0, directory.lastIndexOf("/")) || "/";
|
|
1006
|
+
}
|
|
1007
|
+
}
|
|
1008
|
+
function __pathAliasesOf(tsconfigRaw: string | TsconfigJson | undefined, directory: string): PathAlias[] | null {
|
|
1009
|
+
if (!tsconfigRaw) return null;
|
|
1010
|
+
let parsed: TsconfigJson;
|
|
1011
|
+
try {
|
|
1012
|
+
parsed = typeof tsconfigRaw === "string"
|
|
1013
|
+
? JSON.parse(__stripJsonComments(tsconfigRaw))
|
|
1014
|
+
: tsconfigRaw;
|
|
1015
|
+
} catch {
|
|
1016
|
+
return null;
|
|
1017
|
+
}
|
|
1018
|
+
const compilerOptions = parsed && parsed.compilerOptions;
|
|
1019
|
+
if (!compilerOptions || !compilerOptions.paths || typeof compilerOptions.paths !== "object") return null;
|
|
1020
|
+
const join = (base: string, relative: string): string => {
|
|
1021
|
+
const parts = [];
|
|
1022
|
+
for (const part of (relative.startsWith("/") ? relative : base + "/" + relative).split("/")) {
|
|
1023
|
+
if (!part || part === ".") continue;
|
|
1024
|
+
if (part === "..") parts.pop();
|
|
1025
|
+
else parts.push(part);
|
|
1026
|
+
}
|
|
1027
|
+
return "/" + parts.join("/");
|
|
1028
|
+
};
|
|
1029
|
+
const baseUrl = typeof compilerOptions.baseUrl === "string" ? join(directory, compilerOptions.baseUrl) : directory;
|
|
1030
|
+
const aliases: PathAlias[] = [];
|
|
1031
|
+
for (const [pattern, targets] of Object.entries(compilerOptions.paths)) {
|
|
1032
|
+
if (!Array.isArray(targets)) continue;
|
|
1033
|
+
const star = pattern.indexOf("*");
|
|
1034
|
+
const resolved = targets.filter((target) => typeof target === "string").map((target) => join(baseUrl, target));
|
|
1035
|
+
if (resolved.length === 0) continue;
|
|
1036
|
+
if (star < 0) aliases.push({ exact: pattern, targets: resolved });
|
|
1037
|
+
else aliases.push({ prefix: pattern.slice(0, star), suffix: pattern.slice(star + 1), targets: resolved });
|
|
1038
|
+
}
|
|
1039
|
+
return aliases.length > 0 ? aliases : null;
|
|
1040
|
+
}
|
|
1041
|
+
/** A `sideEffects` glob as a regular expression, the way a bundler reads one. */
|
|
1042
|
+
function __browserRuntimeGlobToRegExp(pattern: string): RegExp {
|
|
1043
|
+
const escaped = pattern.replace(/^\.\//, "").replace(/[.+^$()|[\]\\{}]/g, "\\$&")
|
|
1044
|
+
.replace(/\*\*\//g, "\u0000").replace(/\*/g, "[^/]*").replace(/\?/g, "[^/]").replace(/\u0000/g, "(?:.*/)?");
|
|
1045
|
+
return new RegExp(pattern.includes("/") ? `^${escaped}$` : `(?:^|/)${escaped}$`);
|
|
1046
|
+
}
|
|
1047
|
+
|
|
1048
|
+
/** The package a specifier names: `@scope/name` or `name`, without a subpath. */
|
|
1049
|
+
function packageNameOf(specifier: string): string {
|
|
1050
|
+
const parts = specifier.split("/");
|
|
1051
|
+
return specifier.startsWith("@") ? parts.slice(0, 2).join("/") : parts[0]!;
|
|
1052
|
+
}
|
|
1053
|
+
|
|
1054
|
+
/**
|
|
1055
|
+
* The `neighbors` option: the packages being built beside this one. An import
|
|
1056
|
+
* of one is left external under the specifier it was written with, so whoever
|
|
1057
|
+
* asked for the build serves it its own way, and every specifier an import
|
|
1058
|
+
* reached is recorded for the result. A specifier in `self` is what this build
|
|
1059
|
+
* is of and stays inside it; so do `node:` builtins and anything already
|
|
1060
|
+
* carrying a namespace, which are not bare package names at all.
|
|
1061
|
+
*/
|
|
1062
|
+
function createNeighborsPlugin(neighbors: { names: string[]; self?: string[] }, seen: Set<string>): unknown {
|
|
1063
|
+
const names = new Set(neighbors.names);
|
|
1064
|
+
const self = new Set(neighbors.self ?? []);
|
|
1065
|
+
return {
|
|
1066
|
+
name: "neighbors",
|
|
1067
|
+
setup(build: unknown) {
|
|
1068
|
+
const b = build as {
|
|
1069
|
+
onResolve: (options: { filter: RegExp; namespace?: string }, callback: (args: { path: string; kind?: string; namespace?: string }) => unknown) => void;
|
|
1070
|
+
};
|
|
1071
|
+
// esbuild compiles a filter with Go's regexp engine, which has no
|
|
1072
|
+
// unicode flag: a `/u` here reaches it as `(?u)` and the whole build
|
|
1073
|
+
// dies with "filter is not a valid Go regular expression". The filter
|
|
1074
|
+
// is ASCII anyway -- a specifier that is neither relative nor absolute.
|
|
1075
|
+
b.onResolve({ filter: /^[^./]/ }, (args: { path: string; kind?: string; namespace?: string }) => {
|
|
1076
|
+
if (args.kind === "entry-point" || args.path.startsWith("node:") || args.path.includes(":")) return undefined;
|
|
1077
|
+
if (!names.has(packageNameOf(args.path)) || self.has(args.path)) return undefined;
|
|
1078
|
+
seen.add(args.path);
|
|
1079
|
+
return { path: args.path, external: true };
|
|
1080
|
+
});
|
|
1081
|
+
},
|
|
1082
|
+
};
|
|
1083
|
+
}
|
|
1084
|
+
|
|
1085
|
+
function createVFSPlugin(externals?: string[]): unknown {
|
|
1086
|
+
// The bundler's resolver said nothing about side effects, so a module it
|
|
1087
|
+
// resolved could never be dropped: a barrel that re-exports thousands of
|
|
1088
|
+
// modules bundled all of them however few were imported.
|
|
1089
|
+
//
|
|
1090
|
+
// What a package's manifest says of its files' side effects: false when it
|
|
1091
|
+
// declares none, undefined when it declares them or says nothing. A file
|
|
1092
|
+
// is the package's whose root is the longest known prefix of its path
|
|
1093
|
+
// with no node_modules between; the walk to a manifest happens once per
|
|
1094
|
+
// package, since every filesystem call here is a round trip to the store.
|
|
1095
|
+
const packageRoots: string[] = [];
|
|
1096
|
+
const sideEffectVerdicts = new Map<string, boolean | string[] | undefined>();
|
|
1097
|
+
function packageRootOf(filePath: string): string | null {
|
|
1098
|
+
for (const root of packageRoots) {
|
|
1099
|
+
if (filePath.startsWith(root + "/") && !filePath.slice(root.length + 1).includes("/node_modules/")) return root;
|
|
1100
|
+
}
|
|
1101
|
+
let directory = filePath.slice(0, filePath.lastIndexOf("/"));
|
|
1102
|
+
while (directory) {
|
|
1103
|
+
try {
|
|
1104
|
+
const manifestPath = directory + "/package.json";
|
|
1105
|
+
if (vfs.existsSync(manifestPath)) {
|
|
1106
|
+
// The bundler's filesystem answers in bytes; the engine's in text.
|
|
1107
|
+
const read = vfs.readFileSync(manifestPath, "utf8");
|
|
1108
|
+
const manifest = JSON.parse(typeof read === "string" ? read : new TextDecoder().decode(read));
|
|
1109
|
+
sideEffectVerdicts.set(directory, manifest.sideEffects);
|
|
1110
|
+
packageRoots.push(directory);
|
|
1111
|
+
packageRoots.sort((a, b) => b.length - a.length);
|
|
1112
|
+
return directory;
|
|
1113
|
+
}
|
|
1114
|
+
} catch {
|
|
1115
|
+
return null;
|
|
1116
|
+
}
|
|
1117
|
+
directory = directory.slice(0, directory.lastIndexOf("/"));
|
|
1118
|
+
}
|
|
1119
|
+
return null;
|
|
1120
|
+
}
|
|
1121
|
+
function sideEffectsOf(vfs3: VirtualFS, filePath: string): false | undefined {
|
|
1122
|
+
const root = packageRootOf(filePath);
|
|
1123
|
+
if (!root) return void 0;
|
|
1124
|
+
const sideEffects = sideEffectVerdicts.get(root);
|
|
1125
|
+
if (sideEffects === false) return false;
|
|
1126
|
+
if (Array.isArray(sideEffects)) {
|
|
1127
|
+
const relative = filePath.slice(root.length + 1);
|
|
1128
|
+
return sideEffects.some((entry) => typeof entry === "string" && __browserRuntimeGlobToRegExp(entry).test(relative)) ? void 0 : false;
|
|
1129
|
+
}
|
|
1130
|
+
return void 0;
|
|
1131
|
+
}
|
|
1132
|
+
function withSideEffects<T>(vfs3: VirtualFS, filePath: string, result: T): T {
|
|
1133
|
+
return sideEffectsOf(vfs3, filePath) === false ? { ...result, sideEffects: false } : result;
|
|
1134
|
+
}
|
|
1135
|
+
const __pathAliases = __vfsPathAliases;
|
|
1136
|
+
// Resolver callbacks outlive setup and may overlap another build.
|
|
1137
|
+
const __platformNode = __vfsPlatformNode;
|
|
1138
|
+
if (!globalVFS) {
|
|
1139
|
+
return null;
|
|
1140
|
+
}
|
|
1141
|
+
|
|
1142
|
+
const vfs = globalVFS;
|
|
1143
|
+
|
|
1144
|
+
return {
|
|
1145
|
+
name: 'vfs-loader',
|
|
1146
|
+
setup(build: unknown) {
|
|
1147
|
+
const b = build as {
|
|
1148
|
+
onResolve: (options: { filter: RegExp; namespace?: string }, callback: (args: { path: string; importer: string; kind: string }) => unknown) => void;
|
|
1149
|
+
onLoad: (options: { filter: RegExp; namespace?: string }, callback: (args: { path: string }) => unknown) => void;
|
|
1150
|
+
};
|
|
1151
|
+
|
|
1152
|
+
// A resolved path is the file's own. The shim once answered `.mjs` and
|
|
1153
|
+
// `.cjs` files under a `.js` name, so esbuild would infer the format of
|
|
1154
|
+
// a package the installer had rewritten from ESM to CJS; the installer
|
|
1155
|
+
// no longer rewrites, and a plugin of the build that reads the path
|
|
1156
|
+
// itself, Vite's config loader among them, found no such file.
|
|
1157
|
+
function vfsResolved(foundPath: string) {
|
|
1158
|
+
return withSideEffects(vfs, foundPath, { path: foundPath, pluginData: { fromVFS: true } });
|
|
1159
|
+
}
|
|
1160
|
+
|
|
1161
|
+
// Resolve file paths - handles both imports and entry points
|
|
1162
|
+
b.onResolve({ filter: /.*/ }, (args: { path: string; importer: string; kind?: string; resolveDir?: string }) => {
|
|
1163
|
+
const { path: importPath, importer } = args;
|
|
1164
|
+
|
|
1165
|
+
// Skip external modules (node_modules, bare imports)
|
|
1166
|
+
if (importPath.startsWith('node_modules/')) {
|
|
1167
|
+
return { external: true };
|
|
1168
|
+
}
|
|
1169
|
+
|
|
1170
|
+
const extensions = ['', '.ts', '.tsx', '.js', '.jsx', '.mjs', '.cjs', '.json'];
|
|
1171
|
+
|
|
1172
|
+
// An entry point that is not absolute is a path from the build's
|
|
1173
|
+
// working directory; the resolver read `src/index.ts` as a bare
|
|
1174
|
+
// package and marked it external, which an entry point cannot be.
|
|
1175
|
+
if (args.kind === "entry-point" && !importPath.startsWith("/") && !importPath.startsWith(".")) {
|
|
1176
|
+
const base = (args.resolveDir || "/").replace(/\/$/, "");
|
|
1177
|
+
const entryPath = findVFSFile(vfs, base + "/" + importPath, extensions);
|
|
1178
|
+
if (entryPath) return vfsResolved(entryPath);
|
|
1179
|
+
}
|
|
1180
|
+
|
|
1181
|
+
// Absolute paths - check if file exists in VFS (or remapped location)
|
|
1182
|
+
if (importPath.startsWith('/')) {
|
|
1183
|
+
const foundPath = findVFSFile(vfs, importPath, extensions);
|
|
1184
|
+
if (foundPath) {
|
|
1185
|
+
return vfsResolved(foundPath);
|
|
1186
|
+
}
|
|
1187
|
+
// File not found
|
|
1188
|
+
return { external: true };
|
|
1189
|
+
}
|
|
1190
|
+
|
|
1191
|
+
// Relative paths
|
|
1192
|
+
if (importPath.startsWith('.')) {
|
|
1193
|
+
let resolved = importPath;
|
|
1194
|
+
if (importer) {
|
|
1195
|
+
// Use realPath from pluginData if the importer was remapped from .mjs/.cjs
|
|
1196
|
+
const importerDir = importer.substring(0, importer.lastIndexOf('/'));
|
|
1197
|
+
resolved = importerDir + '/' + importPath;
|
|
1198
|
+
}
|
|
1199
|
+
// Normalize path
|
|
1200
|
+
const parts = resolved.split('/').filter(Boolean);
|
|
1201
|
+
const normalized: string[] = [];
|
|
1202
|
+
for (const part of parts) {
|
|
1203
|
+
if (part === '..') {
|
|
1204
|
+
normalized.pop();
|
|
1205
|
+
} else if (part !== '.') {
|
|
1206
|
+
normalized.push(part);
|
|
1207
|
+
}
|
|
1208
|
+
}
|
|
1209
|
+
resolved = '/' + normalized.join('/');
|
|
1210
|
+
|
|
1211
|
+
// Try to find the file with various extensions
|
|
1212
|
+
const foundPath = findVFSFile(vfs, resolved, extensions);
|
|
1213
|
+
if (foundPath) {
|
|
1214
|
+
return vfsResolved(foundPath);
|
|
1215
|
+
}
|
|
1216
|
+
|
|
1217
|
+
// Try index files
|
|
1218
|
+
for (const ext of ['.ts', '.tsx', '.js', '.jsx']) {
|
|
1219
|
+
const indexPath = resolved + '/index' + ext;
|
|
1220
|
+
const foundIndex = findVFSFile(vfs, indexPath, ['']);
|
|
1221
|
+
if (foundIndex) {
|
|
1222
|
+
return vfsResolved(foundIndex);
|
|
1223
|
+
}
|
|
1224
|
+
}
|
|
1225
|
+
}
|
|
1226
|
+
|
|
1227
|
+
// Bare imports (no ./ or ../ or /) - resolve from node_modules in VFS
|
|
1228
|
+
// See resolveNodeModuleImport() JSDoc for why we resolve from VFS instead of
|
|
1229
|
+
// marking as external (browser bundling, VFS isolation, consistent builds)
|
|
1230
|
+
|
|
1231
|
+
// A package's private `#` imports, resolved where its other imports
|
|
1232
|
+
// are. `#compiler/builders` is not a package, it is an entry in the
|
|
1233
|
+
// importing package's own `imports` map, and leaving it external left
|
|
1234
|
+
// every bundle of such a package with an import no browser can
|
|
1235
|
+
// resolve. The nearest manifest above the importer with an `imports`
|
|
1236
|
+
// map names the file, under the conditions a browser bundle takes.
|
|
1237
|
+
if (importPath.startsWith("#")) {
|
|
1238
|
+
const __conditions = (value: unknown): string | undefined => {
|
|
1239
|
+
if (typeof value === "string") return value;
|
|
1240
|
+
if (!value || typeof value !== "object") return void 0;
|
|
1241
|
+
for (const key of ["browser", "import", "module", "default"]) {
|
|
1242
|
+
if (key in value) {
|
|
1243
|
+
const found = __conditions((value as Record<string, unknown>)[key]);
|
|
1244
|
+
if (found) return found;
|
|
1245
|
+
}
|
|
1246
|
+
}
|
|
1247
|
+
return void 0;
|
|
1248
|
+
};
|
|
1249
|
+
let __directory = importer.slice(0, importer.lastIndexOf("/"));
|
|
1250
|
+
let __resolvedPrivate: ReturnType<typeof vfsResolved> | undefined;
|
|
1251
|
+
while (__directory && __resolvedPrivate === void 0) {
|
|
1252
|
+
const __manifestPath = __directory + "/package.json";
|
|
1253
|
+
if (vfs.existsSync(__manifestPath)) {
|
|
1254
|
+
let __imports: Record<string, unknown> | undefined;
|
|
1255
|
+
try {
|
|
1256
|
+
__imports = JSON.parse(vfs.readFileSync(__manifestPath, "utf8")).imports;
|
|
1257
|
+
} catch (error) {
|
|
1258
|
+
__imports = void 0;
|
|
1259
|
+
}
|
|
1260
|
+
if (__imports && typeof __imports === "object") {
|
|
1261
|
+
let __target = __conditions(__imports[importPath]);
|
|
1262
|
+
if (!__target) {
|
|
1263
|
+
for (const [pattern, value] of Object.entries(__imports)) {
|
|
1264
|
+
const star = pattern.indexOf("*");
|
|
1265
|
+
if (star < 0) continue;
|
|
1266
|
+
const prefix = pattern.slice(0, star);
|
|
1267
|
+
const suffix = pattern.slice(star + 1);
|
|
1268
|
+
if (!importPath.startsWith(prefix) || !importPath.endsWith(suffix)) continue;
|
|
1269
|
+
const found = __conditions(value);
|
|
1270
|
+
if (found) {
|
|
1271
|
+
__target = found.replace("*", importPath.slice(prefix.length, importPath.length - suffix.length));
|
|
1272
|
+
break;
|
|
1273
|
+
}
|
|
1274
|
+
}
|
|
1275
|
+
}
|
|
1276
|
+
if (__target && __target.startsWith("./")) {
|
|
1277
|
+
const __base = __directory + "/" + __target.slice(2);
|
|
1278
|
+
for (const extension of extensions) {
|
|
1279
|
+
const candidate = __base + extension;
|
|
1280
|
+
if (vfs.existsSync(candidate) && !vfs.statSync(candidate).isDirectory()) {
|
|
1281
|
+
__resolvedPrivate = vfsResolved(candidate);
|
|
1282
|
+
break;
|
|
1283
|
+
}
|
|
1284
|
+
}
|
|
1285
|
+
}
|
|
1286
|
+
}
|
|
1287
|
+
}
|
|
1288
|
+
__directory = __directory.slice(0, __directory.lastIndexOf("/"));
|
|
1289
|
+
}
|
|
1290
|
+
if (__resolvedPrivate) return __resolvedPrivate;
|
|
1291
|
+
}
|
|
1292
|
+
if (__pathAliases) {
|
|
1293
|
+
for (const alias of __pathAliases) {
|
|
1294
|
+
const rest = alias.prefix !== void 0
|
|
1295
|
+
? (importPath.startsWith(alias.prefix) && importPath.endsWith(alias.suffix!) && importPath.length >= alias.prefix.length + alias.suffix!.length ? importPath.slice(alias.prefix.length, importPath.length - alias.suffix!.length) : void 0)
|
|
1296
|
+
: (importPath === alias.exact ? "" : void 0);
|
|
1297
|
+
if (rest === void 0) continue;
|
|
1298
|
+
for (const target of alias.targets) {
|
|
1299
|
+
const candidate = target.includes("*") ? target.replace("*", rest) : target;
|
|
1300
|
+
const found = findVFSFile(vfs, candidate, extensions);
|
|
1301
|
+
if (found) return vfsResolved(found);
|
|
1302
|
+
for (const ext2 of [".ts", ".tsx", ".js", ".jsx", ".mjs", ".cjs"]) {
|
|
1303
|
+
const index = findVFSFile(vfs, candidate + "/index" + ext2, [""]);
|
|
1304
|
+
if (index) return vfsResolved(index);
|
|
1305
|
+
}
|
|
1306
|
+
}
|
|
1307
|
+
}
|
|
1308
|
+
}
|
|
1309
|
+
// Check externals list first — packages like react must stay as ESM imports
|
|
1310
|
+
if (externals && externals.some(ext => importPath === ext || importPath.startsWith(ext + '/'))) {
|
|
1311
|
+
return { external: true };
|
|
1312
|
+
}
|
|
1313
|
+
|
|
1314
|
+
const resolution = resolveNodeModuleImport(vfs, importPath, extensions, importer);
|
|
1315
|
+
if (resolution) {
|
|
1316
|
+
return resolution.path ? withSideEffects(vfs, resolution.path, resolution) : resolution;
|
|
1317
|
+
}
|
|
1318
|
+
|
|
1319
|
+
// Node.js builtins that aren't in VFS node_modules should be
|
|
1320
|
+
// stubbed as empty modules rather than externalized. When externalized,
|
|
1321
|
+
// patchExternalRequires() converts them to bare ESM imports that the
|
|
1322
|
+
// browser can't resolve. An empty stub is safe because these builtins
|
|
1323
|
+
// are typically only used in server-only code paths (e.g., @vercel/oidc).
|
|
1324
|
+
const bareModule = importPath.replace(/^node:/, '');
|
|
1325
|
+
// A name the host stands in for resolves to the host's file here as
|
|
1326
|
+
// it does for require, so a config the bundler inlines gets the
|
|
1327
|
+
// stand-in. The table is the host's (`globalThis.__browserRuntimeStandInPaths`,
|
|
1328
|
+
// package name -> file); the engine names no package.
|
|
1329
|
+
const __standInPaths = (globalThis as Record<string, unknown>).__browserRuntimeStandInPaths as Record<string, string> | undefined;
|
|
1330
|
+
if (__standInPaths && Object.prototype.hasOwnProperty.call(__standInPaths, bareModule) && vfs.existsSync(__standInPaths[bareModule])) {
|
|
1331
|
+
return vfsResolved(__standInPaths[bareModule]);
|
|
1332
|
+
}
|
|
1333
|
+
if (NODE_BUILTINS.has(bareModule)) {
|
|
1334
|
+
// tsup's server bundle carried `path` as `{}` and fell over its
|
|
1335
|
+
// first `path.resolve`: a build for Node keeps its builtins
|
|
1336
|
+
// external, to be required where it runs.
|
|
1337
|
+
if (__platformNode) return { external: true };
|
|
1338
|
+
return { path: `/__node_stub__/${bareModule}`, namespace: 'node-stub' };
|
|
1339
|
+
}
|
|
1340
|
+
|
|
1341
|
+
// A name the tree does not answer is put to the module stand-ins before
|
|
1342
|
+
// it is external: a registered stand-in may answer with a module it
|
|
1343
|
+
// computes from the project, what a generator would have written. The
|
|
1344
|
+
// registry is globalThis.__browserRuntimeModuleStandIns, installed by
|
|
1345
|
+
// the toolchain; the runtime's two resolvers ask it the same way.
|
|
1346
|
+
const __standIns = (globalThis as Record<string, unknown>).__browserRuntimeModuleStandIns as { resolve: (id: string, from: string) => string | null } | undefined;
|
|
1347
|
+
const __answered = __standIns && importer
|
|
1348
|
+
? __standIns.resolve(importPath, importer.slice(0, importer.lastIndexOf('/')) || '/') : null;
|
|
1349
|
+
if (__answered) return vfsResolved(__answered);
|
|
1350
|
+
// Could not resolve from node_modules, treat as external
|
|
1351
|
+
return { external: true };
|
|
1352
|
+
});
|
|
1353
|
+
|
|
1354
|
+
// Load empty stubs for Node.js builtins not available in VFS
|
|
1355
|
+
b.onLoad({ filter: /.*/, namespace: 'node-stub' }, () => {
|
|
1356
|
+
return { contents: 'module.exports = {};', loader: 'js' as const };
|
|
1357
|
+
});
|
|
1358
|
+
|
|
1359
|
+
// Load file contents from VFS
|
|
1360
|
+
// Apply path remapping when reading to find the actual file
|
|
1361
|
+
// A preceding plugin can resolve a real file without this resolver's
|
|
1362
|
+
// private pluginData; Vite's dependency optimizer does exactly that.
|
|
1363
|
+
// The fallback loader must read those files too: esbuild-wasm has no OS disk.
|
|
1364
|
+
b.onLoad({ filter: /^\/.*/, namespace: 'file' }, (args: { path: string; pluginData?: { fromVFS?: boolean; realPath?: string } }) => {
|
|
1365
|
+
if (!args.pluginData?.fromVFS && !vfs.existsSync(args.path)) return null;
|
|
1366
|
+
try {
|
|
1367
|
+
// Use realPath if available (set when .mjs/.cjs was normalized to .js)
|
|
1368
|
+
const vfsPath = args.pluginData?.realPath || args.path;
|
|
1369
|
+
let contents: string;
|
|
1370
|
+
const remappedPath = remapVFSPath(vfsPath);
|
|
1371
|
+
|
|
1372
|
+
if (vfs.existsSync(vfsPath)) {
|
|
1373
|
+
contents = vfs.readFileSync(vfsPath, 'utf8');
|
|
1374
|
+
} else if (remappedPath !== vfsPath && vfs.existsSync(remappedPath)) {
|
|
1375
|
+
contents = vfs.readFileSync(remappedPath, 'utf8');
|
|
1376
|
+
} else {
|
|
1377
|
+
throw new Error(`File not found: ${vfsPath} (tried ${remappedPath})`);
|
|
1378
|
+
}
|
|
1379
|
+
|
|
1380
|
+
const ext = args.path.substring(args.path.lastIndexOf('.'));
|
|
1381
|
+
let loader: 'ts' | 'tsx' | 'js' | 'jsx' | 'json' | 'css' = 'ts';
|
|
1382
|
+
if (ext === '.tsx') loader = 'tsx';
|
|
1383
|
+
else if (ext === '.js' || ext === '.mjs' || ext === '.cjs') loader = 'js';
|
|
1384
|
+
else if (ext === '.jsx') loader = 'jsx';
|
|
1385
|
+
else if (ext === '.json') loader = 'json';
|
|
1386
|
+
// A file that is not a module, imported as one: a stylesheet reaching
|
|
1387
|
+
// the bundler as TypeScript failed the whole module graph.
|
|
1388
|
+
else if (ext === '.css') loader = 'css';
|
|
1389
|
+
|
|
1390
|
+
return { contents, loader };
|
|
1391
|
+
} catch (err) {
|
|
1392
|
+
return { errors: [{ text: `Failed to load ${args.path}: ${err}` }] };
|
|
1393
|
+
}
|
|
1394
|
+
});
|
|
1395
|
+
},
|
|
1396
|
+
};
|
|
1397
|
+
}
|
|
1398
|
+
|
|
1399
|
+
// ============================================================================
|
|
1400
|
+
// Build API
|
|
1401
|
+
// ============================================================================
|
|
1402
|
+
|
|
1403
|
+
/**
|
|
1404
|
+
* Build/bundle code (limited support in browser)
|
|
1405
|
+
*/
|
|
1406
|
+
export async function build(options: BuildOptions): Promise<BuildResult> {
|
|
1407
|
+
// The shim stands in for whatever esbuild a project pinned, and answers in
|
|
1408
|
+
// the option vocabulary of the esbuild it runs. tsup 6 speaks esbuild
|
|
1409
|
+
// 0.14's: `incremental` and `watch` on a build, which esbuild 0.17 removed
|
|
1410
|
+
// and 0.20 refuses as invalid options, so `tsup` died on the first library
|
|
1411
|
+
// it built. Both name a build held for rebuilding, which the shim does not
|
|
1412
|
+
// hold; a single build is what they get, as a context's `rebuild` is.
|
|
1413
|
+
if (options && ("incremental" in options || "watch" in options)) {
|
|
1414
|
+
const { incremental: _incremental, watch: _watch, ...accepted } = options as BuildOptions & { incremental?: unknown; watch?: unknown };
|
|
1415
|
+
options = accepted;
|
|
1416
|
+
}
|
|
1417
|
+
const __heldWork = heldWork();
|
|
1418
|
+
__heldWork.count += 1;
|
|
1419
|
+
try { return await __buildHeld(options); } finally { __heldWork.count -= 1; }
|
|
1420
|
+
}
|
|
1421
|
+
async function __buildHeld(options: BuildOptions): Promise<BuildResult> {
|
|
1422
|
+
if (!esbuildInstance) {
|
|
1423
|
+
await initialize();
|
|
1424
|
+
}
|
|
1425
|
+
|
|
1426
|
+
if (!esbuildInstance) {
|
|
1427
|
+
throw new Error('esbuild not initialized');
|
|
1428
|
+
}
|
|
1429
|
+
|
|
1430
|
+
// Add VFS plugin if VFS is available
|
|
1431
|
+
__vfsPlatformNode = options.platform === "node";
|
|
1432
|
+
const __cwd = options.absWorkingDir || (typeof globalThis !== "undefined" && globalThis.process && typeof globalThis.process.cwd === "function" ? globalThis.process.cwd() : "/");
|
|
1433
|
+
let __tsconfigDirectory = __cwd;
|
|
1434
|
+
if (typeof options.tsconfig === "string" && globalVFS && options.tsconfigRaw === void 0) {
|
|
1435
|
+
const tsconfigPath = options.tsconfig.startsWith("/") ? options.tsconfig : (__cwd.endsWith("/") ? __cwd : __cwd + "/") + options.tsconfig;
|
|
1436
|
+
try {
|
|
1437
|
+
const { tsconfig: _tsconfig, ...withoutPath } = options;
|
|
1438
|
+
options = { ...withoutPath, tsconfigRaw: globalVFS.readFileSync(tsconfigPath, "utf8") };
|
|
1439
|
+
__tsconfigDirectory = tsconfigPath.slice(0, tsconfigPath.lastIndexOf("/")) || "/";
|
|
1440
|
+
} catch {
|
|
1441
|
+
}
|
|
1442
|
+
}
|
|
1443
|
+
if (options.tsconfigRaw !== void 0) options = { ...options, tsconfigRaw: __flattenTsconfig(options.tsconfigRaw, __tsconfigDirectory) };
|
|
1444
|
+
// A build names where a workspace member's sources are, `workspacePaths`,
|
|
1445
|
+
// as tsconfig paths with absolute targets; they join the config's own
|
|
1446
|
+
// paths and travel with the build wherever its resolver runs, since
|
|
1447
|
+
// the bundler worker sees neither the engine's links nor its globals.
|
|
1448
|
+
if (options.workspacePaths && typeof options.workspacePaths === "object") {
|
|
1449
|
+
const { workspacePaths: __workspacePaths, ...__rest } = options;
|
|
1450
|
+
const __raw = __rest.tsconfigRaw === void 0 ? {} : typeof __rest.tsconfigRaw === "string" ? JSON.parse(__stripJsonComments(__rest.tsconfigRaw)) : __rest.tsconfigRaw;
|
|
1451
|
+
const __compiler = { ...(__raw && __raw.compilerOptions) };
|
|
1452
|
+
__compiler.paths = { ...(__compiler.paths || {}), ...__workspacePaths };
|
|
1453
|
+
if (typeof __compiler.baseUrl !== "string") __compiler.baseUrl = __tsconfigDirectory;
|
|
1454
|
+
options = { ...__rest, tsconfigRaw: { ...__raw, compilerOptions: __compiler } };
|
|
1455
|
+
}
|
|
1456
|
+
// A bundler that read the tsconfig itself hands over what it kept of it,
|
|
1457
|
+
// often without the paths; esbuild would then find the file on disk on
|
|
1458
|
+
// its own, which the browser has none of, so the file is found here.
|
|
1459
|
+
__vfsPathAliases = __pathAliasesOf(options.tsconfigRaw, __tsconfigDirectory) || __discoveredPathAliases(__cwd);
|
|
1460
|
+
const plugins = [...(options.plugins || [])];
|
|
1461
|
+
// A build of one package among many says which of the others are being
|
|
1462
|
+
// built beside it. esbuild has no such option and refused the whole build
|
|
1463
|
+
// when it was handed one -- "Invalid option in build() call" -- so a
|
|
1464
|
+
// substrate realm that ran its package builds here, rather than at a host
|
|
1465
|
+
// that consumed the option first, could not build a package at all. The
|
|
1466
|
+
// option is the shim's, like `workspacePaths`: it is taken off before
|
|
1467
|
+
// esbuild sees the options and answered here, so a build means the same
|
|
1468
|
+
// thing whether it runs in this realm or at a host.
|
|
1469
|
+
let neighborsSeen: Set<string> | undefined;
|
|
1470
|
+
if (options.neighbors && typeof options.neighbors === "object" && !currentHost?.neighbors) {
|
|
1471
|
+
const { neighbors: __neighbors, ...__rest } = options;
|
|
1472
|
+
options = __rest;
|
|
1473
|
+
neighborsSeen = new Set<string>();
|
|
1474
|
+
plugins.push(createNeighborsPlugin(__neighbors, neighborsSeen));
|
|
1475
|
+
}
|
|
1476
|
+
const vfsPlugin = createVFSPlugin(options.external);
|
|
1477
|
+
if (vfsPlugin) {
|
|
1478
|
+
plugins.push(vfsPlugin);
|
|
1479
|
+
}
|
|
1480
|
+
|
|
1481
|
+
// Resolve entry points to absolute paths.
|
|
1482
|
+
// Path remapping (if any) happens in the VFS plugin's onLoad handler instead,
|
|
1483
|
+
// preserving the original paths for esbuild's output file naming.
|
|
1484
|
+
let entryPoints = options.entryPoints;
|
|
1485
|
+
// Only the array form is rewritten here: esbuild also takes the named
|
|
1486
|
+
// multi-entry form, `{ out: "in.ts" }`, which a browser build uses and
|
|
1487
|
+
// which this mapping would otherwise destroy.
|
|
1488
|
+
if (Array.isArray(entryPoints) && globalVFS) {
|
|
1489
|
+
const absWorkingDir = options.absWorkingDir || (typeof globalThis !== 'undefined' && globalThis.process && typeof globalThis.process.cwd === 'function' ? globalThis.process.cwd() : '/');
|
|
1490
|
+
entryPoints = entryPoints.map(ep => {
|
|
1491
|
+
// Handle paths that came from previous builds with vfs: namespace prefix
|
|
1492
|
+
if (ep.includes('vfs:')) {
|
|
1493
|
+
const vfsIndex = ep.indexOf('vfs:');
|
|
1494
|
+
ep = ep.substring(vfsIndex + 4);
|
|
1495
|
+
}
|
|
1496
|
+
|
|
1497
|
+
// If already absolute, use as-is
|
|
1498
|
+
if (ep.startsWith('/')) {
|
|
1499
|
+
return ep;
|
|
1500
|
+
}
|
|
1501
|
+
|
|
1502
|
+
// A build names its entry the way a project does, `src/index.ts`,
|
|
1503
|
+
// relative to the working directory with no `./`. esbuild reads an
|
|
1504
|
+
// entry as a file path and makes it absolute before any plugin sees
|
|
1505
|
+
// it; a build's own plugin, tsup's for what is external, would
|
|
1506
|
+
// otherwise take `src/index.ts` for a package. A bare entry that is no
|
|
1507
|
+
// file of the project — a package name Vite's optimizer hands its own
|
|
1508
|
+
// plugin to resolve — stays bare.
|
|
1509
|
+
if (!ep.startsWith(".")) {
|
|
1510
|
+
const base = absWorkingDir.endsWith("/") ? absWorkingDir.slice(0, -1) : absWorkingDir;
|
|
1511
|
+
const candidate = base + "/" + ep;
|
|
1512
|
+
let found = false;
|
|
1513
|
+
try { found = globalVFS!.existsSync(candidate); } catch {}
|
|
1514
|
+
if (found) return candidate;
|
|
1515
|
+
}
|
|
1516
|
+
|
|
1517
|
+
if (ep.startsWith('./')) {
|
|
1518
|
+
// Join with absWorkingDir but DO NOT remap paths
|
|
1519
|
+
const base = absWorkingDir.endsWith('/') ? absWorkingDir.slice(0, -1) : absWorkingDir;
|
|
1520
|
+
const relative = ep.slice(2);
|
|
1521
|
+
const resolved = base + '/' + relative;
|
|
1522
|
+
return resolved;
|
|
1523
|
+
}
|
|
1524
|
+
if (ep.startsWith('../')) {
|
|
1525
|
+
const base = absWorkingDir.endsWith('/') ? absWorkingDir.slice(0, -1) : absWorkingDir;
|
|
1526
|
+
const parts = base.split('/').filter(Boolean);
|
|
1527
|
+
parts.pop();
|
|
1528
|
+
const relative = ep.slice(3);
|
|
1529
|
+
const resolved = '/' + parts.join('/') + '/' + relative;
|
|
1530
|
+
return resolved;
|
|
1531
|
+
}
|
|
1532
|
+
return ep;
|
|
1533
|
+
});
|
|
1534
|
+
}
|
|
1535
|
+
|
|
1536
|
+
// In browser, we need write: false to get outputFiles
|
|
1537
|
+
// Pass absWorkingDir so metafile paths are relative to the correct directory
|
|
1538
|
+
const resolvedAbsWorkingDir = options.absWorkingDir || (typeof globalThis !== 'undefined' && globalThis.process && typeof globalThis.process.cwd === 'function' ? globalThis.process.cwd() : '/');
|
|
1539
|
+
const __outputFilesystem = globalVFS;
|
|
1540
|
+
const result = await esbuildInstance.build({
|
|
1541
|
+
...options,
|
|
1542
|
+
entryPoints,
|
|
1543
|
+
plugins,
|
|
1544
|
+
write: false,
|
|
1545
|
+
absWorkingDir: resolvedAbsWorkingDir,
|
|
1546
|
+
}) as BuildResult;
|
|
1547
|
+
|
|
1548
|
+
if (neighborsSeen) result.neighbors = [...neighborsSeen].sort();
|
|
1549
|
+
// Strip 'vfs:' namespace prefix from all output paths.
|
|
1550
|
+
// esbuild-wasm may prefix paths with the plugin namespace; strip it everywhere.
|
|
1551
|
+
if (result.outputFiles) {
|
|
1552
|
+
for (const file of result.outputFiles) {
|
|
1553
|
+
if (file.path.includes('vfs:')) {
|
|
1554
|
+
file.path = file.path.replace(/vfs:/g, '');
|
|
1555
|
+
}
|
|
1556
|
+
}
|
|
1557
|
+
}
|
|
1558
|
+
// esbuild-wasm cannot write to an OS disk. Honor the Node API's output
|
|
1559
|
+
// files here, including its default write=true when an output is named.
|
|
1560
|
+
if (options.write !== false && (options.outdir || options.outfile)) {
|
|
1561
|
+
if (!__outputFilesystem) throw new Error("esbuild has no filesystem for its output.");
|
|
1562
|
+
for (const file of result.outputFiles || []) {
|
|
1563
|
+
const parent = file.path.slice(0, file.path.lastIndexOf("/")) || "/";
|
|
1564
|
+
__outputFilesystem.mkdirSync(parent, { recursive: true });
|
|
1565
|
+
__outputFilesystem.writeFileSync(file.path, file.contents ?? file.text);
|
|
1566
|
+
}
|
|
1567
|
+
}
|
|
1568
|
+
if (result.metafile) {
|
|
1569
|
+
const meta = result.metafile as { inputs?: Record<string, unknown>; outputs?: Record<string, unknown> };
|
|
1570
|
+
for (const key of ['inputs', 'outputs'] as const) {
|
|
1571
|
+
const obj = meta[key];
|
|
1572
|
+
if (obj) {
|
|
1573
|
+
for (const k of Object.keys(obj)) {
|
|
1574
|
+
if (k.includes('vfs:')) {
|
|
1575
|
+
obj[k.replace(/vfs:/g, '')] = obj[k];
|
|
1576
|
+
delete obj[k];
|
|
1577
|
+
}
|
|
1578
|
+
}
|
|
1579
|
+
}
|
|
1580
|
+
}
|
|
1581
|
+
}
|
|
1582
|
+
|
|
1583
|
+
return result;
|
|
1584
|
+
}
|
|
1585
|
+
|
|
1586
|
+
/**
|
|
1587
|
+
* Build synchronously (not supported in browser, throws error)
|
|
1588
|
+
*/
|
|
1589
|
+
export function buildSync(_options: BuildOptions): BuildResult {
|
|
1590
|
+
throw new Error('buildSync is not available in browser. Use build() instead.');
|
|
1591
|
+
}
|
|
1592
|
+
|
|
1593
|
+
/**
|
|
1594
|
+
* Get the esbuild version
|
|
1595
|
+
*/
|
|
1596
|
+
export function version(): string {
|
|
1597
|
+
return '0.20.0'; // Version of esbuild-wasm we're using
|
|
1598
|
+
}
|
|
1599
|
+
|
|
1600
|
+
// A build that named an output wrote nothing and Vite's own build, which
|
|
1601
|
+
// reads what esbuild wrote, saw an empty directory; `tsup --watch` asked for
|
|
1602
|
+
// a context and the dev server answered 500. A context is a build held for
|
|
1603
|
+
// rebuilding: each `rebuild` runs the shim's build with the context's
|
|
1604
|
+
// options, `watch` and `serve` are nothing to hold in the browser, and
|
|
1605
|
+
// `dispose` releases it.
|
|
1606
|
+
export async function context(options: BuildOptions): Promise<unknown> {
|
|
1607
|
+
let disposed = false;
|
|
1608
|
+
return {
|
|
1609
|
+
rebuild: () => {
|
|
1610
|
+
if (disposed) return Promise.reject(new Error("The esbuild context was disposed."));
|
|
1611
|
+
return build(options);
|
|
1612
|
+
},
|
|
1613
|
+
watch: async () => {},
|
|
1614
|
+
serve: async () => ({ host: "127.0.0.1", port: 0, hosts: ["127.0.0.1"] }),
|
|
1615
|
+
cancel: async () => {},
|
|
1616
|
+
dispose: async () => { disposed = true; },
|
|
1617
|
+
};
|
|
1618
|
+
}
|
|
1619
|
+
|
|
1620
|
+
// Default export matching esbuild's API
|
|
1621
|
+
export default {
|
|
1622
|
+
initialize,
|
|
1623
|
+
isInitialized,
|
|
1624
|
+
transform,
|
|
1625
|
+
transformSync,
|
|
1626
|
+
transformToCommonJS,
|
|
1627
|
+
build,
|
|
1628
|
+
buildSync,
|
|
1629
|
+
context,
|
|
1630
|
+
stop,
|
|
1631
|
+
version,
|
|
1632
|
+
setWasmURL,
|
|
1633
|
+
setVFS,
|
|
1634
|
+
setModuleURL,
|
|
1635
|
+
useHost,
|
|
1636
|
+
formatMessages,
|
|
1637
|
+
analyzeMetafile,
|
|
1638
|
+
};
|