almostnode 0.1.0
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 +21 -0
- package/README.md +731 -0
- package/dist/__sw__.js +394 -0
- package/dist/ai-chatbot-demo-entry.d.ts +6 -0
- package/dist/ai-chatbot-demo-entry.d.ts.map +1 -0
- package/dist/ai-chatbot-demo.d.ts +42 -0
- package/dist/ai-chatbot-demo.d.ts.map +1 -0
- package/dist/assets/runtime-worker-D9x_Ddwz.js +60543 -0
- package/dist/assets/runtime-worker-D9x_Ddwz.js.map +1 -0
- package/dist/convex-app-demo-entry.d.ts +6 -0
- package/dist/convex-app-demo-entry.d.ts.map +1 -0
- package/dist/convex-app-demo.d.ts +68 -0
- package/dist/convex-app-demo.d.ts.map +1 -0
- package/dist/cors-proxy.d.ts +46 -0
- package/dist/cors-proxy.d.ts.map +1 -0
- package/dist/create-runtime.d.ts +42 -0
- package/dist/create-runtime.d.ts.map +1 -0
- package/dist/demo.d.ts +6 -0
- package/dist/demo.d.ts.map +1 -0
- package/dist/dev-server.d.ts +97 -0
- package/dist/dev-server.d.ts.map +1 -0
- package/dist/frameworks/next-dev-server.d.ts +202 -0
- package/dist/frameworks/next-dev-server.d.ts.map +1 -0
- package/dist/frameworks/vite-dev-server.d.ts +85 -0
- package/dist/frameworks/vite-dev-server.d.ts.map +1 -0
- package/dist/index.cjs +14965 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.ts +71 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.mjs +14867 -0
- package/dist/index.mjs.map +1 -0
- package/dist/next-demo.d.ts +49 -0
- package/dist/next-demo.d.ts.map +1 -0
- package/dist/npm/index.d.ts +71 -0
- package/dist/npm/index.d.ts.map +1 -0
- package/dist/npm/registry.d.ts +66 -0
- package/dist/npm/registry.d.ts.map +1 -0
- package/dist/npm/resolver.d.ts +52 -0
- package/dist/npm/resolver.d.ts.map +1 -0
- package/dist/npm/tarball.d.ts +29 -0
- package/dist/npm/tarball.d.ts.map +1 -0
- package/dist/runtime-interface.d.ts +90 -0
- package/dist/runtime-interface.d.ts.map +1 -0
- package/dist/runtime.d.ts +103 -0
- package/dist/runtime.d.ts.map +1 -0
- package/dist/sandbox-helpers.d.ts +43 -0
- package/dist/sandbox-helpers.d.ts.map +1 -0
- package/dist/sandbox-runtime.d.ts +65 -0
- package/dist/sandbox-runtime.d.ts.map +1 -0
- package/dist/server-bridge.d.ts +89 -0
- package/dist/server-bridge.d.ts.map +1 -0
- package/dist/shims/assert.d.ts +51 -0
- package/dist/shims/assert.d.ts.map +1 -0
- package/dist/shims/async_hooks.d.ts +37 -0
- package/dist/shims/async_hooks.d.ts.map +1 -0
- package/dist/shims/buffer.d.ts +20 -0
- package/dist/shims/buffer.d.ts.map +1 -0
- package/dist/shims/child_process-browser.d.ts +92 -0
- package/dist/shims/child_process-browser.d.ts.map +1 -0
- package/dist/shims/child_process.d.ts +93 -0
- package/dist/shims/child_process.d.ts.map +1 -0
- package/dist/shims/chokidar.d.ts +55 -0
- package/dist/shims/chokidar.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/crypto.d.ts +122 -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/diagnostics_channel.d.ts +80 -0
- package/dist/shims/diagnostics_channel.d.ts.map +1 -0
- package/dist/shims/dns.d.ts +87 -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 +105 -0
- package/dist/shims/esbuild.d.ts.map +1 -0
- package/dist/shims/events.d.ts +37 -0
- package/dist/shims/events.d.ts.map +1 -0
- package/dist/shims/fs.d.ts +115 -0
- package/dist/shims/fs.d.ts.map +1 -0
- package/dist/shims/fsevents.d.ts +67 -0
- package/dist/shims/fsevents.d.ts.map +1 -0
- package/dist/shims/http.d.ts +217 -0
- package/dist/shims/http.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/https.d.ts +36 -0
- package/dist/shims/https.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/net.d.ts +100 -0
- package/dist/shims/net.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 +72 -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 +93 -0
- package/dist/shims/process.d.ts.map +1 -0
- package/dist/shims/querystring.d.ts +23 -0
- package/dist/shims/querystring.d.ts.map +1 -0
- package/dist/shims/readdirp.d.ts +52 -0
- package/dist/shims/readdirp.d.ts.map +1 -0
- package/dist/shims/readline.d.ts +62 -0
- package/dist/shims/readline.d.ts.map +1 -0
- package/dist/shims/rollup.d.ts +34 -0
- package/dist/shims/rollup.d.ts.map +1 -0
- package/dist/shims/sentry.d.ts +163 -0
- package/dist/shims/sentry.d.ts.map +1 -0
- package/dist/shims/stream.d.ts +181 -0
- package/dist/shims/stream.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/tty.d.ts +30 -0
- package/dist/shims/tty.d.ts.map +1 -0
- package/dist/shims/url.d.ts +64 -0
- package/dist/shims/url.d.ts.map +1 -0
- package/dist/shims/util.d.ts +106 -0
- package/dist/shims/util.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 +45 -0
- package/dist/shims/vm.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/ws.d.ts +66 -0
- package/dist/shims/ws.d.ts.map +1 -0
- package/dist/shims/zlib.d.ts +161 -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/virtual-fs.d.ts +226 -0
- package/dist/virtual-fs.d.ts.map +1 -0
- package/dist/vite-demo.d.ts +35 -0
- package/dist/vite-demo.d.ts.map +1 -0
- package/dist/vite-sw.js +132 -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 +85 -0
- package/src/ai-chatbot-demo-entry.ts +244 -0
- package/src/ai-chatbot-demo.ts +509 -0
- package/src/convex-app-demo-entry.ts +1107 -0
- package/src/convex-app-demo.ts +1316 -0
- package/src/cors-proxy.ts +81 -0
- package/src/create-runtime.ts +147 -0
- package/src/demo.ts +304 -0
- package/src/dev-server.ts +274 -0
- package/src/frameworks/next-dev-server.ts +2224 -0
- package/src/frameworks/vite-dev-server.ts +702 -0
- package/src/index.ts +101 -0
- package/src/next-demo.ts +1784 -0
- package/src/npm/index.ts +347 -0
- package/src/npm/registry.ts +152 -0
- package/src/npm/resolver.ts +385 -0
- package/src/npm/tarball.ts +209 -0
- package/src/runtime-interface.ts +103 -0
- package/src/runtime.ts +1046 -0
- package/src/sandbox-helpers.ts +173 -0
- package/src/sandbox-runtime.ts +252 -0
- package/src/server-bridge.ts +426 -0
- package/src/shims/assert.ts +664 -0
- package/src/shims/async_hooks.ts +86 -0
- package/src/shims/buffer.ts +75 -0
- package/src/shims/child_process-browser.ts +217 -0
- package/src/shims/child_process.ts +463 -0
- package/src/shims/chokidar.ts +313 -0
- package/src/shims/cluster.ts +67 -0
- package/src/shims/crypto.ts +830 -0
- package/src/shims/dgram.ts +47 -0
- package/src/shims/diagnostics_channel.ts +196 -0
- package/src/shims/dns.ts +172 -0
- package/src/shims/domain.ts +58 -0
- package/src/shims/esbuild.ts +805 -0
- package/src/shims/events.ts +195 -0
- package/src/shims/fs.ts +803 -0
- package/src/shims/fsevents.ts +63 -0
- package/src/shims/http.ts +904 -0
- package/src/shims/http2.ts +96 -0
- package/src/shims/https.ts +86 -0
- package/src/shims/inspector.ts +30 -0
- package/src/shims/module.ts +82 -0
- package/src/shims/net.ts +359 -0
- package/src/shims/os.ts +195 -0
- package/src/shims/path.ts +199 -0
- package/src/shims/perf_hooks.ts +92 -0
- package/src/shims/process.ts +346 -0
- package/src/shims/querystring.ts +97 -0
- package/src/shims/readdirp.ts +228 -0
- package/src/shims/readline.ts +110 -0
- package/src/shims/rollup.ts +80 -0
- package/src/shims/sentry.ts +133 -0
- package/src/shims/stream.ts +1126 -0
- package/src/shims/tls.ts +95 -0
- package/src/shims/tty.ts +64 -0
- package/src/shims/url.ts +171 -0
- package/src/shims/util.ts +312 -0
- package/src/shims/v8.ts +113 -0
- package/src/shims/vfs-adapter.ts +402 -0
- package/src/shims/vm.ts +83 -0
- package/src/shims/worker_threads.ts +111 -0
- package/src/shims/ws.ts +382 -0
- package/src/shims/zlib.ts +289 -0
- package/src/transform.ts +313 -0
- package/src/types/external.d.ts +67 -0
- package/src/virtual-fs.ts +903 -0
- package/src/vite-demo.ts +577 -0
- package/src/worker/runtime-worker.ts +128 -0
- package/src/worker-runtime.ts +145 -0
|
@@ -0,0 +1,805 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* esbuild shim - Uses esbuild-wasm for transforms in the browser
|
|
3
|
+
* Provides VFS integration for file access
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import type { VirtualFS } from '../virtual-fs';
|
|
7
|
+
|
|
8
|
+
// ============================================================================
|
|
9
|
+
// Type Definitions
|
|
10
|
+
// ============================================================================
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Represents a package.json exports map entry.
|
|
14
|
+
* Can be a direct path string or a conditional exports object with nested conditions.
|
|
15
|
+
*
|
|
16
|
+
* @example Direct string entry:
|
|
17
|
+
* ```json
|
|
18
|
+
* { "exports": "./dist/index.js" }
|
|
19
|
+
* ```
|
|
20
|
+
*
|
|
21
|
+
* @example Conditional exports:
|
|
22
|
+
* ```json
|
|
23
|
+
* {
|
|
24
|
+
* "exports": {
|
|
25
|
+
* ".": {
|
|
26
|
+
* "import": "./dist/esm/index.js",
|
|
27
|
+
* "require": "./dist/cjs/index.js"
|
|
28
|
+
* }
|
|
29
|
+
* }
|
|
30
|
+
* }
|
|
31
|
+
* ```
|
|
32
|
+
*
|
|
33
|
+
* @example Nested conditions (e.g., convex package):
|
|
34
|
+
* ```json
|
|
35
|
+
* {
|
|
36
|
+
* "exports": {
|
|
37
|
+
* "./server": {
|
|
38
|
+
* "convex": {
|
|
39
|
+
* "import": "./dist/server.js"
|
|
40
|
+
* },
|
|
41
|
+
* "default": "./dist/server.js"
|
|
42
|
+
* }
|
|
43
|
+
* }
|
|
44
|
+
* }
|
|
45
|
+
* ```
|
|
46
|
+
*/
|
|
47
|
+
type ExportEntry = string | ExportConditions;
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Conditional exports object mapping condition names to export entries.
|
|
51
|
+
* Conditions can be nested to support complex resolution scenarios.
|
|
52
|
+
*/
|
|
53
|
+
interface ExportConditions {
|
|
54
|
+
[condition: string]: ExportEntry;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Result of resolving a node module import.
|
|
59
|
+
*/
|
|
60
|
+
interface NodeModuleResolution {
|
|
61
|
+
/** The resolved absolute path to the module file */
|
|
62
|
+
path: string;
|
|
63
|
+
/** Plugin data to pass to the onLoad handler */
|
|
64
|
+
pluginData: { fromVFS: boolean };
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// esbuild-wasm types
|
|
68
|
+
export interface TransformOptions {
|
|
69
|
+
loader?: 'js' | 'jsx' | 'ts' | 'tsx' | 'json' | 'css';
|
|
70
|
+
format?: 'iife' | 'cjs' | 'esm';
|
|
71
|
+
target?: string | string[];
|
|
72
|
+
minify?: boolean;
|
|
73
|
+
sourcemap?: boolean | 'inline' | 'external';
|
|
74
|
+
jsx?: 'transform' | 'preserve';
|
|
75
|
+
jsxFactory?: string;
|
|
76
|
+
jsxFragment?: string;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
export interface TransformResult {
|
|
80
|
+
code: string;
|
|
81
|
+
map: string;
|
|
82
|
+
warnings: unknown[];
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
export interface BuildOptions {
|
|
86
|
+
entryPoints?: string[];
|
|
87
|
+
bundle?: boolean;
|
|
88
|
+
outdir?: string;
|
|
89
|
+
outfile?: string;
|
|
90
|
+
format?: 'iife' | 'cjs' | 'esm';
|
|
91
|
+
platform?: 'browser' | 'node' | 'neutral';
|
|
92
|
+
target?: string | string[];
|
|
93
|
+
minify?: boolean;
|
|
94
|
+
sourcemap?: boolean | 'inline' | 'external';
|
|
95
|
+
external?: string[];
|
|
96
|
+
write?: boolean;
|
|
97
|
+
plugins?: unknown[];
|
|
98
|
+
absWorkingDir?: string;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
export interface BuildResult {
|
|
102
|
+
errors: unknown[];
|
|
103
|
+
warnings: unknown[];
|
|
104
|
+
outputFiles?: Array<{ path: string; contents: Uint8Array; text: string }>;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// Window.__esbuild type is declared in src/types/external.d.ts
|
|
108
|
+
|
|
109
|
+
// ============================================================================
|
|
110
|
+
// Export Condition Resolution
|
|
111
|
+
// ============================================================================
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* The priority order for export conditions when resolving package exports.
|
|
115
|
+
*
|
|
116
|
+
* Order rationale:
|
|
117
|
+
* 1. "convex" - Framework-specific condition for Convex packages (highest priority)
|
|
118
|
+
* 2. "module" - ESM entry point (preferred for modern bundlers)
|
|
119
|
+
* 3. "import" - ESM import condition (standard Node.js condition)
|
|
120
|
+
* 4. "require" - CJS require condition (fallback for CommonJS)
|
|
121
|
+
* 5. "default" - Fallback condition (lowest priority)
|
|
122
|
+
*/
|
|
123
|
+
const EXPORT_CONDITION_PRIORITY = ['convex', 'module', 'import', 'require', 'default'] as const;
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* Resolves a package.json exports entry to a file path by evaluating export conditions.
|
|
127
|
+
*
|
|
128
|
+
* This function handles the Node.js package exports map resolution algorithm,
|
|
129
|
+
* supporting both simple string exports and conditional exports with nested structures.
|
|
130
|
+
*
|
|
131
|
+
* @param entry - The exports map entry to resolve. Can be:
|
|
132
|
+
* - A string path (e.g., "./dist/index.js")
|
|
133
|
+
* - A conditional exports object with condition keys
|
|
134
|
+
* - Nested conditional objects for complex packages
|
|
135
|
+
*
|
|
136
|
+
* @returns The resolved file path relative to the package root, or undefined if
|
|
137
|
+
* no matching condition is found.
|
|
138
|
+
*
|
|
139
|
+
* @example Simple string entry:
|
|
140
|
+
* ```ts
|
|
141
|
+
* resolveExportConditions("./dist/index.js")
|
|
142
|
+
* // Returns: "./dist/index.js"
|
|
143
|
+
* ```
|
|
144
|
+
*
|
|
145
|
+
* @example Conditional exports:
|
|
146
|
+
* ```ts
|
|
147
|
+
* resolveExportConditions({
|
|
148
|
+
* import: "./dist/esm/index.js",
|
|
149
|
+
* require: "./dist/cjs/index.js",
|
|
150
|
+
* default: "./dist/index.js"
|
|
151
|
+
* })
|
|
152
|
+
* // Returns: "./dist/esm/index.js" (import has higher priority)
|
|
153
|
+
* ```
|
|
154
|
+
*
|
|
155
|
+
* @example Nested conditions (convex package style):
|
|
156
|
+
* ```ts
|
|
157
|
+
* resolveExportConditions({
|
|
158
|
+
* convex: { import: "./dist/convex.js" },
|
|
159
|
+
* default: "./dist/default.js"
|
|
160
|
+
* })
|
|
161
|
+
* // Returns: "./dist/convex.js" (convex condition with nested import)
|
|
162
|
+
* ```
|
|
163
|
+
*/
|
|
164
|
+
function resolveExportConditions(entry: ExportEntry): string | undefined {
|
|
165
|
+
// Direct string path - return as-is
|
|
166
|
+
if (typeof entry === 'string') {
|
|
167
|
+
return entry;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
// Conditional exports object - evaluate conditions in priority order
|
|
171
|
+
if (typeof entry === 'object' && entry !== null) {
|
|
172
|
+
for (const condition of EXPORT_CONDITION_PRIORITY) {
|
|
173
|
+
const conditionValue = entry[condition];
|
|
174
|
+
if (conditionValue !== undefined) {
|
|
175
|
+
// Recursively resolve nested conditions
|
|
176
|
+
const result = resolveExportConditions(conditionValue);
|
|
177
|
+
if (result) {
|
|
178
|
+
return result;
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
return undefined;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
// ============================================================================
|
|
188
|
+
// Node Modules Resolution
|
|
189
|
+
// ============================================================================
|
|
190
|
+
|
|
191
|
+
/**
|
|
192
|
+
* Resolves a bare import (e.g., "convex/server", "react") to an absolute file path
|
|
193
|
+
* in the VFS node_modules directory.
|
|
194
|
+
*
|
|
195
|
+
* ## Why resolve from VFS instead of marking as external?
|
|
196
|
+
*
|
|
197
|
+
* We resolve modules from the VFS node_modules directory instead of marking them
|
|
198
|
+
* as external because:
|
|
199
|
+
*
|
|
200
|
+
* 1. **Browser bundling**: In the browser environment, we need to bundle all
|
|
201
|
+
* dependencies since there's no Node.js runtime to resolve modules at runtime.
|
|
202
|
+
*
|
|
203
|
+
* 2. **VFS isolation**: The virtual file system contains a snapshot of dependencies
|
|
204
|
+
* that may differ from what's available in the host environment.
|
|
205
|
+
*
|
|
206
|
+
* 3. **Consistent builds**: By resolving from VFS, we ensure builds are
|
|
207
|
+
* reproducible regardless of the host machine's node_modules.
|
|
208
|
+
*
|
|
209
|
+
* ## Resolution Algorithm
|
|
210
|
+
*
|
|
211
|
+
* 1. Parse the import path to extract the package name and subpath
|
|
212
|
+
* - Scoped packages: "@scope/pkg/sub" -> name="@scope/pkg", subpath="sub"
|
|
213
|
+
* - Regular packages: "pkg/sub" -> name="pkg", subpath="sub"
|
|
214
|
+
*
|
|
215
|
+
* 2. Check if the package exists in /project/node_modules/{name}
|
|
216
|
+
*
|
|
217
|
+
* 3. Read the package.json and resolve the entry point:
|
|
218
|
+
* a. For subpath imports (e.g., "convex/server"):
|
|
219
|
+
* - Check exports map for "./{subpath}" key
|
|
220
|
+
* - Fall back to direct file path resolution
|
|
221
|
+
* b. For main imports (e.g., "convex"):
|
|
222
|
+
* - Check exports map for "." key
|
|
223
|
+
* - Fall back to "module" or "main" fields
|
|
224
|
+
*
|
|
225
|
+
* 4. Verify the resolved file exists with supported extensions
|
|
226
|
+
*
|
|
227
|
+
* @param vfs - The virtual file system instance
|
|
228
|
+
* @param importPath - The bare import path (e.g., "convex/server", "react")
|
|
229
|
+
* @param extensions - File extensions to try when resolving (e.g., ['', '.ts', '.js'])
|
|
230
|
+
*
|
|
231
|
+
* @returns Resolution result with the absolute path, or null if the module
|
|
232
|
+
* cannot be resolved (should be marked as external)
|
|
233
|
+
*/
|
|
234
|
+
function resolveNodeModuleImport(
|
|
235
|
+
vfs: VirtualFS,
|
|
236
|
+
importPath: string,
|
|
237
|
+
extensions: string[]
|
|
238
|
+
): NodeModuleResolution | null {
|
|
239
|
+
// Parse the import path to extract package name and subpath
|
|
240
|
+
// Scoped packages: "@scope/pkg/sub" -> ["@scope", "pkg", "sub"]
|
|
241
|
+
// Regular packages: "pkg/sub" -> ["pkg", "sub"]
|
|
242
|
+
const pathParts = importPath.split('/');
|
|
243
|
+
const isScoped = pathParts[0].startsWith('@');
|
|
244
|
+
|
|
245
|
+
const moduleName = isScoped
|
|
246
|
+
? pathParts.slice(0, 2).join('/') // "@scope/pkg"
|
|
247
|
+
: pathParts[0]; // "pkg"
|
|
248
|
+
|
|
249
|
+
const subPath = isScoped
|
|
250
|
+
? pathParts.slice(2).join('/') // Everything after "@scope/pkg/"
|
|
251
|
+
: pathParts.slice(1).join('/'); // Everything after "pkg/"
|
|
252
|
+
|
|
253
|
+
// Check if the package exists in VFS node_modules
|
|
254
|
+
const nodeModulesBase = '/project/node_modules/' + moduleName;
|
|
255
|
+
|
|
256
|
+
if (!vfs.existsSync(nodeModulesBase)) {
|
|
257
|
+
return null;
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
// Read package.json to determine the entry point
|
|
261
|
+
const packageJsonPath = nodeModulesBase + '/package.json';
|
|
262
|
+
if (!vfs.existsSync(packageJsonPath)) {
|
|
263
|
+
return null;
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
try {
|
|
267
|
+
const packageJsonContent = vfs.readFileSync(packageJsonPath, 'utf8');
|
|
268
|
+
const packageJson = JSON.parse(packageJsonContent) as {
|
|
269
|
+
exports?: Record<string, ExportEntry> | ExportEntry;
|
|
270
|
+
module?: string;
|
|
271
|
+
main?: string;
|
|
272
|
+
};
|
|
273
|
+
|
|
274
|
+
let resolvedPath: string | null = null;
|
|
275
|
+
|
|
276
|
+
if (subPath) {
|
|
277
|
+
// Importing a subpath like "convex/server"
|
|
278
|
+
resolvedPath = resolveSubpathImport(
|
|
279
|
+
vfs,
|
|
280
|
+
packageJson,
|
|
281
|
+
nodeModulesBase,
|
|
282
|
+
subPath,
|
|
283
|
+
extensions
|
|
284
|
+
);
|
|
285
|
+
} else {
|
|
286
|
+
// Importing the main module like "convex"
|
|
287
|
+
resolvedPath = resolveMainImport(
|
|
288
|
+
vfs,
|
|
289
|
+
packageJson,
|
|
290
|
+
nodeModulesBase,
|
|
291
|
+
extensions
|
|
292
|
+
);
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
if (resolvedPath) {
|
|
296
|
+
return { path: resolvedPath, pluginData: { fromVFS: true } };
|
|
297
|
+
}
|
|
298
|
+
} catch {
|
|
299
|
+
// Failed to read package.json, fall through to return null
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
return null;
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
/**
|
|
306
|
+
* Resolves a subpath import (e.g., "convex/server" -> "./server" subpath).
|
|
307
|
+
*
|
|
308
|
+
* Resolution order:
|
|
309
|
+
* 1. Check exports map for "./{subpath}" key with condition resolution
|
|
310
|
+
* 2. Fall back to direct file path resolution with extensions
|
|
311
|
+
*/
|
|
312
|
+
function resolveSubpathImport(
|
|
313
|
+
vfs: VirtualFS,
|
|
314
|
+
packageJson: { exports?: Record<string, ExportEntry> | ExportEntry },
|
|
315
|
+
nodeModulesBase: string,
|
|
316
|
+
subPath: string,
|
|
317
|
+
extensions: string[]
|
|
318
|
+
): string | null {
|
|
319
|
+
// Try exports map first
|
|
320
|
+
if (packageJson.exports && typeof packageJson.exports === 'object') {
|
|
321
|
+
const exportKey = './' + subPath;
|
|
322
|
+
const exportsMap = packageJson.exports as Record<string, ExportEntry>;
|
|
323
|
+
const exportEntry = exportsMap[exportKey];
|
|
324
|
+
|
|
325
|
+
if (exportEntry) {
|
|
326
|
+
const exportPath = resolveExportConditions(exportEntry);
|
|
327
|
+
if (exportPath) {
|
|
328
|
+
const resolvedPath = nodeModulesBase + '/' + exportPath.replace(/^\.\//, '');
|
|
329
|
+
const foundPath = findVFSFile(vfs, resolvedPath, ['', '.js', '.ts', '.mjs']);
|
|
330
|
+
if (foundPath) {
|
|
331
|
+
return foundPath;
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
// Fall back to direct path resolution
|
|
338
|
+
const directPath = nodeModulesBase + '/' + subPath;
|
|
339
|
+
return findVFSFile(vfs, directPath, extensions);
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
/**
|
|
343
|
+
* Resolves the main entry point of a package (e.g., "convex" without subpath).
|
|
344
|
+
*
|
|
345
|
+
* Resolution order:
|
|
346
|
+
* 1. Check exports map "." key with condition resolution
|
|
347
|
+
* 2. Fall back to "module" field (ESM entry)
|
|
348
|
+
* 3. Fall back to "main" field (CJS entry)
|
|
349
|
+
* 4. Default to "index.js"
|
|
350
|
+
*/
|
|
351
|
+
function resolveMainImport(
|
|
352
|
+
vfs: VirtualFS,
|
|
353
|
+
packageJson: {
|
|
354
|
+
exports?: Record<string, ExportEntry> | ExportEntry;
|
|
355
|
+
module?: string;
|
|
356
|
+
main?: string;
|
|
357
|
+
},
|
|
358
|
+
nodeModulesBase: string,
|
|
359
|
+
extensions: string[]
|
|
360
|
+
): string | null {
|
|
361
|
+
// Try exports map first
|
|
362
|
+
if (packageJson.exports) {
|
|
363
|
+
// The main export can be at "." key or be the exports value itself
|
|
364
|
+
const mainExport = typeof packageJson.exports === 'object' && !Array.isArray(packageJson.exports)
|
|
365
|
+
? (packageJson.exports['.'] || packageJson.exports)
|
|
366
|
+
: packageJson.exports;
|
|
367
|
+
|
|
368
|
+
const exportPath = resolveExportConditions(mainExport as ExportEntry);
|
|
369
|
+
if (exportPath) {
|
|
370
|
+
const resolvedPath = nodeModulesBase + '/' + exportPath.replace(/^\.\//, '');
|
|
371
|
+
const foundPath = findVFSFile(vfs, resolvedPath, ['', '.js', '.ts', '.mjs']);
|
|
372
|
+
if (foundPath) {
|
|
373
|
+
return foundPath;
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
// Fall back to module/main fields
|
|
379
|
+
// Prefer "module" (ESM) over "main" (CJS) for better tree-shaking
|
|
380
|
+
const mainField = packageJson.module || packageJson.main || 'index.js';
|
|
381
|
+
const resolvedPath = nodeModulesBase + '/' + mainField.replace(/^\.\//, '');
|
|
382
|
+
return findVFSFile(vfs, resolvedPath, extensions);
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
// ============================================================================
|
|
386
|
+
// Module State
|
|
387
|
+
// ============================================================================
|
|
388
|
+
|
|
389
|
+
// State
|
|
390
|
+
let esbuildInstance: typeof import('esbuild-wasm') | null = null;
|
|
391
|
+
let initPromise: Promise<void> | null = null;
|
|
392
|
+
let wasmURL = 'https://unpkg.com/esbuild-wasm@0.20.0/esbuild.wasm';
|
|
393
|
+
let globalVFS: VirtualFS | null = null;
|
|
394
|
+
|
|
395
|
+
/**
|
|
396
|
+
* Set the VirtualFS instance for file access
|
|
397
|
+
*/
|
|
398
|
+
export function setVFS(vfs: VirtualFS): void {
|
|
399
|
+
globalVFS = vfs;
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
/**
|
|
403
|
+
* Set the URL for the esbuild WASM file
|
|
404
|
+
*/
|
|
405
|
+
export function setWasmURL(url: string): void {
|
|
406
|
+
wasmURL = url;
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
/**
|
|
410
|
+
* Initialize esbuild-wasm
|
|
411
|
+
* Must be called before using transform or build
|
|
412
|
+
*/
|
|
413
|
+
export async function initialize(options?: { wasmURL?: string }): Promise<void> {
|
|
414
|
+
if (esbuildInstance) {
|
|
415
|
+
return; // Already initialized
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
// Check for shared esbuild instance from transform.ts
|
|
419
|
+
if (typeof window !== 'undefined' && window.__esbuild) {
|
|
420
|
+
esbuildInstance = window.__esbuild;
|
|
421
|
+
return;
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
// Wait for any in-progress initialization from transform.ts
|
|
425
|
+
if (typeof window !== 'undefined' && window.__esbuildInitPromise) {
|
|
426
|
+
await window.__esbuildInitPromise;
|
|
427
|
+
if (window.__esbuild) {
|
|
428
|
+
esbuildInstance = window.__esbuild;
|
|
429
|
+
return;
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
if (initPromise) {
|
|
434
|
+
return initPromise; // Our initialization in progress
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
initPromise = (async () => {
|
|
438
|
+
try {
|
|
439
|
+
// Dynamically import esbuild-wasm from CDN
|
|
440
|
+
const esbuild = await import(
|
|
441
|
+
/* @vite-ignore */
|
|
442
|
+
'https://unpkg.com/esbuild-wasm@0.20.0/esm/browser.min.js'
|
|
443
|
+
);
|
|
444
|
+
|
|
445
|
+
await esbuild.initialize({
|
|
446
|
+
wasmURL: options?.wasmURL || wasmURL,
|
|
447
|
+
});
|
|
448
|
+
|
|
449
|
+
esbuildInstance = esbuild;
|
|
450
|
+
} catch (error) {
|
|
451
|
+
initPromise = null;
|
|
452
|
+
throw new Error(`Failed to initialize esbuild-wasm: ${error}`);
|
|
453
|
+
}
|
|
454
|
+
})();
|
|
455
|
+
|
|
456
|
+
return initPromise;
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
/**
|
|
460
|
+
* Check if esbuild is initialized
|
|
461
|
+
*/
|
|
462
|
+
export function isInitialized(): boolean {
|
|
463
|
+
return esbuildInstance !== null;
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
// ============================================================================
|
|
467
|
+
// Transform API
|
|
468
|
+
// ============================================================================
|
|
469
|
+
|
|
470
|
+
/**
|
|
471
|
+
* Transform code using esbuild
|
|
472
|
+
*/
|
|
473
|
+
export async function transform(
|
|
474
|
+
code: string,
|
|
475
|
+
options?: TransformOptions
|
|
476
|
+
): Promise<TransformResult> {
|
|
477
|
+
if (!esbuildInstance) {
|
|
478
|
+
await initialize();
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
if (!esbuildInstance) {
|
|
482
|
+
throw new Error('esbuild not initialized');
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
return esbuildInstance.transform(code, options);
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
/**
|
|
489
|
+
* Transform code synchronously (requires prior initialization)
|
|
490
|
+
*/
|
|
491
|
+
export function transformSync(
|
|
492
|
+
code: string,
|
|
493
|
+
options?: TransformOptions
|
|
494
|
+
): TransformResult {
|
|
495
|
+
if (!esbuildInstance) {
|
|
496
|
+
throw new Error('esbuild not initialized. Call initialize() first.');
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
// esbuild-wasm doesn't have sync API in browser, so we throw
|
|
500
|
+
throw new Error('transformSync is not available in browser. Use transform() instead.');
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
/**
|
|
504
|
+
* Transform ESM to CJS
|
|
505
|
+
*/
|
|
506
|
+
export async function transformToCommonJS(
|
|
507
|
+
code: string,
|
|
508
|
+
options?: { loader?: TransformOptions['loader'] }
|
|
509
|
+
): Promise<string> {
|
|
510
|
+
const result = await transform(code, {
|
|
511
|
+
loader: options?.loader || 'js',
|
|
512
|
+
format: 'cjs',
|
|
513
|
+
target: 'es2020',
|
|
514
|
+
});
|
|
515
|
+
|
|
516
|
+
return result.code;
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
// ============================================================================
|
|
520
|
+
// VFS Path Resolution Helpers
|
|
521
|
+
// ============================================================================
|
|
522
|
+
|
|
523
|
+
/**
|
|
524
|
+
* Apply path remapping for VFS (e.g., /convex/ -> /project/convex/)
|
|
525
|
+
* This keeps the original path for esbuild output naming but finds the actual file.
|
|
526
|
+
*/
|
|
527
|
+
function remapVFSPath(path: string): string {
|
|
528
|
+
// Remap /convex/ to /project/convex/
|
|
529
|
+
if (path === '/convex' || path.startsWith('/convex/')) {
|
|
530
|
+
return '/project' + path;
|
|
531
|
+
}
|
|
532
|
+
return path;
|
|
533
|
+
}
|
|
534
|
+
|
|
535
|
+
/**
|
|
536
|
+
* Check if file exists at path or remapped path
|
|
537
|
+
* Returns the original path if found (to preserve output naming)
|
|
538
|
+
*/
|
|
539
|
+
function findVFSFile(vfs: VirtualFS, originalPath: string, extensions: string[]): string | null {
|
|
540
|
+
for (const ext of extensions) {
|
|
541
|
+
const pathWithExt = originalPath + ext;
|
|
542
|
+
// First check original path
|
|
543
|
+
if (vfs.existsSync(pathWithExt)) {
|
|
544
|
+
return pathWithExt;
|
|
545
|
+
}
|
|
546
|
+
// Then try remapped path
|
|
547
|
+
const remapped = remapVFSPath(pathWithExt);
|
|
548
|
+
if (remapped !== pathWithExt && vfs.existsSync(remapped)) {
|
|
549
|
+
// Return original path (not remapped) to preserve esbuild output naming
|
|
550
|
+
return pathWithExt;
|
|
551
|
+
}
|
|
552
|
+
}
|
|
553
|
+
return null;
|
|
554
|
+
}
|
|
555
|
+
|
|
556
|
+
// ============================================================================
|
|
557
|
+
// VFS Plugin for esbuild
|
|
558
|
+
// ============================================================================
|
|
559
|
+
|
|
560
|
+
/**
|
|
561
|
+
* Create a VFS plugin for esbuild to read files from VirtualFS.
|
|
562
|
+
*
|
|
563
|
+
* This plugin enables esbuild to resolve and load files from the virtual file system,
|
|
564
|
+
* which is essential for browser-based bundling where we don't have access to the
|
|
565
|
+
* real file system.
|
|
566
|
+
*
|
|
567
|
+
* The plugin handles three types of imports:
|
|
568
|
+
* 1. Absolute paths (/project/src/file.ts)
|
|
569
|
+
* 2. Relative paths (./file.ts, ../file.ts)
|
|
570
|
+
* 3. Bare imports (convex/server, react)
|
|
571
|
+
*/
|
|
572
|
+
function createVFSPlugin(): unknown {
|
|
573
|
+
if (!globalVFS) {
|
|
574
|
+
return null;
|
|
575
|
+
}
|
|
576
|
+
|
|
577
|
+
const vfs = globalVFS;
|
|
578
|
+
|
|
579
|
+
return {
|
|
580
|
+
name: 'vfs-loader',
|
|
581
|
+
setup(build: unknown) {
|
|
582
|
+
const b = build as {
|
|
583
|
+
onResolve: (options: { filter: RegExp; namespace?: string }, callback: (args: { path: string; importer: string; kind: string }) => unknown) => void;
|
|
584
|
+
onLoad: (options: { filter: RegExp; namespace?: string }, callback: (args: { path: string }) => unknown) => void;
|
|
585
|
+
};
|
|
586
|
+
|
|
587
|
+
// Resolve file paths - handles both imports and entry points
|
|
588
|
+
b.onResolve({ filter: /.*/ }, (args: { path: string; importer: string }) => {
|
|
589
|
+
const { path: importPath, importer } = args;
|
|
590
|
+
|
|
591
|
+
// Skip external modules (node_modules, bare imports)
|
|
592
|
+
if (importPath.startsWith('node_modules/')) {
|
|
593
|
+
return { external: true };
|
|
594
|
+
}
|
|
595
|
+
|
|
596
|
+
const extensions = ['', '.ts', '.tsx', '.js', '.jsx', '.json'];
|
|
597
|
+
|
|
598
|
+
// Absolute paths - check if file exists in VFS (or remapped location)
|
|
599
|
+
if (importPath.startsWith('/')) {
|
|
600
|
+
const foundPath = findVFSFile(vfs, importPath, extensions);
|
|
601
|
+
if (foundPath) {
|
|
602
|
+
return { path: foundPath, pluginData: { fromVFS: true } };
|
|
603
|
+
}
|
|
604
|
+
// File not found
|
|
605
|
+
return { external: true };
|
|
606
|
+
}
|
|
607
|
+
|
|
608
|
+
// Relative paths
|
|
609
|
+
if (importPath.startsWith('.')) {
|
|
610
|
+
let resolved = importPath;
|
|
611
|
+
if (importer) {
|
|
612
|
+
const importerDir = importer.substring(0, importer.lastIndexOf('/'));
|
|
613
|
+
resolved = importerDir + '/' + importPath;
|
|
614
|
+
}
|
|
615
|
+
// Normalize path
|
|
616
|
+
const parts = resolved.split('/').filter(Boolean);
|
|
617
|
+
const normalized: string[] = [];
|
|
618
|
+
for (const part of parts) {
|
|
619
|
+
if (part === '..') {
|
|
620
|
+
normalized.pop();
|
|
621
|
+
} else if (part !== '.') {
|
|
622
|
+
normalized.push(part);
|
|
623
|
+
}
|
|
624
|
+
}
|
|
625
|
+
resolved = '/' + normalized.join('/');
|
|
626
|
+
|
|
627
|
+
// Try to find the file with various extensions
|
|
628
|
+
const foundPath = findVFSFile(vfs, resolved, extensions);
|
|
629
|
+
if (foundPath) {
|
|
630
|
+
return { path: foundPath, pluginData: { fromVFS: true } };
|
|
631
|
+
}
|
|
632
|
+
|
|
633
|
+
// Try index files
|
|
634
|
+
for (const ext of ['.ts', '.tsx', '.js', '.jsx']) {
|
|
635
|
+
const indexPath = resolved + '/index' + ext;
|
|
636
|
+
const foundIndex = findVFSFile(vfs, indexPath, ['']);
|
|
637
|
+
if (foundIndex) {
|
|
638
|
+
return { path: foundIndex, pluginData: { fromVFS: true } };
|
|
639
|
+
}
|
|
640
|
+
}
|
|
641
|
+
}
|
|
642
|
+
|
|
643
|
+
// Bare imports (no ./ or ../ or /) - resolve from node_modules in VFS
|
|
644
|
+
// See resolveNodeModuleImport() JSDoc for why we resolve from VFS instead of
|
|
645
|
+
// marking as external (browser bundling, VFS isolation, consistent builds)
|
|
646
|
+
const resolution = resolveNodeModuleImport(vfs, importPath, extensions);
|
|
647
|
+
if (resolution) {
|
|
648
|
+
return resolution;
|
|
649
|
+
}
|
|
650
|
+
|
|
651
|
+
// Could not resolve from node_modules, treat as external
|
|
652
|
+
return { external: true };
|
|
653
|
+
});
|
|
654
|
+
|
|
655
|
+
// Load file contents from VFS
|
|
656
|
+
// Apply path remapping when reading to find the actual file
|
|
657
|
+
b.onLoad({ filter: /^\/.*/ }, (args: { path: string; pluginData?: { fromVFS?: boolean } }) => {
|
|
658
|
+
// Only handle files that were resolved by our plugin
|
|
659
|
+
if (!args.pluginData?.fromVFS) {
|
|
660
|
+
return null; // Let other loaders handle it
|
|
661
|
+
}
|
|
662
|
+
try {
|
|
663
|
+
// Try original path first, then remapped path
|
|
664
|
+
let contents: string;
|
|
665
|
+
const originalPath = args.path;
|
|
666
|
+
const remappedPath = remapVFSPath(originalPath);
|
|
667
|
+
|
|
668
|
+
if (vfs.existsSync(originalPath)) {
|
|
669
|
+
contents = vfs.readFileSync(originalPath, 'utf8');
|
|
670
|
+
} else if (remappedPath !== originalPath && vfs.existsSync(remappedPath)) {
|
|
671
|
+
contents = vfs.readFileSync(remappedPath, 'utf8');
|
|
672
|
+
} else {
|
|
673
|
+
throw new Error(`File not found: ${originalPath} (tried ${remappedPath})`);
|
|
674
|
+
}
|
|
675
|
+
|
|
676
|
+
const ext = originalPath.substring(originalPath.lastIndexOf('.'));
|
|
677
|
+
let loader: 'ts' | 'tsx' | 'js' | 'jsx' | 'json' = 'ts';
|
|
678
|
+
if (ext === '.tsx') loader = 'tsx';
|
|
679
|
+
else if (ext === '.js') loader = 'js';
|
|
680
|
+
else if (ext === '.jsx') loader = 'jsx';
|
|
681
|
+
else if (ext === '.json') loader = 'json';
|
|
682
|
+
|
|
683
|
+
return { contents, loader };
|
|
684
|
+
} catch (err) {
|
|
685
|
+
return { errors: [{ text: `Failed to load ${args.path}: ${err}` }] };
|
|
686
|
+
}
|
|
687
|
+
});
|
|
688
|
+
},
|
|
689
|
+
};
|
|
690
|
+
}
|
|
691
|
+
|
|
692
|
+
// ============================================================================
|
|
693
|
+
// Build API
|
|
694
|
+
// ============================================================================
|
|
695
|
+
|
|
696
|
+
/**
|
|
697
|
+
* Build/bundle code (limited support in browser)
|
|
698
|
+
*/
|
|
699
|
+
export async function build(options: BuildOptions): Promise<BuildResult> {
|
|
700
|
+
if (!esbuildInstance) {
|
|
701
|
+
await initialize();
|
|
702
|
+
}
|
|
703
|
+
|
|
704
|
+
if (!esbuildInstance) {
|
|
705
|
+
throw new Error('esbuild not initialized');
|
|
706
|
+
}
|
|
707
|
+
|
|
708
|
+
// Add VFS plugin if VFS is available
|
|
709
|
+
const vfsPlugin = createVFSPlugin();
|
|
710
|
+
const plugins = [...(options.plugins || [])];
|
|
711
|
+
if (vfsPlugin) {
|
|
712
|
+
plugins.unshift(vfsPlugin);
|
|
713
|
+
}
|
|
714
|
+
|
|
715
|
+
// Resolve entry points to absolute paths (but DON'T remap /convex/ to /project/convex/)
|
|
716
|
+
// The path remapping happens in the VFS plugin's onLoad handler instead.
|
|
717
|
+
// This preserves the original paths for esbuild's output file naming.
|
|
718
|
+
let entryPoints = options.entryPoints;
|
|
719
|
+
if (entryPoints && globalVFS) {
|
|
720
|
+
const absWorkingDir = options.absWorkingDir || '/';
|
|
721
|
+
entryPoints = entryPoints.map(ep => {
|
|
722
|
+
// Handle paths that came from previous builds with vfs: namespace prefix
|
|
723
|
+
if (ep.includes('vfs:')) {
|
|
724
|
+
const vfsIndex = ep.indexOf('vfs:');
|
|
725
|
+
ep = ep.substring(vfsIndex + 4);
|
|
726
|
+
}
|
|
727
|
+
|
|
728
|
+
// If already absolute, use as-is
|
|
729
|
+
if (ep.startsWith('/')) {
|
|
730
|
+
return ep;
|
|
731
|
+
}
|
|
732
|
+
|
|
733
|
+
if (ep.startsWith('./')) {
|
|
734
|
+
// Join with absWorkingDir but DO NOT remap paths
|
|
735
|
+
const base = absWorkingDir.endsWith('/') ? absWorkingDir.slice(0, -1) : absWorkingDir;
|
|
736
|
+
const relative = ep.slice(2);
|
|
737
|
+
const resolved = base + '/' + relative;
|
|
738
|
+
return resolved;
|
|
739
|
+
}
|
|
740
|
+
if (ep.startsWith('../')) {
|
|
741
|
+
const base = absWorkingDir.endsWith('/') ? absWorkingDir.slice(0, -1) : absWorkingDir;
|
|
742
|
+
const parts = base.split('/').filter(Boolean);
|
|
743
|
+
parts.pop();
|
|
744
|
+
const relative = ep.slice(3);
|
|
745
|
+
const resolved = '/' + parts.join('/') + '/' + relative;
|
|
746
|
+
return resolved;
|
|
747
|
+
}
|
|
748
|
+
return ep;
|
|
749
|
+
});
|
|
750
|
+
}
|
|
751
|
+
|
|
752
|
+
// In browser, we need write: false to get outputFiles
|
|
753
|
+
const result = await esbuildInstance.build({
|
|
754
|
+
...options,
|
|
755
|
+
entryPoints,
|
|
756
|
+
plugins,
|
|
757
|
+
write: false,
|
|
758
|
+
}) as BuildResult;
|
|
759
|
+
|
|
760
|
+
// Strip 'vfs:' namespace prefix from output file paths
|
|
761
|
+
// The namespace prefix causes issues when the CLI uses these paths
|
|
762
|
+
if (result.outputFiles) {
|
|
763
|
+
for (const file of result.outputFiles) {
|
|
764
|
+
if (file.path.includes('vfs:')) {
|
|
765
|
+
file.path = file.path.replace(/vfs:/g, '');
|
|
766
|
+
}
|
|
767
|
+
}
|
|
768
|
+
}
|
|
769
|
+
|
|
770
|
+
return result;
|
|
771
|
+
}
|
|
772
|
+
|
|
773
|
+
/**
|
|
774
|
+
* Build synchronously (not supported in browser, throws error)
|
|
775
|
+
*/
|
|
776
|
+
export function buildSync(_options: BuildOptions): BuildResult {
|
|
777
|
+
throw new Error('buildSync is not available in browser. Use build() instead.');
|
|
778
|
+
}
|
|
779
|
+
|
|
780
|
+
/**
|
|
781
|
+
* Get the esbuild version
|
|
782
|
+
*/
|
|
783
|
+
export function version(): string {
|
|
784
|
+
return '0.20.0'; // Version of esbuild-wasm we're using
|
|
785
|
+
}
|
|
786
|
+
|
|
787
|
+
// Context API (minimal stub for compatibility)
|
|
788
|
+
export async function context(_options: BuildOptions): Promise<unknown> {
|
|
789
|
+
throw new Error('esbuild context API is not supported in browser');
|
|
790
|
+
}
|
|
791
|
+
|
|
792
|
+
// Default export matching esbuild's API
|
|
793
|
+
export default {
|
|
794
|
+
initialize,
|
|
795
|
+
isInitialized,
|
|
796
|
+
transform,
|
|
797
|
+
transformSync,
|
|
798
|
+
transformToCommonJS,
|
|
799
|
+
build,
|
|
800
|
+
buildSync,
|
|
801
|
+
context,
|
|
802
|
+
version,
|
|
803
|
+
setWasmURL,
|
|
804
|
+
setVFS,
|
|
805
|
+
};
|