Skip to content

Instantly share code, notes, and snippets.

@randallb
Last active November 27, 2022 04:28
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save randallb/4b218b78e6c3a73ef4a835c88914aaad to your computer and use it in GitHub Desktop.
Save randallb/4b218b78e6c3a73ef4a835c88914aaad to your computer and use it in GitHub Desktop.
I wrote a thing that should be executable in deno...
// this should be executable in deno.
// `deno run --allow-read --allow-write --allow-run --allow-net --allow-env packages/app/esbuild.ts`
import * as esbuild from "https://deno.land/x/esbuild@v0.15.15/mod.js";
const ts = `
import * as log from "https://deno.land/std@0.165.0/log/mod.ts";
import App from "/packages/app/Test.tsx";
console.log('wow');
log.info('such wow');
export default function Example() {
return <h1>hi</h1>
}
console.log(String(Example));
log.info(import.meta)
console.log(String(App));
`;
const LOCAL_NAMESPACE = "deno-local";
const REMOTE_NAMESPACE = "deno-remote";
async function fetchSourceMap(url: URL) {
const map = await fetch(url);
const type = map.headers.get("content-type") ?? undefined;
const buffer = await map.arrayBuffer();
const blob = new Blob([buffer], { type });
const reader = new FileReader();
return new Promise((cb) => {
reader.onload = (e) => cb(e.target?.result);
reader.readAsDataURL(blob);
});
}
// regex to match urls which start with http or https
const remoteUrlRegex = /^https?:\/\//;
const denoPlugin = {
name: "deno",
setup(build) {
const { onResolve, onLoad } = build;
onResolve({ filter: remoteUrlRegex }, (args) => {
return { path: args.path, namespace: REMOTE_NAMESPACE };
});
onResolve({ filter: /.*/, namespace: REMOTE_NAMESPACE }, (args) => {
const path = new URL(args.path, args.importer).href;
const namespace = REMOTE_NAMESPACE;
return { path, namespace };
});
onResolve({ filter: /.*/ }, (args) => {
if (args.kind === "entry-point") {
return;
}
const resolvedPath = import.meta.resolve(args.path);
if (resolvedPath.startsWith("file://")) {
const path = resolvedPath.replace("file://", "");
return {
path,
namespace: LOCAL_NAMESPACE,
};
}
if (resolvedPath.startsWith("http")) {
const path = new URL(resolvedPath).href;
return {
path,
namespace: REMOTE_NAMESPACE,
};
}
});
function getLoader(extension: string) {
const validExtensions = [".js", ".jsx", ".ts", ".tsx"];
if (validExtensions.includes(extension)) {
return extension;
}
return "ts";
}
// pulled from https://github.com/jed/esbuild-plugin-http-fetch/blob/main/index.js#L28
onLoad({ filter: /.*/, namespace: REMOTE_NAMESPACE }, async (args) => {
const source = await fetch(args.path);
if (!source.ok) {
throw new Error(
`Failed to fetch ${args.path}: ${source.status} ${source.statusText}`,
);
}
let contents = await source.text();
const pattern = /\/\/# sourceMappingURL=(\S+)/;
const match = contents.match(pattern);
if (match) {
const sourceMapUrl = new URL(match[1], args.path);
const dataurl = await fetchSourceMap(sourceMapUrl);
const comment = `//# sourceMappingURL=${dataurl}`;
contents = contents.replace(pattern, comment);
}
const { pathname } = new URL(source.url);
const ext = pathname.match(/[^.]+$/);
const loader = getLoader(ext ? ext[0] : "");
return { contents, loader };
});
onLoad({ filter: /.*/, namespace: LOCAL_NAMESPACE }, async (args) => {
const source = await Deno.readTextFile(args.path);
const ext = args.path.match(/[^.]+$/);
const loader = ext ? ext[0] : "ts";
return { contents: source, loader };
});
},
};
await Deno.writeTextFile("/Users/randallb/rbcode/tmp.tsx", ts);
const result = await esbuild.build({
bundle: true,
entryPoints: ["/Users/randallb/rbcode/tmp.tsx"],
write: false,
outdir: "out",
plugins: [denoPlugin],
});
esbuild.stop();
const textDecoder = new TextDecoder();
const { contents } = result.outputFiles[0];
const str = textDecoder.decode(contents);
const mdxModule = await import(
"data:application/typescript;base64," + btoa(str)
);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment