Created
April 10, 2025 00:18
-
-
Save sanandnarayan/1b247e30aa96f38004bdf6f8256d5016 to your computer and use it in GitHub Desktop.
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
// @deno-types="https://deno.land/x/[email protected]/mod.d.ts" | |
import * as esbuild from "https://deno.land/x/[email protected]/wasm.js"; | |
import { serve } from "https://deno.land/[email protected]/http/server.ts"; | |
import { join } from "https://deno.land/[email protected]/path/mod.ts"; | |
const PORT = Number(Deno.env.get("PORT")) || 3000; | |
// Plugin to resolve bare module imports to a CDN URL and load them over HTTP. | |
const httpPlugin = { | |
name: 'http', | |
setup(build: esbuild.PluginBuild) { | |
// Resolve bare module imports (e.g. "lodash", "@scope/pkg"). | |
build.onResolve({ filter: /^[a-z@][^:]*$/ }, (args: esbuild.OnResolveArgs) => { | |
return { path: `https://cdn.skypack.dev/${args.path}`, namespace: 'http-url' }; | |
}); | |
// Resolve relative paths inside modules. | |
build.onResolve({ filter: /.*/, namespace: 'http-url' }, (args: esbuild.OnResolveArgs) => { | |
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: esbuild.OnLoadArgs) => { | |
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}`); | |
} | |
}); | |
} | |
}; | |
// Home page HTML | |
const homePage = `<!DOCTYPE html> | |
<html> | |
<head> | |
<title>esbuild Service (Deno)</title> | |
<meta charset="utf-8"> | |
<meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
<style> | |
body { | |
font-family: system-ui, -apple-system, sans-serif; | |
max-width: 800px; | |
margin: 0 auto; | |
padding: 2rem; | |
line-height: 1.5; | |
} | |
code { | |
background: #f0f0f0; | |
padding: 0.2em 0.4em; | |
border-radius: 3px; | |
} | |
.example { | |
margin-top: 1rem; | |
} | |
</style> | |
</head> | |
<body> | |
<h1>esbuild Service (Deno)</h1> | |
<p>Usage: /<code>package[@version][/(filePath)]</code>?minify=[true|false]&format=[esm|cjs|iife]</p> | |
<div class="example"> | |
<p>Examples:</p> | |
<ul> | |
<li><a href="/[email protected]/debounce?minify=false">lodash debounce (unminified)</a></li> | |
<li><a href="/[email protected]?minify=true">react (minified)</a></li> | |
</ul> | |
</div> | |
</body> | |
</html>`; | |
// Request handler | |
async function handler(req: Request): Promise<Response> { | |
const url = new URL(req.url); | |
const path = url.pathname; | |
// Handle home page | |
if (path === "/") { | |
return new Response(homePage, { | |
headers: { | |
"content-type": "text/html", | |
"cache-control": "public, max-age=3600" | |
}, | |
}); | |
} | |
// Ignore favicon requests | |
if (path === "/favicon.ico") { | |
return new Response(null, { status: 204 }); | |
} | |
try { | |
const pkg = path.substring(1); | |
const searchParams = url.searchParams; | |
const format = searchParams.get("format") || "esm"; | |
const minify = searchParams.get("minify") !== "false"; | |
console.log(`Processing request for package: ${pkg}`); | |
const result = await esbuild.build({ | |
entryPoints: [pkg], | |
bundle: true, | |
write: false, | |
format: format as esbuild.Format, | |
minify, | |
platform: "browser", | |
plugins: [httpPlugin], | |
}); | |
const bundledCode = result.outputFiles[0].text; | |
return new Response(bundledCode, { | |
headers: { | |
"content-type": "application/javascript", | |
"cache-control": "public, max-age=86400" | |
}, | |
}); | |
} catch (err) { | |
console.error("Build error:", err); | |
return new Response(`Build error: ${err.message}`, { | |
status: 500, | |
headers: { "content-type": "text/plain" } | |
}); | |
} | |
} | |
// Initialize esbuild | |
try { | |
await esbuild.initialize({ | |
worker: false, | |
wasmURL: "https://deno.land/x/[email protected]/esbuild.wasm" | |
}); | |
// Start the server | |
console.log(`Starting server on http://localhost:${PORT}`); | |
await serve(handler, { | |
port: PORT, | |
onListen: ({ port, hostname }) => { | |
console.log(`Server is running on: http://${hostname}:${port}`); | |
}, | |
}); | |
} catch (error) { | |
console.error("Failed to start server:", error); | |
Deno.exit(1); | |
} finally { | |
// Cleanup when done | |
addEventListener("unload", () => { | |
esbuild.stop(); | |
}); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment