make esbuild run serverless

This commit is contained in:
Fredrik Jensen 2025-12-06 16:42:28 +01:00
parent c2e411b100
commit fe026c6122
4 changed files with 21 additions and 54 deletions

22
package-lock.json generated
View File

@ -1872,18 +1872,6 @@
"node": ">= 0.4" "node": ">= 0.4"
} }
}, },
"node_modules/esbuild-wasm": {
"version": "0.25.12",
"resolved": "https://registry.npmjs.org/esbuild-wasm/-/esbuild-wasm-0.25.12.tgz",
"integrity": "sha512-rZqkjL3Y6FwLpSHzLnaEy8Ps6veCNo1kZa9EOfJvmWtBq5dJH4iVjfmOO6Mlkv9B0tt9WFPFmb/VxlgJOnueNg==",
"license": "MIT",
"bin": {
"esbuild": "bin/esbuild"
},
"engines": {
"node": ">=18"
}
},
"node_modules/escalade": { "node_modules/escalade": {
"version": "3.2.0", "version": "3.2.0",
"resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz",
@ -3538,7 +3526,7 @@
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@mcp-ui/server": "^5.15.0", "@mcp-ui/server": "^5.15.0",
"esbuild-wasm": "^0.25.0" "esbuild": "^0.25.0"
}, },
"devDependencies": { "devDependencies": {
"@types/node": "^20.10.0", "@types/node": "^20.10.0",
@ -3552,7 +3540,12 @@
"node": ">=18.0.0" "node": ">=18.0.0"
}, },
"optionalDependencies": { "optionalDependencies": {
"esbuild": "^0.25.0" "@esbuild/darwin-arm64": "^0.25.0",
"@esbuild/darwin-x64": "^0.25.0",
"@esbuild/linux-arm64": "^0.25.0",
"@esbuild/linux-x64": "^0.25.0",
"@esbuild/win32-arm64": "^0.25.0",
"@esbuild/win32-x64": "^0.25.0"
}, },
"peerDependencies": { "peerDependencies": {
"react": ">=18.0.0", "react": ">=18.0.0",
@ -3599,7 +3592,6 @@
"integrity": "sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg==", "integrity": "sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg==",
"hasInstallScript": true, "hasInstallScript": true,
"license": "MIT", "license": "MIT",
"optional": true,
"bin": { "bin": {
"esbuild": "bin/esbuild" "esbuild": "bin/esbuild"
}, },

View File

@ -47,10 +47,15 @@
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@mcp-ui/server": "^5.15.0", "@mcp-ui/server": "^5.15.0",
"esbuild-wasm": "^0.25.0" "esbuild": "^0.25.0"
}, },
"optionalDependencies": { "optionalDependencies": {
"esbuild": "^0.25.0" "@esbuild/linux-x64": "^0.25.0",
"@esbuild/linux-arm64": "^0.25.0",
"@esbuild/darwin-x64": "^0.25.0",
"@esbuild/darwin-arm64": "^0.25.0",
"@esbuild/win32-x64": "^0.25.0",
"@esbuild/win32-arm64": "^0.25.0"
}, },
"peerDependencies": { "peerDependencies": {
"react": ">=18.0.0", "react": ">=18.0.0",

View File

@ -1,38 +1,12 @@
import * as esbuild from 'esbuild';
// Cache bundled JS per entry path (only used in production) // Cache bundled JS per entry path (only used in production)
const bundleCache = new Map<string, string>(); const bundleCache = new Map<string, string>();
// In development mode, skip cache to allow hot-reloading of component changes // In development mode, skip cache to allow hot-reloading of component changes
const isDev = process.env.NODE_ENV !== 'production'; const isDev = process.env.NODE_ENV !== 'production';
// Dynamic esbuild loader - tries native first, falls back to wasm for serverless async function runBuild(entryPath: string): Promise<esbuild.BuildResult<{ write: false }>> {
let esbuildModule: typeof import('esbuild') | null = null;
let wasmInitialized = false;
async function getEsbuild(): Promise<typeof import('esbuild')> {
if (esbuildModule) return esbuildModule;
// Try native esbuild first (faster, works locally)
try {
esbuildModule = await import('esbuild');
// Test if native binary works
await esbuildModule.transform('', { loader: 'js' });
return esbuildModule;
} catch {
// Fall back to wasm (works on serverless without native binaries)
const wasm = await import('esbuild-wasm');
if (!wasmInitialized) {
await wasm.initialize({
wasmURL: `https://unpkg.com/esbuild-wasm@${wasm.version}/esbuild.wasm`,
});
wasmInitialized = true;
}
esbuildModule = wasm as typeof import('esbuild');
return esbuildModule;
}
}
async function runBuild(entryPath: string): Promise<import('esbuild').BuildResult<{ write: false }>> {
const esbuild = await getEsbuild();
return esbuild.build({ return esbuild.build({
entryPoints: [entryPath], entryPoints: [entryPath],
bundle: true, bundle: true,
@ -53,7 +27,7 @@ export async function bundleComponent(entryPath: string): Promise<string> {
return bundleCache.get(entryPath)!; return bundleCache.get(entryPath)!;
} }
let result: import('esbuild').BuildResult<{ write: false }>; let result: esbuild.BuildResult<{ write: false }>;
try { try {
result = await runBuild(entryPath); result = await runBuild(entryPath);
@ -67,7 +41,6 @@ export async function bundleComponent(entryPath: string): Promise<string> {
); );
if (isServiceError) { if (isServiceError) {
// Force stop the dead service, then retry - esbuild will start fresh // Force stop the dead service, then retry - esbuild will start fresh
const esbuild = await getEsbuild();
await esbuild.stop(); await esbuild.stop();
result = await runBuild(entryPath); result = await runBuild(entryPath);
} else { } else {

View File

@ -167,7 +167,7 @@
dependencies: dependencies:
"@jridgewell/trace-mapping" "0.3.9" "@jridgewell/trace-mapping" "0.3.9"
"@esbuild/darwin-x64@0.25.12": "@esbuild/darwin-x64@^0.25.0", "@esbuild/darwin-x64@0.25.12":
version "0.25.12" version "0.25.12"
resolved "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.12.tgz" resolved "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.12.tgz"
integrity sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA== integrity sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA==
@ -711,11 +711,6 @@ es-object-atoms@^1.0.0, es-object-atoms@^1.1.1:
dependencies: dependencies:
es-errors "^1.3.0" es-errors "^1.3.0"
esbuild-wasm@^0.25.0:
version "0.25.12"
resolved "https://registry.npmjs.org/esbuild-wasm/-/esbuild-wasm-0.25.12.tgz"
integrity sha512-rZqkjL3Y6FwLpSHzLnaEy8Ps6veCNo1kZa9EOfJvmWtBq5dJH4iVjfmOO6Mlkv9B0tt9WFPFmb/VxlgJOnueNg==
esbuild@^0.25.0: esbuild@^0.25.0:
version "0.25.12" version "0.25.12"
resolved "https://registry.npmjs.org/esbuild/-/esbuild-0.25.12.tgz" resolved "https://registry.npmjs.org/esbuild/-/esbuild-0.25.12.tgz"
@ -1044,6 +1039,8 @@ mcp-ui-kit@*, "mcp-ui-kit@file:/Users/fedjens/projects/mcp-ui-kit/packages/libra
resolved "file:packages/library" resolved "file:packages/library"
dependencies: dependencies:
"@mcp-ui/server" "^5.15.0" "@mcp-ui/server" "^5.15.0"
esbuild-wasm "^0.25.0"
optionalDependencies:
esbuild "^0.25.0" esbuild "^0.25.0"
media-typer@^1.1.0: media-typer@^1.1.0: