Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save sanandnarayan/efe459d21b63e5b04bd4ff872570551a to your computer and use it in GitHub Desktop.
Save sanandnarayan/efe459d21b63e5b04bd4ff872570551a to your computer and use it in GitHub Desktop.
cloudflare bundler
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