run esbuild wasm
This commit is contained in:
parent
b76b8c4c68
commit
2b64a038ce
15
package-lock.json
generated
15
package-lock.json
generated
@ -1197,6 +1197,18 @@
|
|||||||
"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",
|
||||||
@ -2851,7 +2863,8 @@
|
|||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@mcp-ui/server": "^5.15.0",
|
"@mcp-ui/server": "^5.15.0",
|
||||||
"esbuild": "^0.25.0"
|
"esbuild": "^0.25.0",
|
||||||
|
"esbuild-wasm": "^0.25.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/node": "^20.10.0",
|
"@types/node": "^20.10.0",
|
||||||
|
|||||||
@ -47,7 +47,8 @@
|
|||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@mcp-ui/server": "^5.15.0",
|
"@mcp-ui/server": "^5.15.0",
|
||||||
"esbuild": "^0.25.0"
|
"esbuild": "^0.25.0",
|
||||||
|
"esbuild-wasm": "^0.25.0"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"react": ">=18.0.0",
|
"react": ">=18.0.0",
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import * as esbuild from 'esbuild';
|
import type * as EsbuildType 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>();
|
||||||
@ -6,12 +6,51 @@ 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';
|
||||||
|
|
||||||
async function runBuild(entryPath: string): Promise<esbuild.BuildResult<{ write: false }>> {
|
// Esbuild instance - lazily loaded
|
||||||
console.log('[mcp-ui-kit] runBuild called for:', entryPath);
|
let esbuild: typeof EsbuildType | null = null;
|
||||||
|
let usingWasm = false;
|
||||||
|
|
||||||
|
async function getEsbuild(): Promise<typeof EsbuildType> {
|
||||||
|
if (esbuild) return esbuild;
|
||||||
|
|
||||||
|
// Try native esbuild first
|
||||||
|
try {
|
||||||
|
console.log('[mcp-ui-kit] Trying native esbuild...');
|
||||||
|
const native = await import('esbuild');
|
||||||
|
// Test if native works by running a simple transform
|
||||||
|
await native.transform('const x = 1', { loader: 'js' });
|
||||||
|
console.log('[mcp-ui-kit] Native esbuild works!');
|
||||||
|
esbuild = native;
|
||||||
|
return esbuild;
|
||||||
|
} catch (nativeError) {
|
||||||
|
console.log('[mcp-ui-kit] Native esbuild failed:', nativeError instanceof Error ? nativeError.message : String(nativeError));
|
||||||
|
|
||||||
|
// Fall back to wasm
|
||||||
|
try {
|
||||||
|
console.log('[mcp-ui-kit] Falling back to esbuild-wasm...');
|
||||||
|
const wasm = await import('esbuild-wasm');
|
||||||
|
await wasm.initialize({
|
||||||
|
wasmURL: `https://unpkg.com/esbuild-wasm@${wasm.version}/esbuild.wasm`,
|
||||||
|
});
|
||||||
|
console.log('[mcp-ui-kit] esbuild-wasm initialized!');
|
||||||
|
esbuild = wasm as typeof EsbuildType;
|
||||||
|
usingWasm = true;
|
||||||
|
return esbuild;
|
||||||
|
} catch (wasmError) {
|
||||||
|
console.log('[mcp-ui-kit] esbuild-wasm also failed:', wasmError instanceof Error ? wasmError.message : String(wasmError));
|
||||||
|
throw wasmError;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function runBuild(entryPath: string): Promise<EsbuildType.BuildResult<{ write: false }>> {
|
||||||
|
const esbuild = await getEsbuild();
|
||||||
|
console.log('[mcp-ui-kit] runBuild using', usingWasm ? 'wasm' : 'native', 'for:', entryPath);
|
||||||
|
|
||||||
return esbuild.build({
|
return esbuild.build({
|
||||||
entryPoints: [entryPath],
|
entryPoints: [entryPath],
|
||||||
bundle: true,
|
bundle: true,
|
||||||
write: false, // No disk I/O - keep everything in memory
|
write: false,
|
||||||
format: 'iife',
|
format: 'iife',
|
||||||
target: 'es2020',
|
target: 'es2020',
|
||||||
jsx: 'automatic',
|
jsx: 'automatic',
|
||||||
@ -25,45 +64,33 @@ async function runBuild(entryPath: string): Promise<esbuild.BuildResult<{ write:
|
|||||||
|
|
||||||
export async function bundleComponent(entryPath: string): Promise<string> {
|
export async function bundleComponent(entryPath: string): Promise<string> {
|
||||||
console.log('[mcp-ui-kit] bundleComponent called for:', entryPath);
|
console.log('[mcp-ui-kit] bundleComponent called for:', entryPath);
|
||||||
console.log('[mcp-ui-kit] isDev:', isDev, 'NODE_ENV:', process.env.NODE_ENV);
|
|
||||||
console.log('[mcp-ui-kit] Cache has entry:', bundleCache.has(entryPath));
|
|
||||||
|
|
||||||
if (!isDev && bundleCache.has(entryPath)) {
|
if (!isDev && bundleCache.has(entryPath)) {
|
||||||
console.log('[mcp-ui-kit] Returning cached bundle');
|
console.log('[mcp-ui-kit] Returning cached bundle');
|
||||||
return bundleCache.get(entryPath)!;
|
return bundleCache.get(entryPath)!;
|
||||||
}
|
}
|
||||||
|
|
||||||
let result: esbuild.BuildResult<{ write: false }>;
|
let result: EsbuildType.BuildResult<{ write: false }>;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
console.log('[mcp-ui-kit] Attempting first build...');
|
|
||||||
result = await runBuild(entryPath);
|
result = await runBuild(entryPath);
|
||||||
console.log('[mcp-ui-kit] First build succeeded');
|
console.log('[mcp-ui-kit] Build succeeded');
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
const errorMessage = error instanceof Error ? error.message : String(error);
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
||||||
const errorStack = error instanceof Error ? error.stack : '';
|
console.log('[mcp-ui-kit] Build failed:', errorMessage);
|
||||||
console.log('[mcp-ui-kit] ========== BUILD ERROR ==========');
|
|
||||||
console.log('[mcp-ui-kit] Error message:', errorMessage);
|
|
||||||
console.log('[mcp-ui-kit] Error stack:', errorStack);
|
|
||||||
console.log('[mcp-ui-kit] Full error:', JSON.stringify(error, Object.getOwnPropertyNames(error || {}), 2));
|
|
||||||
console.log('[mcp-ui-kit] ================================');
|
|
||||||
|
|
||||||
// Handle esbuild service errors in serverless environments (Vercel, Lambda, etc.)
|
// Handle service errors for native esbuild in serverless
|
||||||
// This happens when the serverless runtime freezes/stops the esbuild subprocess.
|
const isServiceError = !usingWasm && error instanceof Error && (
|
||||||
const isServiceError = error instanceof Error && (
|
|
||||||
errorMessage.includes('service was stopped') ||
|
errorMessage.includes('service was stopped') ||
|
||||||
errorMessage.includes('service is no longer running') ||
|
errorMessage.includes('service is no longer running') ||
|
||||||
errorMessage.includes('The service') ||
|
errorMessage.includes('The service')
|
||||||
errorMessage.includes('could not be found')
|
|
||||||
);
|
);
|
||||||
console.log('[mcp-ui-kit] Is service error:', isServiceError);
|
|
||||||
|
|
||||||
if (isServiceError) {
|
if (isServiceError) {
|
||||||
// Force stop the dead service, then retry - esbuild will start fresh
|
console.log('[mcp-ui-kit] Service error, stopping and retrying...');
|
||||||
console.log('[mcp-ui-kit] Stopping esbuild service and retrying...');
|
const esbuild = await getEsbuild();
|
||||||
await esbuild.stop();
|
await esbuild.stop();
|
||||||
result = await runBuild(entryPath);
|
result = await runBuild(entryPath);
|
||||||
console.log('[mcp-ui-kit] Retry succeeded');
|
|
||||||
} else {
|
} else {
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
@ -72,10 +99,8 @@ export async function bundleComponent(entryPath: string): Promise<string> {
|
|||||||
const bundledJS = result.outputFiles[0].text;
|
const bundledJS = result.outputFiles[0].text;
|
||||||
console.log('[mcp-ui-kit] Bundle size:', bundledJS.length, 'bytes');
|
console.log('[mcp-ui-kit] Bundle size:', bundledJS.length, 'bytes');
|
||||||
|
|
||||||
// Only cache in production mode
|
|
||||||
if (!isDev) {
|
if (!isDev) {
|
||||||
bundleCache.set(entryPath, bundledJS);
|
bundleCache.set(entryPath, bundledJS);
|
||||||
console.log('[mcp-ui-kit] Bundle cached');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return bundledJS;
|
return bundledJS;
|
||||||
|
|||||||
@ -713,6 +713,11 @@ 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"
|
||||||
@ -1042,6 +1047,7 @@ mcp-ui-kit@*, "mcp-ui-kit@file:/Users/fedjens/projects/mcp-ui-kit/packages/libra
|
|||||||
dependencies:
|
dependencies:
|
||||||
"@mcp-ui/server" "^5.15.0"
|
"@mcp-ui/server" "^5.15.0"
|
||||||
esbuild "^0.25.0"
|
esbuild "^0.25.0"
|
||||||
|
esbuild-wasm "^0.25.0"
|
||||||
|
|
||||||
media-typer@^1.1.0:
|
media-typer@^1.1.0:
|
||||||
version "1.1.0"
|
version "1.1.0"
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user