sandlot 0.2.2 → 0.2.3
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/dist/browser/bundler.d.ts.map +1 -1
- package/dist/browser/index.js +134 -67
- package/dist/core/bundler-utils.d.ts +43 -1
- package/dist/core/bundler-utils.d.ts.map +1 -1
- package/dist/core/sandbox.d.ts.map +1 -1
- package/dist/index.js +58 -0
- package/dist/node/bundler.d.ts.map +1 -1
- package/dist/node/index.js +136 -134
- package/dist/node/wasm-bundler.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/browser/bundler.ts +6 -106
- package/src/core/bundler-utils.ts +148 -0
- package/src/core/sandbox.ts +82 -0
- package/src/node/bundler.ts +6 -110
- package/src/node/wasm-bundler.ts +6 -110
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bundler.d.ts","sourceRoot":"","sources":["../../src/browser/bundler.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"bundler.d.ts","sourceRoot":"","sources":["../../src/browser/bundler.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,KAAK,EAAE,QAAQ,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AAmCtE,MAAM,WAAW,yBAAyB;IACxC;;;OAGG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IAEjB;;;OAGG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IAEpB;;;;OAIG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IAEpB;;;;OAIG;IACH,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,qBAAa,kBAAmB,YAAW,QAAQ;IACjD,OAAO,CAAC,OAAO,CAA4B;gBAE/B,OAAO,GAAE,yBAA8B;IAWnD;;;;;;OAMG;IACG,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;YAmBnB,YAAY;IA8B1B;;OAEG;IACH,OAAO,CAAC,UAAU;IAQlB;;;;;;OAMG;IACG,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAU9B,OAAO,CAAC,yBAAyB;IAc3B,MAAM,CAAC,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,YAAY,CAAC;CAU5D"}
|
package/dist/browser/index.js
CHANGED
|
@@ -649,6 +649,78 @@ function generateSharedModuleCode(moduleId, registry) {
|
|
|
649
649
|
}
|
|
650
650
|
return code;
|
|
651
651
|
}
|
|
652
|
+
async function executeBundleWithEsbuild(options) {
|
|
653
|
+
const { esbuild, bundleOptions, cdnBaseUrl, bundleCdnImports } = options;
|
|
654
|
+
const {
|
|
655
|
+
fs,
|
|
656
|
+
entryPoint,
|
|
657
|
+
installedPackages = {},
|
|
658
|
+
sharedModules = [],
|
|
659
|
+
sharedModuleRegistry,
|
|
660
|
+
external = [],
|
|
661
|
+
format = "esm",
|
|
662
|
+
minify = false,
|
|
663
|
+
sourcemap = false,
|
|
664
|
+
target = ["es2020"]
|
|
665
|
+
} = bundleOptions;
|
|
666
|
+
const normalizedEntry = entryPoint.startsWith("/") ? entryPoint : `/${entryPoint}`;
|
|
667
|
+
if (!fs.exists(normalizedEntry)) {
|
|
668
|
+
return {
|
|
669
|
+
success: false,
|
|
670
|
+
errors: [{ text: `Entry point not found: ${normalizedEntry}` }],
|
|
671
|
+
warnings: []
|
|
672
|
+
};
|
|
673
|
+
}
|
|
674
|
+
const includedFiles = new Set;
|
|
675
|
+
const plugin = createVfsPlugin({
|
|
676
|
+
fs,
|
|
677
|
+
entryPoint: normalizedEntry,
|
|
678
|
+
installedPackages,
|
|
679
|
+
sharedModules: new Set(sharedModules),
|
|
680
|
+
sharedModuleRegistry: sharedModuleRegistry ?? null,
|
|
681
|
+
cdnBaseUrl,
|
|
682
|
+
includedFiles,
|
|
683
|
+
bundleCdnImports
|
|
684
|
+
});
|
|
685
|
+
try {
|
|
686
|
+
const result = await esbuild.build({
|
|
687
|
+
entryPoints: [normalizedEntry],
|
|
688
|
+
bundle: true,
|
|
689
|
+
write: false,
|
|
690
|
+
format,
|
|
691
|
+
minify,
|
|
692
|
+
sourcemap: sourcemap ? "inline" : false,
|
|
693
|
+
target,
|
|
694
|
+
external,
|
|
695
|
+
plugins: [plugin],
|
|
696
|
+
jsx: "automatic"
|
|
697
|
+
});
|
|
698
|
+
const code = result.outputFiles?.[0]?.text ?? "";
|
|
699
|
+
const warnings = result.warnings.map((w) => convertEsbuildMessage(w));
|
|
700
|
+
return {
|
|
701
|
+
success: true,
|
|
702
|
+
code,
|
|
703
|
+
warnings,
|
|
704
|
+
includedFiles: Array.from(includedFiles)
|
|
705
|
+
};
|
|
706
|
+
} catch (err) {
|
|
707
|
+
if (isEsbuildBuildFailure(err)) {
|
|
708
|
+
const errors = err.errors.map((e) => convertEsbuildMessage(e));
|
|
709
|
+
const warnings = err.warnings.map((w) => convertEsbuildMessage(w));
|
|
710
|
+
return {
|
|
711
|
+
success: false,
|
|
712
|
+
errors,
|
|
713
|
+
warnings
|
|
714
|
+
};
|
|
715
|
+
}
|
|
716
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
717
|
+
return {
|
|
718
|
+
success: false,
|
|
719
|
+
errors: [{ text: message }],
|
|
720
|
+
warnings: []
|
|
721
|
+
};
|
|
722
|
+
}
|
|
723
|
+
}
|
|
652
724
|
|
|
653
725
|
// src/browser/bundler.ts
|
|
654
726
|
var ESBUILD_VERSION = "0.27.2";
|
|
@@ -729,75 +801,12 @@ To enable, add these headers to your server:
|
|
|
729
801
|
}
|
|
730
802
|
async bundle(options) {
|
|
731
803
|
await this.initialize();
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
entryPoint,
|
|
736
|
-
installedPackages = {},
|
|
737
|
-
sharedModules = [],
|
|
738
|
-
sharedModuleRegistry,
|
|
739
|
-
external = [],
|
|
740
|
-
format = "esm",
|
|
741
|
-
minify = false,
|
|
742
|
-
sourcemap = false,
|
|
743
|
-
target = ["es2020"]
|
|
744
|
-
} = options;
|
|
745
|
-
const normalizedEntry = entryPoint.startsWith("/") ? entryPoint : `/${entryPoint}`;
|
|
746
|
-
if (!fs.exists(normalizedEntry)) {
|
|
747
|
-
return {
|
|
748
|
-
success: false,
|
|
749
|
-
errors: [{ text: `Entry point not found: ${normalizedEntry}` }],
|
|
750
|
-
warnings: []
|
|
751
|
-
};
|
|
752
|
-
}
|
|
753
|
-
const includedFiles = new Set;
|
|
754
|
-
const plugin = createVfsPlugin({
|
|
755
|
-
fs,
|
|
756
|
-
entryPoint: normalizedEntry,
|
|
757
|
-
installedPackages,
|
|
758
|
-
sharedModules: new Set(sharedModules),
|
|
759
|
-
sharedModuleRegistry: sharedModuleRegistry ?? null,
|
|
804
|
+
return executeBundleWithEsbuild({
|
|
805
|
+
esbuild: this.getEsbuild(),
|
|
806
|
+
bundleOptions: options,
|
|
760
807
|
cdnBaseUrl: this.options.cdnBaseUrl,
|
|
761
|
-
|
|
808
|
+
bundleCdnImports: false
|
|
762
809
|
});
|
|
763
|
-
try {
|
|
764
|
-
const result = await esbuild.build({
|
|
765
|
-
entryPoints: [normalizedEntry],
|
|
766
|
-
bundle: true,
|
|
767
|
-
write: false,
|
|
768
|
-
format,
|
|
769
|
-
minify,
|
|
770
|
-
sourcemap: sourcemap ? "inline" : false,
|
|
771
|
-
target,
|
|
772
|
-
external,
|
|
773
|
-
plugins: [plugin],
|
|
774
|
-
jsx: "automatic"
|
|
775
|
-
});
|
|
776
|
-
const code = result.outputFiles?.[0]?.text ?? "";
|
|
777
|
-
const warnings = result.warnings.map((w) => convertEsbuildMessage(w));
|
|
778
|
-
return {
|
|
779
|
-
success: true,
|
|
780
|
-
code,
|
|
781
|
-
warnings,
|
|
782
|
-
includedFiles: Array.from(includedFiles)
|
|
783
|
-
};
|
|
784
|
-
} catch (err) {
|
|
785
|
-
if (isEsbuildBuildFailure(err)) {
|
|
786
|
-
const errors = err.errors.map((e) => convertEsbuildMessage(e));
|
|
787
|
-
const warnings = err.warnings.map((w) => convertEsbuildMessage(w));
|
|
788
|
-
return {
|
|
789
|
-
success: false,
|
|
790
|
-
errors,
|
|
791
|
-
warnings
|
|
792
|
-
};
|
|
793
|
-
}
|
|
794
|
-
const message = err instanceof Error ? err.message : String(err);
|
|
795
|
-
return {
|
|
796
|
-
success: false,
|
|
797
|
-
errors: [{ text: message }],
|
|
798
|
-
warnings: []
|
|
799
|
-
};
|
|
800
|
-
}
|
|
801
810
|
}
|
|
802
811
|
}
|
|
803
812
|
// src/core/executor.ts
|
|
@@ -2369,6 +2378,64 @@ async function createSandboxImpl(fs, options, context) {
|
|
|
2369
2378
|
if (!fs.exists(TSCONFIG_PATH)) {
|
|
2370
2379
|
fs.writeFile(TSCONFIG_PATH, JSON.stringify(DEFAULT_TSCONFIG, null, 2));
|
|
2371
2380
|
}
|
|
2381
|
+
if (sharedModuleRegistry && typesResolver) {
|
|
2382
|
+
const sharedModuleIds = sharedModuleRegistry.list();
|
|
2383
|
+
const typesFetches = sharedModuleIds.map(async (moduleId) => {
|
|
2384
|
+
try {
|
|
2385
|
+
const typeFiles = await typesResolver.resolveTypes(moduleId);
|
|
2386
|
+
return { moduleId, typeFiles, error: null };
|
|
2387
|
+
} catch (err) {
|
|
2388
|
+
console.warn(`[sandlot] Failed to fetch types for shared module "${moduleId}":`, err);
|
|
2389
|
+
return { moduleId, typeFiles: {}, error: err };
|
|
2390
|
+
}
|
|
2391
|
+
});
|
|
2392
|
+
const results = await Promise.all(typesFetches);
|
|
2393
|
+
for (const { moduleId, typeFiles } of results) {
|
|
2394
|
+
if (Object.keys(typeFiles).length === 0)
|
|
2395
|
+
continue;
|
|
2396
|
+
let packageName = moduleId;
|
|
2397
|
+
let subpath;
|
|
2398
|
+
if (moduleId.startsWith("@")) {
|
|
2399
|
+
const parts = moduleId.split("/");
|
|
2400
|
+
if (parts.length >= 2) {
|
|
2401
|
+
packageName = `${parts[0]}/${parts[1]}`;
|
|
2402
|
+
subpath = parts.length > 2 ? parts.slice(2).join("/") : undefined;
|
|
2403
|
+
}
|
|
2404
|
+
} else {
|
|
2405
|
+
const slashIndex = moduleId.indexOf("/");
|
|
2406
|
+
if (slashIndex !== -1) {
|
|
2407
|
+
packageName = moduleId.slice(0, slashIndex);
|
|
2408
|
+
subpath = moduleId.slice(slashIndex + 1);
|
|
2409
|
+
}
|
|
2410
|
+
}
|
|
2411
|
+
const packageDir = `/node_modules/${packageName}`;
|
|
2412
|
+
let typesEntry = null;
|
|
2413
|
+
let fallbackEntry = null;
|
|
2414
|
+
for (const [filePath, content] of Object.entries(typeFiles)) {
|
|
2415
|
+
const fullPath = filePath.startsWith("/") ? filePath : `${packageDir}/${filePath}`;
|
|
2416
|
+
const dir = fullPath.substring(0, fullPath.lastIndexOf("/"));
|
|
2417
|
+
ensureDir(fs, dir);
|
|
2418
|
+
fs.writeFile(fullPath, content);
|
|
2419
|
+
const relativePath = fullPath.replace(`${packageDir}/`, "");
|
|
2420
|
+
if (relativePath === "index.d.ts") {
|
|
2421
|
+
typesEntry = "index.d.ts";
|
|
2422
|
+
} else if (!fallbackEntry && relativePath.endsWith(".d.ts") && !relativePath.includes("/")) {
|
|
2423
|
+
fallbackEntry = relativePath;
|
|
2424
|
+
}
|
|
2425
|
+
}
|
|
2426
|
+
const finalTypesEntry = typesEntry ?? fallbackEntry ?? "index.d.ts";
|
|
2427
|
+
const pkgJsonPath = `${packageDir}/package.json`;
|
|
2428
|
+
if (!fs.exists(pkgJsonPath)) {
|
|
2429
|
+
const pkgJson = {
|
|
2430
|
+
name: packageName,
|
|
2431
|
+
version: "shared",
|
|
2432
|
+
types: finalTypesEntry,
|
|
2433
|
+
main: finalTypesEntry.replace(/\.d\.ts$/, ".js")
|
|
2434
|
+
};
|
|
2435
|
+
fs.writeFile(pkgJsonPath, JSON.stringify(pkgJson, null, 2));
|
|
2436
|
+
}
|
|
2437
|
+
}
|
|
2438
|
+
}
|
|
2372
2439
|
async function install(packageSpec) {
|
|
2373
2440
|
const { name, version } = parsePackageSpec(packageSpec);
|
|
2374
2441
|
let resolvedVersion = version ?? "latest";
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* This module contains the VFS plugin, path resolution, and shared module
|
|
5
5
|
* code generation logic that is common to both esbuild and esbuild-wasm.
|
|
6
6
|
*/
|
|
7
|
-
import type { ISharedModuleRegistry, BundleWarning, BundleError, Filesystem } from "../types";
|
|
7
|
+
import type { ISharedModuleRegistry, BundleOptions, BundleResult, BundleWarning, BundleError, Filesystem } from "../types";
|
|
8
8
|
/**
|
|
9
9
|
* Minimal esbuild types needed for the shared utilities.
|
|
10
10
|
* These are compatible with both esbuild and esbuild-wasm.
|
|
@@ -139,4 +139,46 @@ export declare function getLoader(path: string): EsbuildLoader;
|
|
|
139
139
|
* Generate JavaScript code that accesses a shared module at runtime.
|
|
140
140
|
*/
|
|
141
141
|
export declare function generateSharedModuleCode(moduleId: string, registry: ISharedModuleRegistry | null): string;
|
|
142
|
+
/**
|
|
143
|
+
* Minimal esbuild interface needed for bundling.
|
|
144
|
+
* Compatible with both esbuild and esbuild-wasm.
|
|
145
|
+
*
|
|
146
|
+
* Uses a loose `Record<string, unknown>` for build options to avoid
|
|
147
|
+
* type conflicts between the various esbuild module signatures.
|
|
148
|
+
*/
|
|
149
|
+
export interface EsbuildInstance {
|
|
150
|
+
build(options: Record<string, unknown>): Promise<{
|
|
151
|
+
outputFiles?: Array<{
|
|
152
|
+
text: string;
|
|
153
|
+
}>;
|
|
154
|
+
warnings: EsbuildMessage[];
|
|
155
|
+
}>;
|
|
156
|
+
}
|
|
157
|
+
/**
|
|
158
|
+
* Options for the shared bundle execution helper.
|
|
159
|
+
*/
|
|
160
|
+
export interface ExecuteBundleOptions {
|
|
161
|
+
/** The esbuild instance to use */
|
|
162
|
+
esbuild: EsbuildInstance;
|
|
163
|
+
/** Bundle options from the IBundler interface */
|
|
164
|
+
bundleOptions: BundleOptions;
|
|
165
|
+
/** Base URL for CDN imports */
|
|
166
|
+
cdnBaseUrl: string;
|
|
167
|
+
/**
|
|
168
|
+
* Whether to bundle CDN imports inline.
|
|
169
|
+
* - Browser: false (external) - browser can fetch at runtime
|
|
170
|
+
* - Node/Bun: true (bundle) - esbuild fetches during build
|
|
171
|
+
*/
|
|
172
|
+
bundleCdnImports: boolean;
|
|
173
|
+
}
|
|
174
|
+
/**
|
|
175
|
+
* Execute a bundle using esbuild with the VFS plugin.
|
|
176
|
+
*
|
|
177
|
+
* This is the shared implementation used by both browser and node WASM bundlers.
|
|
178
|
+
* It handles entry point normalization, VFS plugin creation, and error handling.
|
|
179
|
+
*
|
|
180
|
+
* @param options - Bundle execution options
|
|
181
|
+
* @returns Bundle result with code or errors
|
|
182
|
+
*/
|
|
183
|
+
export declare function executeBundleWithEsbuild(options: ExecuteBundleOptions): Promise<BundleResult>;
|
|
142
184
|
//# sourceMappingURL=bundler-utils.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bundler-utils.d.ts","sourceRoot":"","sources":["../../src/core/bundler-utils.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"bundler-utils.d.ts","sourceRoot":"","sources":["../../src/core/bundler-utils.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sandbox.d.ts","sourceRoot":"","sources":["../../src/core/sandbox.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAGH,OAAO,KAAK,EACV,QAAQ,EACR,YAAY,EACZ,cAAc,EACd,qBAAqB,EACrB,SAAS,EACT,OAAO,EACP,cAAc,EAYf,MAAM,UAAU,CAAC;AAClB,OAAO,EAAE,UAAU,EAA6B,MAAM,MAAM,CAAC;AA2J7D,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,QAAQ,CAAC;IAClB,WAAW,CAAC,EAAE,YAAY,CAAC;IAC3B,aAAa,CAAC,EAAE,cAAc,CAAC;IAC/B,oBAAoB,EAAE,qBAAqB,GAAG,IAAI,CAAC;IACnD,QAAQ,CAAC,EAAE,SAAS,CAAC;CACtB;AAMD;;;GAGG;AACH,wBAAsB,iBAAiB,CACrC,EAAE,EAAE,UAAU,EACd,OAAO,EAAE,cAAc,EACvB,OAAO,EAAE,cAAc,GACtB,OAAO,CAAC,OAAO,CAAC,
|
|
1
|
+
{"version":3,"file":"sandbox.d.ts","sourceRoot":"","sources":["../../src/core/sandbox.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAGH,OAAO,KAAK,EACV,QAAQ,EACR,YAAY,EACZ,cAAc,EACd,qBAAqB,EACrB,SAAS,EACT,OAAO,EACP,cAAc,EAYf,MAAM,UAAU,CAAC;AAClB,OAAO,EAAE,UAAU,EAA6B,MAAM,MAAM,CAAC;AA2J7D,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,QAAQ,CAAC;IAClB,WAAW,CAAC,EAAE,YAAY,CAAC;IAC3B,aAAa,CAAC,EAAE,cAAc,CAAC;IAC/B,oBAAoB,EAAE,qBAAqB,GAAG,IAAI,CAAC;IACnD,QAAQ,CAAC,EAAE,SAAS,CAAC;CACtB;AAMD;;;GAGG;AACH,wBAAsB,iBAAiB,CACrC,EAAE,EAAE,UAAU,EACd,OAAO,EAAE,cAAc,EACvB,OAAO,EAAE,cAAc,GACtB,OAAO,CAAC,OAAO,CAAC,CA6elB"}
|
package/dist/index.js
CHANGED
|
@@ -1283,6 +1283,64 @@ async function createSandboxImpl(fs, options, context) {
|
|
|
1283
1283
|
if (!fs.exists(TSCONFIG_PATH)) {
|
|
1284
1284
|
fs.writeFile(TSCONFIG_PATH, JSON.stringify(DEFAULT_TSCONFIG, null, 2));
|
|
1285
1285
|
}
|
|
1286
|
+
if (sharedModuleRegistry && typesResolver) {
|
|
1287
|
+
const sharedModuleIds = sharedModuleRegistry.list();
|
|
1288
|
+
const typesFetches = sharedModuleIds.map(async (moduleId) => {
|
|
1289
|
+
try {
|
|
1290
|
+
const typeFiles = await typesResolver.resolveTypes(moduleId);
|
|
1291
|
+
return { moduleId, typeFiles, error: null };
|
|
1292
|
+
} catch (err) {
|
|
1293
|
+
console.warn(`[sandlot] Failed to fetch types for shared module "${moduleId}":`, err);
|
|
1294
|
+
return { moduleId, typeFiles: {}, error: err };
|
|
1295
|
+
}
|
|
1296
|
+
});
|
|
1297
|
+
const results = await Promise.all(typesFetches);
|
|
1298
|
+
for (const { moduleId, typeFiles } of results) {
|
|
1299
|
+
if (Object.keys(typeFiles).length === 0)
|
|
1300
|
+
continue;
|
|
1301
|
+
let packageName = moduleId;
|
|
1302
|
+
let subpath;
|
|
1303
|
+
if (moduleId.startsWith("@")) {
|
|
1304
|
+
const parts = moduleId.split("/");
|
|
1305
|
+
if (parts.length >= 2) {
|
|
1306
|
+
packageName = `${parts[0]}/${parts[1]}`;
|
|
1307
|
+
subpath = parts.length > 2 ? parts.slice(2).join("/") : undefined;
|
|
1308
|
+
}
|
|
1309
|
+
} else {
|
|
1310
|
+
const slashIndex = moduleId.indexOf("/");
|
|
1311
|
+
if (slashIndex !== -1) {
|
|
1312
|
+
packageName = moduleId.slice(0, slashIndex);
|
|
1313
|
+
subpath = moduleId.slice(slashIndex + 1);
|
|
1314
|
+
}
|
|
1315
|
+
}
|
|
1316
|
+
const packageDir = `/node_modules/${packageName}`;
|
|
1317
|
+
let typesEntry = null;
|
|
1318
|
+
let fallbackEntry = null;
|
|
1319
|
+
for (const [filePath, content] of Object.entries(typeFiles)) {
|
|
1320
|
+
const fullPath = filePath.startsWith("/") ? filePath : `${packageDir}/${filePath}`;
|
|
1321
|
+
const dir = fullPath.substring(0, fullPath.lastIndexOf("/"));
|
|
1322
|
+
ensureDir(fs, dir);
|
|
1323
|
+
fs.writeFile(fullPath, content);
|
|
1324
|
+
const relativePath = fullPath.replace(`${packageDir}/`, "");
|
|
1325
|
+
if (relativePath === "index.d.ts") {
|
|
1326
|
+
typesEntry = "index.d.ts";
|
|
1327
|
+
} else if (!fallbackEntry && relativePath.endsWith(".d.ts") && !relativePath.includes("/")) {
|
|
1328
|
+
fallbackEntry = relativePath;
|
|
1329
|
+
}
|
|
1330
|
+
}
|
|
1331
|
+
const finalTypesEntry = typesEntry ?? fallbackEntry ?? "index.d.ts";
|
|
1332
|
+
const pkgJsonPath = `${packageDir}/package.json`;
|
|
1333
|
+
if (!fs.exists(pkgJsonPath)) {
|
|
1334
|
+
const pkgJson = {
|
|
1335
|
+
name: packageName,
|
|
1336
|
+
version: "shared",
|
|
1337
|
+
types: finalTypesEntry,
|
|
1338
|
+
main: finalTypesEntry.replace(/\.d\.ts$/, ".js")
|
|
1339
|
+
};
|
|
1340
|
+
fs.writeFile(pkgJsonPath, JSON.stringify(pkgJson, null, 2));
|
|
1341
|
+
}
|
|
1342
|
+
}
|
|
1343
|
+
}
|
|
1286
1344
|
async function install(packageSpec) {
|
|
1287
1345
|
const { name, version } = parsePackageSpec(packageSpec);
|
|
1288
1346
|
let resolvedVersion = version ?? "latest";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bundler.d.ts","sourceRoot":"","sources":["../../src/node/bundler.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"bundler.d.ts","sourceRoot":"","sources":["../../src/node/bundler.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,KAAK,EAAE,QAAQ,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AAGtE,MAAM,WAAW,2BAA2B;IAC1C;;;;OAIG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED;;;;;;;;;;;;;;;GAeG;AACH,qBAAa,oBAAqB,YAAW,QAAQ;IACnD,OAAO,CAAC,OAAO,CAA8B;IAC7C,OAAO,CAAC,OAAO,CAAoC;gBAEvC,OAAO,GAAE,2BAAgC;IAOrD;;;OAGG;IACG,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAUjC,OAAO,CAAC,UAAU;IAOlB;;;OAGG;IACG,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAOxB,MAAM,CAAC,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,YAAY,CAAC;CAY5D;AAED;;GAEG;AACH,wBAAgB,0BAA0B,CACxC,OAAO,CAAC,EAAE,2BAA2B,GACpC,oBAAoB,CAEtB"}
|
package/dist/node/index.js
CHANGED
|
@@ -319,6 +319,78 @@ function generateSharedModuleCode(moduleId, registry) {
|
|
|
319
319
|
}
|
|
320
320
|
return code;
|
|
321
321
|
}
|
|
322
|
+
async function executeBundleWithEsbuild(options) {
|
|
323
|
+
const { esbuild, bundleOptions, cdnBaseUrl, bundleCdnImports } = options;
|
|
324
|
+
const {
|
|
325
|
+
fs,
|
|
326
|
+
entryPoint,
|
|
327
|
+
installedPackages = {},
|
|
328
|
+
sharedModules = [],
|
|
329
|
+
sharedModuleRegistry,
|
|
330
|
+
external = [],
|
|
331
|
+
format = "esm",
|
|
332
|
+
minify = false,
|
|
333
|
+
sourcemap = false,
|
|
334
|
+
target = ["es2020"]
|
|
335
|
+
} = bundleOptions;
|
|
336
|
+
const normalizedEntry = entryPoint.startsWith("/") ? entryPoint : `/${entryPoint}`;
|
|
337
|
+
if (!fs.exists(normalizedEntry)) {
|
|
338
|
+
return {
|
|
339
|
+
success: false,
|
|
340
|
+
errors: [{ text: `Entry point not found: ${normalizedEntry}` }],
|
|
341
|
+
warnings: []
|
|
342
|
+
};
|
|
343
|
+
}
|
|
344
|
+
const includedFiles = new Set;
|
|
345
|
+
const plugin = createVfsPlugin({
|
|
346
|
+
fs,
|
|
347
|
+
entryPoint: normalizedEntry,
|
|
348
|
+
installedPackages,
|
|
349
|
+
sharedModules: new Set(sharedModules),
|
|
350
|
+
sharedModuleRegistry: sharedModuleRegistry ?? null,
|
|
351
|
+
cdnBaseUrl,
|
|
352
|
+
includedFiles,
|
|
353
|
+
bundleCdnImports
|
|
354
|
+
});
|
|
355
|
+
try {
|
|
356
|
+
const result = await esbuild.build({
|
|
357
|
+
entryPoints: [normalizedEntry],
|
|
358
|
+
bundle: true,
|
|
359
|
+
write: false,
|
|
360
|
+
format,
|
|
361
|
+
minify,
|
|
362
|
+
sourcemap: sourcemap ? "inline" : false,
|
|
363
|
+
target,
|
|
364
|
+
external,
|
|
365
|
+
plugins: [plugin],
|
|
366
|
+
jsx: "automatic"
|
|
367
|
+
});
|
|
368
|
+
const code = result.outputFiles?.[0]?.text ?? "";
|
|
369
|
+
const warnings = result.warnings.map((w) => convertEsbuildMessage(w));
|
|
370
|
+
return {
|
|
371
|
+
success: true,
|
|
372
|
+
code,
|
|
373
|
+
warnings,
|
|
374
|
+
includedFiles: Array.from(includedFiles)
|
|
375
|
+
};
|
|
376
|
+
} catch (err) {
|
|
377
|
+
if (isEsbuildBuildFailure(err)) {
|
|
378
|
+
const errors = err.errors.map((e) => convertEsbuildMessage(e));
|
|
379
|
+
const warnings = err.warnings.map((w) => convertEsbuildMessage(w));
|
|
380
|
+
return {
|
|
381
|
+
success: false,
|
|
382
|
+
errors,
|
|
383
|
+
warnings
|
|
384
|
+
};
|
|
385
|
+
}
|
|
386
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
387
|
+
return {
|
|
388
|
+
success: false,
|
|
389
|
+
errors: [{ text: message }],
|
|
390
|
+
warnings: []
|
|
391
|
+
};
|
|
392
|
+
}
|
|
393
|
+
}
|
|
322
394
|
|
|
323
395
|
// src/node/bundler.ts
|
|
324
396
|
class EsbuildNativeBundler {
|
|
@@ -350,76 +422,12 @@ class EsbuildNativeBundler {
|
|
|
350
422
|
}
|
|
351
423
|
async bundle(options) {
|
|
352
424
|
await this.initialize();
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
entryPoint,
|
|
357
|
-
installedPackages = {},
|
|
358
|
-
sharedModules = [],
|
|
359
|
-
sharedModuleRegistry,
|
|
360
|
-
external = [],
|
|
361
|
-
format = "esm",
|
|
362
|
-
minify = false,
|
|
363
|
-
sourcemap = false,
|
|
364
|
-
target = ["es2020"]
|
|
365
|
-
} = options;
|
|
366
|
-
const normalizedEntry = entryPoint.startsWith("/") ? entryPoint : `/${entryPoint}`;
|
|
367
|
-
if (!fs.exists(normalizedEntry)) {
|
|
368
|
-
return {
|
|
369
|
-
success: false,
|
|
370
|
-
errors: [{ text: `Entry point not found: ${normalizedEntry}` }],
|
|
371
|
-
warnings: []
|
|
372
|
-
};
|
|
373
|
-
}
|
|
374
|
-
const includedFiles = new Set;
|
|
375
|
-
const plugin = createVfsPlugin({
|
|
376
|
-
fs,
|
|
377
|
-
entryPoint: normalizedEntry,
|
|
378
|
-
installedPackages,
|
|
379
|
-
sharedModules: new Set(sharedModules),
|
|
380
|
-
sharedModuleRegistry: sharedModuleRegistry ?? null,
|
|
425
|
+
return executeBundleWithEsbuild({
|
|
426
|
+
esbuild: this.getEsbuild(),
|
|
427
|
+
bundleOptions: options,
|
|
381
428
|
cdnBaseUrl: this.options.cdnBaseUrl,
|
|
382
|
-
includedFiles,
|
|
383
429
|
bundleCdnImports: true
|
|
384
430
|
});
|
|
385
|
-
try {
|
|
386
|
-
const result = await esbuild.build({
|
|
387
|
-
entryPoints: [normalizedEntry],
|
|
388
|
-
bundle: true,
|
|
389
|
-
write: false,
|
|
390
|
-
format,
|
|
391
|
-
minify,
|
|
392
|
-
sourcemap: sourcemap ? "inline" : false,
|
|
393
|
-
target,
|
|
394
|
-
external,
|
|
395
|
-
plugins: [plugin],
|
|
396
|
-
jsx: "automatic"
|
|
397
|
-
});
|
|
398
|
-
const code = result.outputFiles?.[0]?.text ?? "";
|
|
399
|
-
const warnings = result.warnings.map((w) => convertEsbuildMessage(w));
|
|
400
|
-
return {
|
|
401
|
-
success: true,
|
|
402
|
-
code,
|
|
403
|
-
warnings,
|
|
404
|
-
includedFiles: Array.from(includedFiles)
|
|
405
|
-
};
|
|
406
|
-
} catch (err) {
|
|
407
|
-
if (isEsbuildBuildFailure(err)) {
|
|
408
|
-
const errors = err.errors.map((e) => convertEsbuildMessage(e));
|
|
409
|
-
const warnings = err.warnings.map((w) => convertEsbuildMessage(w));
|
|
410
|
-
return {
|
|
411
|
-
success: false,
|
|
412
|
-
errors,
|
|
413
|
-
warnings
|
|
414
|
-
};
|
|
415
|
-
}
|
|
416
|
-
const message = err instanceof Error ? err.message : String(err);
|
|
417
|
-
return {
|
|
418
|
-
success: false,
|
|
419
|
-
errors: [{ text: message }],
|
|
420
|
-
warnings: []
|
|
421
|
-
};
|
|
422
|
-
}
|
|
423
431
|
}
|
|
424
432
|
}
|
|
425
433
|
function createEsbuildNativeBundler(options) {
|
|
@@ -486,76 +494,12 @@ class EsbuildWasmNodeBundler {
|
|
|
486
494
|
}
|
|
487
495
|
async bundle(options) {
|
|
488
496
|
await this.initialize();
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
entryPoint,
|
|
493
|
-
installedPackages = {},
|
|
494
|
-
sharedModules = [],
|
|
495
|
-
sharedModuleRegistry,
|
|
496
|
-
external = [],
|
|
497
|
-
format = "esm",
|
|
498
|
-
minify = false,
|
|
499
|
-
sourcemap = false,
|
|
500
|
-
target = ["es2020"]
|
|
501
|
-
} = options;
|
|
502
|
-
const normalizedEntry = entryPoint.startsWith("/") ? entryPoint : `/${entryPoint}`;
|
|
503
|
-
if (!fs.exists(normalizedEntry)) {
|
|
504
|
-
return {
|
|
505
|
-
success: false,
|
|
506
|
-
errors: [{ text: `Entry point not found: ${normalizedEntry}` }],
|
|
507
|
-
warnings: []
|
|
508
|
-
};
|
|
509
|
-
}
|
|
510
|
-
const includedFiles = new Set;
|
|
511
|
-
const plugin = createVfsPlugin({
|
|
512
|
-
fs,
|
|
513
|
-
entryPoint: normalizedEntry,
|
|
514
|
-
installedPackages,
|
|
515
|
-
sharedModules: new Set(sharedModules),
|
|
516
|
-
sharedModuleRegistry: sharedModuleRegistry ?? null,
|
|
497
|
+
return executeBundleWithEsbuild({
|
|
498
|
+
esbuild: this.getEsbuild(),
|
|
499
|
+
bundleOptions: options,
|
|
517
500
|
cdnBaseUrl: this.options.cdnBaseUrl,
|
|
518
|
-
includedFiles,
|
|
519
501
|
bundleCdnImports: true
|
|
520
502
|
});
|
|
521
|
-
try {
|
|
522
|
-
const result = await esbuild.build({
|
|
523
|
-
entryPoints: [normalizedEntry],
|
|
524
|
-
bundle: true,
|
|
525
|
-
write: false,
|
|
526
|
-
format,
|
|
527
|
-
minify,
|
|
528
|
-
sourcemap: sourcemap ? "inline" : false,
|
|
529
|
-
target,
|
|
530
|
-
external,
|
|
531
|
-
plugins: [plugin],
|
|
532
|
-
jsx: "automatic"
|
|
533
|
-
});
|
|
534
|
-
const code = result.outputFiles?.[0]?.text ?? "";
|
|
535
|
-
const warnings = result.warnings.map((w) => convertEsbuildMessage(w));
|
|
536
|
-
return {
|
|
537
|
-
success: true,
|
|
538
|
-
code,
|
|
539
|
-
warnings,
|
|
540
|
-
includedFiles: Array.from(includedFiles)
|
|
541
|
-
};
|
|
542
|
-
} catch (err) {
|
|
543
|
-
if (isEsbuildBuildFailure(err)) {
|
|
544
|
-
const errors = err.errors.map((e) => convertEsbuildMessage(e));
|
|
545
|
-
const warnings = err.warnings.map((w) => convertEsbuildMessage(w));
|
|
546
|
-
return {
|
|
547
|
-
success: false,
|
|
548
|
-
errors,
|
|
549
|
-
warnings
|
|
550
|
-
};
|
|
551
|
-
}
|
|
552
|
-
const message = err instanceof Error ? err.message : String(err);
|
|
553
|
-
return {
|
|
554
|
-
success: false,
|
|
555
|
-
errors: [{ text: message }],
|
|
556
|
-
warnings: []
|
|
557
|
-
};
|
|
558
|
-
}
|
|
559
503
|
}
|
|
560
504
|
}
|
|
561
505
|
function createEsbuildWasmNodeBundler(options) {
|
|
@@ -2291,6 +2235,64 @@ async function createSandboxImpl(fs, options, context) {
|
|
|
2291
2235
|
if (!fs.exists(TSCONFIG_PATH)) {
|
|
2292
2236
|
fs.writeFile(TSCONFIG_PATH, JSON.stringify(DEFAULT_TSCONFIG, null, 2));
|
|
2293
2237
|
}
|
|
2238
|
+
if (sharedModuleRegistry && typesResolver) {
|
|
2239
|
+
const sharedModuleIds = sharedModuleRegistry.list();
|
|
2240
|
+
const typesFetches = sharedModuleIds.map(async (moduleId) => {
|
|
2241
|
+
try {
|
|
2242
|
+
const typeFiles = await typesResolver.resolveTypes(moduleId);
|
|
2243
|
+
return { moduleId, typeFiles, error: null };
|
|
2244
|
+
} catch (err) {
|
|
2245
|
+
console.warn(`[sandlot] Failed to fetch types for shared module "${moduleId}":`, err);
|
|
2246
|
+
return { moduleId, typeFiles: {}, error: err };
|
|
2247
|
+
}
|
|
2248
|
+
});
|
|
2249
|
+
const results = await Promise.all(typesFetches);
|
|
2250
|
+
for (const { moduleId, typeFiles } of results) {
|
|
2251
|
+
if (Object.keys(typeFiles).length === 0)
|
|
2252
|
+
continue;
|
|
2253
|
+
let packageName = moduleId;
|
|
2254
|
+
let subpath;
|
|
2255
|
+
if (moduleId.startsWith("@")) {
|
|
2256
|
+
const parts = moduleId.split("/");
|
|
2257
|
+
if (parts.length >= 2) {
|
|
2258
|
+
packageName = `${parts[0]}/${parts[1]}`;
|
|
2259
|
+
subpath = parts.length > 2 ? parts.slice(2).join("/") : undefined;
|
|
2260
|
+
}
|
|
2261
|
+
} else {
|
|
2262
|
+
const slashIndex = moduleId.indexOf("/");
|
|
2263
|
+
if (slashIndex !== -1) {
|
|
2264
|
+
packageName = moduleId.slice(0, slashIndex);
|
|
2265
|
+
subpath = moduleId.slice(slashIndex + 1);
|
|
2266
|
+
}
|
|
2267
|
+
}
|
|
2268
|
+
const packageDir = `/node_modules/${packageName}`;
|
|
2269
|
+
let typesEntry = null;
|
|
2270
|
+
let fallbackEntry = null;
|
|
2271
|
+
for (const [filePath, content] of Object.entries(typeFiles)) {
|
|
2272
|
+
const fullPath = filePath.startsWith("/") ? filePath : `${packageDir}/${filePath}`;
|
|
2273
|
+
const dir = fullPath.substring(0, fullPath.lastIndexOf("/"));
|
|
2274
|
+
ensureDir(fs, dir);
|
|
2275
|
+
fs.writeFile(fullPath, content);
|
|
2276
|
+
const relativePath = fullPath.replace(`${packageDir}/`, "");
|
|
2277
|
+
if (relativePath === "index.d.ts") {
|
|
2278
|
+
typesEntry = "index.d.ts";
|
|
2279
|
+
} else if (!fallbackEntry && relativePath.endsWith(".d.ts") && !relativePath.includes("/")) {
|
|
2280
|
+
fallbackEntry = relativePath;
|
|
2281
|
+
}
|
|
2282
|
+
}
|
|
2283
|
+
const finalTypesEntry = typesEntry ?? fallbackEntry ?? "index.d.ts";
|
|
2284
|
+
const pkgJsonPath = `${packageDir}/package.json`;
|
|
2285
|
+
if (!fs.exists(pkgJsonPath)) {
|
|
2286
|
+
const pkgJson = {
|
|
2287
|
+
name: packageName,
|
|
2288
|
+
version: "shared",
|
|
2289
|
+
types: finalTypesEntry,
|
|
2290
|
+
main: finalTypesEntry.replace(/\.d\.ts$/, ".js")
|
|
2291
|
+
};
|
|
2292
|
+
fs.writeFile(pkgJsonPath, JSON.stringify(pkgJson, null, 2));
|
|
2293
|
+
}
|
|
2294
|
+
}
|
|
2295
|
+
}
|
|
2294
2296
|
async function install(packageSpec) {
|
|
2295
2297
|
const { name, version } = parsePackageSpec(packageSpec);
|
|
2296
2298
|
let resolvedVersion = version ?? "latest";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"wasm-bundler.d.ts","sourceRoot":"","sources":["../../src/node/wasm-bundler.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAGH,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"wasm-bundler.d.ts","sourceRoot":"","sources":["../../src/node/wasm-bundler.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAGH,OAAO,KAAK,EAAE,QAAQ,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AAgCtE,MAAM,WAAW,6BAA6B;IAC5C;;;;OAIG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AACH,qBAAa,sBAAuB,YAAW,QAAQ;IACrD,OAAO,CAAC,OAAO,CAAgC;gBAEnC,OAAO,GAAE,6BAAkC;IAOvD;;;;;;OAMG;IACG,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;YAmBnB,YAAY;IAoB1B;;OAEG;IACH,OAAO,CAAC,UAAU;IAQlB;;;;;;OAMG;IACG,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAUxB,MAAM,CAAC,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,YAAY,CAAC;CAY5D;AAED;;;;;GAKG;AACH,wBAAgB,4BAA4B,CAC1C,OAAO,CAAC,EAAE,6BAA6B,GACtC,sBAAsB,CAExB"}
|
package/package.json
CHANGED
package/src/browser/bundler.ts
CHANGED
|
@@ -6,18 +6,8 @@
|
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
8
|
import type * as EsbuildTypes from "esbuild-wasm";
|
|
9
|
-
import type {
|
|
10
|
-
|
|
11
|
-
BundleOptions,
|
|
12
|
-
BundleResult,
|
|
13
|
-
BundleWarning,
|
|
14
|
-
BundleError,
|
|
15
|
-
} from "../types";
|
|
16
|
-
import {
|
|
17
|
-
createVfsPlugin,
|
|
18
|
-
isEsbuildBuildFailure,
|
|
19
|
-
convertEsbuildMessage,
|
|
20
|
-
} from "../core/bundler-utils";
|
|
9
|
+
import type { IBundler, BundleOptions, BundleResult } from "../types";
|
|
10
|
+
import { executeBundleWithEsbuild } from "../core/bundler-utils";
|
|
21
11
|
|
|
22
12
|
/**
|
|
23
13
|
* esbuild-wasm version - should match what's in package.json
|
|
@@ -211,101 +201,11 @@ export class EsbuildWasmBundler implements IBundler {
|
|
|
211
201
|
async bundle(options: BundleOptions): Promise<BundleResult> {
|
|
212
202
|
await this.initialize();
|
|
213
203
|
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
fs,
|
|
218
|
-
entryPoint,
|
|
219
|
-
installedPackages = {},
|
|
220
|
-
sharedModules = [],
|
|
221
|
-
sharedModuleRegistry,
|
|
222
|
-
external = [],
|
|
223
|
-
format = "esm",
|
|
224
|
-
minify = false,
|
|
225
|
-
sourcemap = false,
|
|
226
|
-
target = ["es2020"],
|
|
227
|
-
} = options;
|
|
228
|
-
|
|
229
|
-
// Normalize entry point to absolute path
|
|
230
|
-
const normalizedEntry = entryPoint.startsWith("/")
|
|
231
|
-
? entryPoint
|
|
232
|
-
: `/${entryPoint}`;
|
|
233
|
-
|
|
234
|
-
// Verify entry point exists
|
|
235
|
-
if (!fs.exists(normalizedEntry)) {
|
|
236
|
-
return {
|
|
237
|
-
success: false,
|
|
238
|
-
errors: [{ text: `Entry point not found: ${normalizedEntry}` }],
|
|
239
|
-
warnings: [],
|
|
240
|
-
};
|
|
241
|
-
}
|
|
242
|
-
|
|
243
|
-
// Track files included in the bundle
|
|
244
|
-
const includedFiles = new Set<string>();
|
|
245
|
-
|
|
246
|
-
// Create the VFS plugin
|
|
247
|
-
const plugin = createVfsPlugin({
|
|
248
|
-
fs,
|
|
249
|
-
entryPoint: normalizedEntry,
|
|
250
|
-
installedPackages,
|
|
251
|
-
sharedModules: new Set(sharedModules),
|
|
252
|
-
sharedModuleRegistry: sharedModuleRegistry ?? null,
|
|
204
|
+
return executeBundleWithEsbuild({
|
|
205
|
+
esbuild: this.getEsbuild(),
|
|
206
|
+
bundleOptions: options,
|
|
253
207
|
cdnBaseUrl: this.options.cdnBaseUrl!,
|
|
254
|
-
|
|
208
|
+
bundleCdnImports: false, // Browser can fetch CDN imports at runtime
|
|
255
209
|
});
|
|
256
|
-
|
|
257
|
-
try {
|
|
258
|
-
// Run esbuild
|
|
259
|
-
const result = await esbuild.build({
|
|
260
|
-
entryPoints: [normalizedEntry],
|
|
261
|
-
bundle: true,
|
|
262
|
-
write: false,
|
|
263
|
-
format,
|
|
264
|
-
minify,
|
|
265
|
-
sourcemap: sourcemap ? "inline" : false,
|
|
266
|
-
target,
|
|
267
|
-
external,
|
|
268
|
-
// Cast to esbuild's Plugin type since our minimal interface is compatible
|
|
269
|
-
plugins: [plugin as EsbuildTypes.Plugin],
|
|
270
|
-
jsx: "automatic",
|
|
271
|
-
});
|
|
272
|
-
|
|
273
|
-
const code = result.outputFiles?.[0]?.text ?? "";
|
|
274
|
-
|
|
275
|
-
// Convert esbuild warnings to our format
|
|
276
|
-
const warnings: BundleWarning[] = result.warnings.map((w) =>
|
|
277
|
-
convertEsbuildMessage(w)
|
|
278
|
-
);
|
|
279
|
-
|
|
280
|
-
return {
|
|
281
|
-
success: true,
|
|
282
|
-
code,
|
|
283
|
-
warnings,
|
|
284
|
-
includedFiles: Array.from(includedFiles),
|
|
285
|
-
};
|
|
286
|
-
} catch (err) {
|
|
287
|
-
// esbuild throws BuildFailure with .errors array
|
|
288
|
-
if (isEsbuildBuildFailure(err)) {
|
|
289
|
-
const errors: BundleError[] = err.errors.map((e) =>
|
|
290
|
-
convertEsbuildMessage(e)
|
|
291
|
-
);
|
|
292
|
-
const warnings: BundleWarning[] = err.warnings.map((w) =>
|
|
293
|
-
convertEsbuildMessage(w)
|
|
294
|
-
);
|
|
295
|
-
return {
|
|
296
|
-
success: false,
|
|
297
|
-
errors,
|
|
298
|
-
warnings,
|
|
299
|
-
};
|
|
300
|
-
}
|
|
301
|
-
|
|
302
|
-
// Unknown error - wrap it
|
|
303
|
-
const message = err instanceof Error ? err.message : String(err);
|
|
304
|
-
return {
|
|
305
|
-
success: false,
|
|
306
|
-
errors: [{ text: message }],
|
|
307
|
-
warnings: [],
|
|
308
|
-
};
|
|
309
|
-
}
|
|
310
210
|
}
|
|
311
211
|
}
|
|
@@ -7,6 +7,8 @@
|
|
|
7
7
|
|
|
8
8
|
import type {
|
|
9
9
|
ISharedModuleRegistry,
|
|
10
|
+
BundleOptions,
|
|
11
|
+
BundleResult,
|
|
10
12
|
BundleWarning,
|
|
11
13
|
BundleError,
|
|
12
14
|
BundleLocation,
|
|
@@ -628,3 +630,149 @@ export function generateSharedModuleCode(
|
|
|
628
630
|
|
|
629
631
|
return code;
|
|
630
632
|
}
|
|
633
|
+
|
|
634
|
+
// =============================================================================
|
|
635
|
+
// Shared Bundle Execution
|
|
636
|
+
// =============================================================================
|
|
637
|
+
|
|
638
|
+
/**
|
|
639
|
+
* Minimal esbuild interface needed for bundling.
|
|
640
|
+
* Compatible with both esbuild and esbuild-wasm.
|
|
641
|
+
*
|
|
642
|
+
* Uses a loose `Record<string, unknown>` for build options to avoid
|
|
643
|
+
* type conflicts between the various esbuild module signatures.
|
|
644
|
+
*/
|
|
645
|
+
export interface EsbuildInstance {
|
|
646
|
+
build(options: Record<string, unknown>): Promise<{
|
|
647
|
+
outputFiles?: Array<{ text: string }>;
|
|
648
|
+
warnings: EsbuildMessage[];
|
|
649
|
+
}>;
|
|
650
|
+
}
|
|
651
|
+
|
|
652
|
+
/**
|
|
653
|
+
* Options for the shared bundle execution helper.
|
|
654
|
+
*/
|
|
655
|
+
export interface ExecuteBundleOptions {
|
|
656
|
+
/** The esbuild instance to use */
|
|
657
|
+
esbuild: EsbuildInstance;
|
|
658
|
+
/** Bundle options from the IBundler interface */
|
|
659
|
+
bundleOptions: BundleOptions;
|
|
660
|
+
/** Base URL for CDN imports */
|
|
661
|
+
cdnBaseUrl: string;
|
|
662
|
+
/**
|
|
663
|
+
* Whether to bundle CDN imports inline.
|
|
664
|
+
* - Browser: false (external) - browser can fetch at runtime
|
|
665
|
+
* - Node/Bun: true (bundle) - esbuild fetches during build
|
|
666
|
+
*/
|
|
667
|
+
bundleCdnImports: boolean;
|
|
668
|
+
}
|
|
669
|
+
|
|
670
|
+
/**
|
|
671
|
+
* Execute a bundle using esbuild with the VFS plugin.
|
|
672
|
+
*
|
|
673
|
+
* This is the shared implementation used by both browser and node WASM bundlers.
|
|
674
|
+
* It handles entry point normalization, VFS plugin creation, and error handling.
|
|
675
|
+
*
|
|
676
|
+
* @param options - Bundle execution options
|
|
677
|
+
* @returns Bundle result with code or errors
|
|
678
|
+
*/
|
|
679
|
+
export async function executeBundleWithEsbuild(
|
|
680
|
+
options: ExecuteBundleOptions
|
|
681
|
+
): Promise<BundleResult> {
|
|
682
|
+
const { esbuild, bundleOptions, cdnBaseUrl, bundleCdnImports } = options;
|
|
683
|
+
|
|
684
|
+
const {
|
|
685
|
+
fs,
|
|
686
|
+
entryPoint,
|
|
687
|
+
installedPackages = {},
|
|
688
|
+
sharedModules = [],
|
|
689
|
+
sharedModuleRegistry,
|
|
690
|
+
external = [],
|
|
691
|
+
format = "esm",
|
|
692
|
+
minify = false,
|
|
693
|
+
sourcemap = false,
|
|
694
|
+
target = ["es2020"],
|
|
695
|
+
} = bundleOptions;
|
|
696
|
+
|
|
697
|
+
// Normalize entry point to absolute path
|
|
698
|
+
const normalizedEntry = entryPoint.startsWith("/")
|
|
699
|
+
? entryPoint
|
|
700
|
+
: `/${entryPoint}`;
|
|
701
|
+
|
|
702
|
+
// Verify entry point exists
|
|
703
|
+
if (!fs.exists(normalizedEntry)) {
|
|
704
|
+
return {
|
|
705
|
+
success: false,
|
|
706
|
+
errors: [{ text: `Entry point not found: ${normalizedEntry}` }],
|
|
707
|
+
warnings: [],
|
|
708
|
+
};
|
|
709
|
+
}
|
|
710
|
+
|
|
711
|
+
// Track files included in the bundle
|
|
712
|
+
const includedFiles = new Set<string>();
|
|
713
|
+
|
|
714
|
+
// Create the VFS plugin
|
|
715
|
+
const plugin = createVfsPlugin({
|
|
716
|
+
fs,
|
|
717
|
+
entryPoint: normalizedEntry,
|
|
718
|
+
installedPackages,
|
|
719
|
+
sharedModules: new Set(sharedModules),
|
|
720
|
+
sharedModuleRegistry: sharedModuleRegistry ?? null,
|
|
721
|
+
cdnBaseUrl,
|
|
722
|
+
includedFiles,
|
|
723
|
+
bundleCdnImports,
|
|
724
|
+
});
|
|
725
|
+
|
|
726
|
+
try {
|
|
727
|
+
// Run esbuild
|
|
728
|
+
const result = await esbuild.build({
|
|
729
|
+
entryPoints: [normalizedEntry],
|
|
730
|
+
bundle: true,
|
|
731
|
+
write: false,
|
|
732
|
+
format,
|
|
733
|
+
minify,
|
|
734
|
+
sourcemap: sourcemap ? "inline" : false,
|
|
735
|
+
target,
|
|
736
|
+
external,
|
|
737
|
+
plugins: [plugin],
|
|
738
|
+
jsx: "automatic",
|
|
739
|
+
});
|
|
740
|
+
|
|
741
|
+
const code = result.outputFiles?.[0]?.text ?? "";
|
|
742
|
+
|
|
743
|
+
// Convert esbuild warnings to our format
|
|
744
|
+
const warnings: BundleWarning[] = result.warnings.map((w) =>
|
|
745
|
+
convertEsbuildMessage(w)
|
|
746
|
+
);
|
|
747
|
+
|
|
748
|
+
return {
|
|
749
|
+
success: true,
|
|
750
|
+
code,
|
|
751
|
+
warnings,
|
|
752
|
+
includedFiles: Array.from(includedFiles),
|
|
753
|
+
};
|
|
754
|
+
} catch (err) {
|
|
755
|
+
// esbuild throws BuildFailure with .errors array
|
|
756
|
+
if (isEsbuildBuildFailure(err)) {
|
|
757
|
+
const errors: BundleError[] = err.errors.map((e) =>
|
|
758
|
+
convertEsbuildMessage(e)
|
|
759
|
+
);
|
|
760
|
+
const warnings: BundleWarning[] = err.warnings.map((w) =>
|
|
761
|
+
convertEsbuildMessage(w)
|
|
762
|
+
);
|
|
763
|
+
return {
|
|
764
|
+
success: false,
|
|
765
|
+
errors,
|
|
766
|
+
warnings,
|
|
767
|
+
};
|
|
768
|
+
}
|
|
769
|
+
|
|
770
|
+
// Unknown error - wrap it
|
|
771
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
772
|
+
return {
|
|
773
|
+
success: false,
|
|
774
|
+
errors: [{ text: message }],
|
|
775
|
+
warnings: [],
|
|
776
|
+
};
|
|
777
|
+
}
|
|
778
|
+
}
|
package/src/core/sandbox.ts
CHANGED
|
@@ -262,6 +262,88 @@ export async function createSandboxImpl(
|
|
|
262
262
|
fs.writeFile(TSCONFIG_PATH, JSON.stringify(DEFAULT_TSCONFIG, null, 2));
|
|
263
263
|
}
|
|
264
264
|
|
|
265
|
+
// ---------------------------------------------------------------------------
|
|
266
|
+
// Install types for shared modules (if both registry and resolver exist)
|
|
267
|
+
// ---------------------------------------------------------------------------
|
|
268
|
+
|
|
269
|
+
if (sharedModuleRegistry && typesResolver) {
|
|
270
|
+
const sharedModuleIds = sharedModuleRegistry.list();
|
|
271
|
+
|
|
272
|
+
// Resolve types for all shared modules in parallel
|
|
273
|
+
const typesFetches = sharedModuleIds.map(async (moduleId) => {
|
|
274
|
+
try {
|
|
275
|
+
const typeFiles = await typesResolver.resolveTypes(moduleId);
|
|
276
|
+
return { moduleId, typeFiles, error: null };
|
|
277
|
+
} catch (err) {
|
|
278
|
+
// Log but don't fail - types are nice to have but not required
|
|
279
|
+
console.warn(`[sandlot] Failed to fetch types for shared module "${moduleId}":`, err);
|
|
280
|
+
return { moduleId, typeFiles: {}, error: err };
|
|
281
|
+
}
|
|
282
|
+
});
|
|
283
|
+
|
|
284
|
+
const results = await Promise.all(typesFetches);
|
|
285
|
+
|
|
286
|
+
// Write type files to the filesystem
|
|
287
|
+
for (const { moduleId, typeFiles } of results) {
|
|
288
|
+
if (Object.keys(typeFiles).length === 0) continue;
|
|
289
|
+
|
|
290
|
+
// Determine the package name (strip subpath for @types resolution)
|
|
291
|
+
// e.g., "react-dom/client" -> "react-dom"
|
|
292
|
+
let packageName = moduleId;
|
|
293
|
+
let subpath: string | undefined;
|
|
294
|
+
|
|
295
|
+
if (moduleId.startsWith("@")) {
|
|
296
|
+
const parts = moduleId.split("/");
|
|
297
|
+
if (parts.length >= 2) {
|
|
298
|
+
packageName = `${parts[0]}/${parts[1]}`;
|
|
299
|
+
subpath = parts.length > 2 ? parts.slice(2).join("/") : undefined;
|
|
300
|
+
}
|
|
301
|
+
} else {
|
|
302
|
+
const slashIndex = moduleId.indexOf("/");
|
|
303
|
+
if (slashIndex !== -1) {
|
|
304
|
+
packageName = moduleId.slice(0, slashIndex);
|
|
305
|
+
subpath = moduleId.slice(slashIndex + 1);
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
const packageDir = `/node_modules/${packageName}`;
|
|
310
|
+
let typesEntry: string | null = null;
|
|
311
|
+
let fallbackEntry: string | null = null;
|
|
312
|
+
|
|
313
|
+
for (const [filePath, content] of Object.entries(typeFiles)) {
|
|
314
|
+
const fullPath = filePath.startsWith("/")
|
|
315
|
+
? filePath
|
|
316
|
+
: `${packageDir}/${filePath}`;
|
|
317
|
+
const dir = fullPath.substring(0, fullPath.lastIndexOf("/"));
|
|
318
|
+
ensureDir(fs, dir);
|
|
319
|
+
fs.writeFile(fullPath, content);
|
|
320
|
+
|
|
321
|
+
// Track types entry: prefer index.d.ts, fallback to first top-level .d.ts
|
|
322
|
+
const relativePath = fullPath.replace(`${packageDir}/`, "");
|
|
323
|
+
if (relativePath === "index.d.ts") {
|
|
324
|
+
typesEntry = "index.d.ts";
|
|
325
|
+
} else if (!fallbackEntry && relativePath.endsWith(".d.ts") && !relativePath.includes("/")) {
|
|
326
|
+
fallbackEntry = relativePath;
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
// Use index.d.ts if found, otherwise use fallback
|
|
331
|
+
const finalTypesEntry = typesEntry ?? fallbackEntry ?? "index.d.ts";
|
|
332
|
+
|
|
333
|
+
// Create package.json if it doesn't exist yet
|
|
334
|
+
const pkgJsonPath = `${packageDir}/package.json`;
|
|
335
|
+
if (!fs.exists(pkgJsonPath)) {
|
|
336
|
+
const pkgJson = {
|
|
337
|
+
name: packageName,
|
|
338
|
+
version: "shared",
|
|
339
|
+
types: finalTypesEntry,
|
|
340
|
+
main: finalTypesEntry.replace(/\.d\.ts$/, ".js"),
|
|
341
|
+
};
|
|
342
|
+
fs.writeFile(pkgJsonPath, JSON.stringify(pkgJson, null, 2));
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
|
|
265
347
|
// ---------------------------------------------------------------------------
|
|
266
348
|
// Core Methods
|
|
267
349
|
// ---------------------------------------------------------------------------
|
package/src/node/bundler.ts
CHANGED
|
@@ -6,18 +6,8 @@
|
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
8
|
import type * as EsbuildTypes from "esbuild";
|
|
9
|
-
import type {
|
|
10
|
-
|
|
11
|
-
BundleOptions,
|
|
12
|
-
BundleResult,
|
|
13
|
-
BundleWarning,
|
|
14
|
-
BundleError,
|
|
15
|
-
} from "../types";
|
|
16
|
-
import {
|
|
17
|
-
createVfsPlugin,
|
|
18
|
-
isEsbuildBuildFailure,
|
|
19
|
-
convertEsbuildMessage,
|
|
20
|
-
} from "../core/bundler-utils";
|
|
9
|
+
import type { IBundler, BundleOptions, BundleResult } from "../types";
|
|
10
|
+
import { executeBundleWithEsbuild } from "../core/bundler-utils";
|
|
21
11
|
|
|
22
12
|
export interface EsbuildNativeBundlerOptions {
|
|
23
13
|
/**
|
|
@@ -90,108 +80,14 @@ export class EsbuildNativeBundler implements IBundler {
|
|
|
90
80
|
async bundle(options: BundleOptions): Promise<BundleResult> {
|
|
91
81
|
await this.initialize();
|
|
92
82
|
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
const {
|
|
96
|
-
fs,
|
|
97
|
-
entryPoint,
|
|
98
|
-
installedPackages = {},
|
|
99
|
-
sharedModules = [],
|
|
100
|
-
sharedModuleRegistry,
|
|
101
|
-
external = [],
|
|
102
|
-
format = "esm",
|
|
103
|
-
minify = false,
|
|
104
|
-
sourcemap = false,
|
|
105
|
-
target = ["es2020"],
|
|
106
|
-
} = options;
|
|
107
|
-
|
|
108
|
-
// Normalize entry point to absolute path
|
|
109
|
-
const normalizedEntry = entryPoint.startsWith("/")
|
|
110
|
-
? entryPoint
|
|
111
|
-
: `/${entryPoint}`;
|
|
112
|
-
|
|
113
|
-
// Verify entry point exists
|
|
114
|
-
if (!fs.exists(normalizedEntry)) {
|
|
115
|
-
return {
|
|
116
|
-
success: false,
|
|
117
|
-
errors: [{ text: `Entry point not found: ${normalizedEntry}` }],
|
|
118
|
-
warnings: [],
|
|
119
|
-
};
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
// Track files included in the bundle
|
|
123
|
-
const includedFiles = new Set<string>();
|
|
124
|
-
|
|
125
|
-
// Create the VFS plugin
|
|
126
|
-
// Note: bundleCdnImports is true for Node/Bun because they cannot
|
|
83
|
+
// bundleCdnImports is true for Node/Bun because they cannot
|
|
127
84
|
// resolve HTTP imports at runtime - native esbuild will fetch and bundle them
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
installedPackages,
|
|
132
|
-
sharedModules: new Set(sharedModules),
|
|
133
|
-
sharedModuleRegistry: sharedModuleRegistry ?? null,
|
|
85
|
+
return executeBundleWithEsbuild({
|
|
86
|
+
esbuild: this.getEsbuild(),
|
|
87
|
+
bundleOptions: options,
|
|
134
88
|
cdnBaseUrl: this.options.cdnBaseUrl!,
|
|
135
|
-
includedFiles,
|
|
136
89
|
bundleCdnImports: true,
|
|
137
90
|
});
|
|
138
|
-
|
|
139
|
-
try {
|
|
140
|
-
// Run esbuild
|
|
141
|
-
// Note: We do NOT mark http/https as external here because Node/Bun
|
|
142
|
-
// cannot resolve HTTP imports at runtime. Instead, bundleCdnImports: true
|
|
143
|
-
// tells the VFS plugin to let native esbuild fetch and bundle CDN imports.
|
|
144
|
-
const result = await esbuild.build({
|
|
145
|
-
entryPoints: [normalizedEntry],
|
|
146
|
-
bundle: true,
|
|
147
|
-
write: false,
|
|
148
|
-
format,
|
|
149
|
-
minify,
|
|
150
|
-
sourcemap: sourcemap ? "inline" : false,
|
|
151
|
-
target,
|
|
152
|
-
external,
|
|
153
|
-
// Cast to esbuild's Plugin type since our minimal interface is compatible
|
|
154
|
-
plugins: [plugin as EsbuildTypes.Plugin],
|
|
155
|
-
jsx: "automatic",
|
|
156
|
-
});
|
|
157
|
-
|
|
158
|
-
const code = result.outputFiles?.[0]?.text ?? "";
|
|
159
|
-
|
|
160
|
-
// Convert esbuild warnings to our format
|
|
161
|
-
const warnings: BundleWarning[] = result.warnings.map((w) =>
|
|
162
|
-
convertEsbuildMessage(w)
|
|
163
|
-
);
|
|
164
|
-
|
|
165
|
-
return {
|
|
166
|
-
success: true,
|
|
167
|
-
code,
|
|
168
|
-
warnings,
|
|
169
|
-
includedFiles: Array.from(includedFiles),
|
|
170
|
-
};
|
|
171
|
-
} catch (err) {
|
|
172
|
-
// esbuild throws BuildFailure with .errors array
|
|
173
|
-
if (isEsbuildBuildFailure(err)) {
|
|
174
|
-
const errors: BundleError[] = err.errors.map((e) =>
|
|
175
|
-
convertEsbuildMessage(e)
|
|
176
|
-
);
|
|
177
|
-
const warnings: BundleWarning[] = err.warnings.map((w) =>
|
|
178
|
-
convertEsbuildMessage(w)
|
|
179
|
-
);
|
|
180
|
-
return {
|
|
181
|
-
success: false,
|
|
182
|
-
errors,
|
|
183
|
-
warnings,
|
|
184
|
-
};
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
// Unknown error - wrap it
|
|
188
|
-
const message = err instanceof Error ? err.message : String(err);
|
|
189
|
-
return {
|
|
190
|
-
success: false,
|
|
191
|
-
errors: [{ text: message }],
|
|
192
|
-
warnings: [],
|
|
193
|
-
};
|
|
194
|
-
}
|
|
195
91
|
}
|
|
196
92
|
}
|
|
197
93
|
|
package/src/node/wasm-bundler.ts
CHANGED
|
@@ -12,18 +12,8 @@
|
|
|
12
12
|
*/
|
|
13
13
|
|
|
14
14
|
import type * as EsbuildTypes from "esbuild-wasm";
|
|
15
|
-
import type {
|
|
16
|
-
|
|
17
|
-
BundleOptions,
|
|
18
|
-
BundleResult,
|
|
19
|
-
BundleWarning,
|
|
20
|
-
BundleError,
|
|
21
|
-
} from "../types";
|
|
22
|
-
import {
|
|
23
|
-
createVfsPlugin,
|
|
24
|
-
isEsbuildBuildFailure,
|
|
25
|
-
convertEsbuildMessage,
|
|
26
|
-
} from "../core/bundler-utils";
|
|
15
|
+
import type { IBundler, BundleOptions, BundleResult } from "../types";
|
|
16
|
+
import { executeBundleWithEsbuild } from "../core/bundler-utils";
|
|
27
17
|
|
|
28
18
|
// =============================================================================
|
|
29
19
|
// Global Singleton for esbuild-wasm initialization
|
|
@@ -181,108 +171,14 @@ export class EsbuildWasmNodeBundler implements IBundler {
|
|
|
181
171
|
async bundle(options: BundleOptions): Promise<BundleResult> {
|
|
182
172
|
await this.initialize();
|
|
183
173
|
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
const {
|
|
187
|
-
fs,
|
|
188
|
-
entryPoint,
|
|
189
|
-
installedPackages = {},
|
|
190
|
-
sharedModules = [],
|
|
191
|
-
sharedModuleRegistry,
|
|
192
|
-
external = [],
|
|
193
|
-
format = "esm",
|
|
194
|
-
minify = false,
|
|
195
|
-
sourcemap = false,
|
|
196
|
-
target = ["es2020"],
|
|
197
|
-
} = options;
|
|
198
|
-
|
|
199
|
-
// Normalize entry point to absolute path
|
|
200
|
-
const normalizedEntry = entryPoint.startsWith("/")
|
|
201
|
-
? entryPoint
|
|
202
|
-
: `/${entryPoint}`;
|
|
203
|
-
|
|
204
|
-
// Verify entry point exists
|
|
205
|
-
if (!fs.exists(normalizedEntry)) {
|
|
206
|
-
return {
|
|
207
|
-
success: false,
|
|
208
|
-
errors: [{ text: `Entry point not found: ${normalizedEntry}` }],
|
|
209
|
-
warnings: [],
|
|
210
|
-
};
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
// Track files included in the bundle
|
|
214
|
-
const includedFiles = new Set<string>();
|
|
215
|
-
|
|
216
|
-
// Create the VFS plugin
|
|
217
|
-
// Note: bundleCdnImports is true for Node/Bun because they cannot
|
|
174
|
+
// bundleCdnImports is true for Node/Bun because they cannot
|
|
218
175
|
// resolve HTTP imports at runtime - esbuild will fetch and bundle them
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
installedPackages,
|
|
223
|
-
sharedModules: new Set(sharedModules),
|
|
224
|
-
sharedModuleRegistry: sharedModuleRegistry ?? null,
|
|
176
|
+
return executeBundleWithEsbuild({
|
|
177
|
+
esbuild: this.getEsbuild(),
|
|
178
|
+
bundleOptions: options,
|
|
225
179
|
cdnBaseUrl: this.options.cdnBaseUrl!,
|
|
226
|
-
includedFiles,
|
|
227
180
|
bundleCdnImports: true,
|
|
228
181
|
});
|
|
229
|
-
|
|
230
|
-
try {
|
|
231
|
-
// Run esbuild
|
|
232
|
-
// Note: We do NOT mark http/https as external here because Node/Bun
|
|
233
|
-
// cannot resolve HTTP imports at runtime. Instead, bundleCdnImports: true
|
|
234
|
-
// tells the VFS plugin to let esbuild fetch and bundle CDN imports.
|
|
235
|
-
const result = await esbuild.build({
|
|
236
|
-
entryPoints: [normalizedEntry],
|
|
237
|
-
bundle: true,
|
|
238
|
-
write: false,
|
|
239
|
-
format,
|
|
240
|
-
minify,
|
|
241
|
-
sourcemap: sourcemap ? "inline" : false,
|
|
242
|
-
target,
|
|
243
|
-
external,
|
|
244
|
-
// Cast to esbuild's Plugin type since our minimal interface is compatible
|
|
245
|
-
plugins: [plugin as EsbuildTypes.Plugin],
|
|
246
|
-
jsx: "automatic",
|
|
247
|
-
});
|
|
248
|
-
|
|
249
|
-
const code = result.outputFiles?.[0]?.text ?? "";
|
|
250
|
-
|
|
251
|
-
// Convert esbuild warnings to our format
|
|
252
|
-
const warnings: BundleWarning[] = result.warnings.map((w) =>
|
|
253
|
-
convertEsbuildMessage(w)
|
|
254
|
-
);
|
|
255
|
-
|
|
256
|
-
return {
|
|
257
|
-
success: true,
|
|
258
|
-
code,
|
|
259
|
-
warnings,
|
|
260
|
-
includedFiles: Array.from(includedFiles),
|
|
261
|
-
};
|
|
262
|
-
} catch (err) {
|
|
263
|
-
// esbuild throws BuildFailure with .errors array
|
|
264
|
-
if (isEsbuildBuildFailure(err)) {
|
|
265
|
-
const errors: BundleError[] = err.errors.map((e) =>
|
|
266
|
-
convertEsbuildMessage(e)
|
|
267
|
-
);
|
|
268
|
-
const warnings: BundleWarning[] = err.warnings.map((w) =>
|
|
269
|
-
convertEsbuildMessage(w)
|
|
270
|
-
);
|
|
271
|
-
return {
|
|
272
|
-
success: false,
|
|
273
|
-
errors,
|
|
274
|
-
warnings,
|
|
275
|
-
};
|
|
276
|
-
}
|
|
277
|
-
|
|
278
|
-
// Unknown error - wrap it
|
|
279
|
-
const message = err instanceof Error ? err.message : String(err);
|
|
280
|
-
return {
|
|
281
|
-
success: false,
|
|
282
|
-
errors: [{ text: message }],
|
|
283
|
-
warnings: [],
|
|
284
|
-
};
|
|
285
|
-
}
|
|
286
182
|
}
|
|
287
183
|
}
|
|
288
184
|
|