forked from stack-auth/stack-auth
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathesbuild.tsx
More file actions
128 lines (114 loc) · 4.38 KB
/
esbuild.tsx
File metadata and controls
128 lines (114 loc) · 4.38 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
import * as esbuild from 'esbuild-wasm/lib/browser.js';
import { join } from 'path';
import { isBrowserLike } from './env';
import { StackAssertionError, throwErr } from "./errors";
import { Result } from "./results";
import { traceSpan, withTraceSpan } from './telemetry';
const esbuildWasmUrl = `https://unpkg.com/esbuild-wasm@${esbuild.version}/esbuild.wasm`;
let esbuildInitializePromise: Promise<void> | null = null;
// esbuild requires self property to be set, and it is not set by default in nodejs
(globalThis.self as any) ??= globalThis as any;
export function initializeEsbuild(): Promise<void> {
if (!esbuildInitializePromise) {
esbuildInitializePromise = withTraceSpan('initializeEsbuild', async () => {
await esbuild.initialize(isBrowserLike() ? {
wasmURL: esbuildWasmUrl,
} : {
wasmModule: (
await fetch(esbuildWasmUrl)
.then(wasm => wasm.arrayBuffer())
.then(wasm => new WebAssembly.Module(wasm))
),
worker: false,
});
})();
}
return esbuildInitializePromise;
}
export async function bundleJavaScript(sourceFiles: Record<string, string> & { '/entry.js': string }, options: {
format?: 'iife' | 'esm' | 'cjs',
externalPackages?: Record<string, string>,
keepAsImports?: string[],
sourcemap?: false | 'inline',
} = {}): Promise<Result<string, string>> {
await initializeEsbuild();
const sourceFilesMap = new Map(Object.entries(sourceFiles));
const externalPackagesMap = new Map(Object.entries(options.externalPackages ?? {}));
const keepAsImports = options.keepAsImports ?? [];
const extToLoader: Map<string, esbuild.Loader> = new Map([
['tsx', 'tsx'],
['ts', 'ts'],
['js', 'js'],
['jsx', 'jsx'],
['json', 'json'],
['css', 'css'],
]);
let result;
try {
result = await traceSpan('bundleJavaScript', async () => await esbuild.build({
entryPoints: ['/entry.js'],
bundle: true,
write: false,
format: options.format ?? 'iife',
platform: 'browser',
target: 'es2015',
jsx: 'automatic',
sourcemap: options.sourcemap ?? 'inline',
external: keepAsImports,
plugins: [
{
name: 'replace-packages-with-globals',
setup(build) {
build.onResolve({ filter: /.*/ }, args => {
// Skip packages that should remain external (not be shimmed)
if (keepAsImports.includes(args.path)) {
return undefined;
}
if (externalPackagesMap.has(args.path)) {
return { path: args.path, namespace: 'package-shim' };
}
return undefined;
});
build.onLoad({ filter: /.*/, namespace: 'package-shim' }, (args) => {
const contents = externalPackagesMap.get(args.path);
if (contents == null) throw new StackAssertionError(`esbuild requested file ${args.path} that is not in the virtual file system`);
return { contents, loader: 'ts' };
});
},
},
{
name: 'virtual-fs',
setup(build) {
build.onResolve({ filter: /.*/ }, args => {
const absolutePath = join("/", args.path);
if (sourceFilesMap.has(absolutePath)) {
return { path: absolutePath, namespace: 'virtual' };
}
return undefined;
});
/* 2️⃣ Load the module from the map */
build.onLoad({ filter: /.*/, namespace: 'virtual' }, args => {
const contents = sourceFilesMap.get(args.path);
if (contents == null) throw new StackAssertionError(`esbuild requested file ${args.path} that is not in the virtual file system`);
const ext = args.path.split('.').pop() ?? '';
const loader = extToLoader.get(ext) ?? throwErr(`esbuild requested file ${args.path} with unknown extension ${ext}`);
return { contents, loader };
});
},
},
],
}));
} catch (e) {
if (e instanceof Error && e.message.startsWith("Build failed with ")) {
return Result.error(e.message);
}
throw e;
}
if (result.errors.length > 0) {
return Result.error(result.errors.map(e => e.text).join('\n'));
}
if (result.outputFiles.length > 0) {
return Result.ok(result.outputFiles[0].text);
}
return throwErr("No output generated??");
}