Created
April 15, 2025 18:00
-
-
Save sanandnarayan/efe459d21b63e5b04bd4ff872570551a to your computer and use it in GitHub Desktop.
cloudflare bundler
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { NodeModulesPolyfillPlugin } from '@esbuild-plugins/node-modules-polyfill' | |
import * as esbuild from 'esbuild-wasm' | |
import wasm from '../node_modules/esbuild-wasm/esbuild.wasm' | |
interface BundleRequest { | |
code: string; | |
minify?: boolean; | |
target?: string; | |
} | |
interface Env { | |
ASSETS: { fetch: (path: string) => Promise<Response> }; | |
} | |
let initialized = false; | |
const httpPlugin = { | |
name: 'http', | |
setup(build) { | |
// Resolve bare module imports (e.g. "lodash", "@scope/pkg"). | |
build.onResolve({ filter: /^[a-z@][^:]*$/ }, args => { | |
console.log("resolving", args.path) | |
// TODO: this is a hack to get the agents/mcp module to work | |
// TODO fix these issues | |
if(args.path === "agents/mcp") { | |
return { path: `https://cdn.jsdelivr.net/npm/agents/dist/mcp/index.js`, namespace: 'http-url' }; | |
} else if(args.path === "node:async_hooks") { | |
// mark as external | |
return { external: true }; | |
} | |
return { path: `https://cdn.jsdelivr.net/npm/${args.path}/+esm`, namespace: 'http-url' }; | |
}); | |
// Resolve relative paths inside modules. | |
build.onResolve({ filter: /.*/, namespace: 'http-url' }, args => { | |
if (args.path.startsWith('node:')) { | |
console.log(`Marking nested import ${args.path} as external`); | |
return { path: args.path, external: true }; | |
} | |
const url = new URL(args.path, args.importer).toString(); | |
return { path: url, namespace: 'http-url' }; | |
}); | |
// Load module contents from the resolved HTTP URL. | |
build.onLoad({ filter: /.*/, namespace: 'http-url' }, async args => { | |
try { | |
const res = await fetch(args.path); | |
if (!res.ok) throw new Error(`Failed to fetch ${args.path}: ${res.statusText}`); | |
const contents = await res.text(); | |
return { contents, loader: 'js' }; | |
} catch (err) { | |
throw new Error(`Failed to load ${args.path}: ${err.message}`); | |
} | |
}); | |
} | |
}; | |
// Simple minification function | |
async function minifyCode(inputScript: string): Promise<any> { | |
const result = await esbuild.build({ | |
stdin: { | |
contents: inputScript, | |
loader: 'ts', | |
}, | |
conditions: ['worker', 'browser'], | |
target: 'es2020', | |
bundle: true, | |
write: false, | |
format: 'esm', | |
minify: false, | |
platform: 'browser', | |
define: { | |
IS_CLOUDFLARE_WORKER: 'true' | |
}, | |
plugins: [httpPlugin, NodeModulesPolyfillPlugin()], | |
external: ['node:async_hooks', 'cloudflare:kv', 'cloudflare:queues', 'cloudflare:cloudflare', 'cloudflare:cloudflare-worker'] | |
}); | |
console.log("result"); | |
console.log(result); | |
return result; | |
} | |
export default { | |
async fetch(request: Request, env: Env, ctx: ExecutionContext): Promise<Response> { | |
if (!initialized) { | |
await esbuild.initialize({ | |
wasmModule: wasm, | |
worker: false | |
}) | |
initialized = true; | |
} | |
// Handle OPTIONS request for CORS | |
if (request.method === 'OPTIONS') { | |
return new Response(null, { | |
headers: { | |
'Access-Control-Allow-Origin': '*', | |
'Access-Control-Allow-Methods': 'POST, OPTIONS', | |
'Access-Control-Allow-Headers': 'Content-Type', | |
}, | |
}); | |
} | |
// Only accept POST requests | |
if (request.method !== 'POST') { | |
return new Response('Please send a POST request with JavaScript code to bundle', { | |
status: 405, | |
}); | |
} | |
try { | |
// Parse the request body | |
const requestData: BundleRequest = await request.json(); | |
if (!requestData.code) { | |
return new Response('Please provide JavaScript code in the "code" field', { | |
status: 400, | |
}); | |
} | |
// Process the code | |
let processedCode = requestData.code; | |
// Minify if requested | |
if (requestData.minify) { | |
processedCode = await minifyCode(processedCode); | |
} | |
// Return the processed code | |
return new Response(JSON.stringify({ | |
code: processedCode, | |
warnings: [], | |
}), { | |
headers: { | |
'Content-Type': 'application/json', | |
'Access-Control-Allow-Origin': '*', | |
'Access-Control-Allow-Methods': 'POST, OPTIONS', | |
'Access-Control-Allow-Headers': 'Content-Type', | |
}, | |
}); | |
} catch (error) { | |
console.error('Error:', error); | |
return new Response(JSON.stringify({ | |
error: error instanceof Error ? error.message : 'An unknown error occurred', | |
stack: error instanceof Error ? error.stack : undefined, | |
}), { | |
status: 500, | |
headers: { | |
'Content-Type': 'application/json', | |
'Access-Control-Allow-Origin': '*', | |
}, | |
}); | |
} | |
}, | |
} satisfies ExportedHandler<Env>; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment