@lit-protocol/esbuild-plugin-polyfill-node
Version:
ESBuild plugin for polyfilling Node.js builtins for edge and Deno
246 lines (245 loc) • 7 kB
JavaScript
// src/index.ts
import { fileURLToPath, pathToFileURL } from "url";
import { resolve, dirname } from "path";
var filename = typeof __filename === "undefined" ? fileURLToPath(import.meta.url) : __filename;
var importMetaUrl = import.meta.url ?? pathToFileURL(filename).href;
function polyfillNode(options = {}) {
const { globals = {}, polyfills = {} } = options;
const {
global = true,
__dirname = true,
__filename: __filename2 = true,
buffer = true,
process = true,
navigator = false,
denoBuildOs = "linux"
} = globals || {
global: false,
__dirname: false,
__filename: false,
buffer: false,
process: false,
navigator: false,
denoBuildOs: "linux"
};
polyfills.fs = polyfills.fs ?? "empty";
polyfills.crypto = polyfills.crypto ?? "empty";
polyfills.dns = polyfills.dns ?? "empty";
polyfills.dgram = polyfills.dgram ?? "empty";
polyfills.cluster = polyfills.cluster ?? "empty";
polyfills.repl = polyfills.repl ?? "empty";
polyfills.tls = polyfills.tls ?? "empty";
const moduleNames = [...jspmPolyiflls];
const filter = new RegExp(`^(node:)?(${moduleNames.join("|")})$`);
return {
name: "node-polyfills",
async setup(build) {
var _a;
if (denoBuildOs !== false) {
const desired = typeof denoBuildOs === "string" ? denoBuildOs : "x64";
const snippet = `;(()=>{try{const g=globalThis;const D=(g.Deno=g.Deno||{});const B=(D.build=D.build||{});if(B.os==null){B.os=${JSON.stringify(desired)};}}catch{}})();`;
const prev = ((_a = build.initialOptions.banner) == null ? void 0 : _a.js) ?? "";
build.initialOptions.banner = {
...build.initialOptions.banner ?? {},
// Prepend to ensure we’re literally first.
js: snippet + (prev ? "\n" + prev : "")
};
}
const fsResolved = await resolveImport(`@jspm/core/nodelibs/fs`);
build.onResolve({ filter }, async ({ path }) => {
const [, , moduleName] = path.match(filter);
const polyfill = polyfills[moduleName] ?? true;
if (polyfill === false) {
return;
} else if (polyfill === "empty") {
return { path: resolve(dirname(filename), "../polyfills/empty.js") };
} else if (!jspmPolyiflls.has(moduleName)) {
throw new Error("Cannot find polyfill for " + moduleName);
}
const resolved = resolve(fsResolved, `../../browser/${moduleName}.js`);
return { path: resolved };
});
if (globals) {
build.initialOptions.inject = build.initialOptions.inject || [];
if (global) {
resolve(dirname(filename), "../polyfills/global.js");
}
if (__dirname) {
build.initialOptions.inject.push(
resolve(dirname(filename), "../polyfills/__dirname.js")
);
}
if (__filename2) {
resolve(dirname(filename), "../polyfills/__filename.js");
}
if (buffer) {
build.initialOptions.inject.push(
resolve(dirname(filename), "../polyfills/buffer.js")
);
}
if (process) {
build.initialOptions.inject.push(
resolve(dirname(filename), "../polyfills/process.js")
);
}
if (navigator) {
build.initialOptions.inject.push(
resolve(dirname(filename), "../polyfills/navigator.js")
);
}
}
}
};
}
function polyfillNodeForDeno(options = {}) {
const { stdVersion = "0.177.0", globals = true, polyfills = {} } = options;
const moduleNames = [.../* @__PURE__ */ new Set([...denoPolyfills])];
const filter = new RegExp(`^(node:)?(${moduleNames.join("|")})$`);
return {
name: "node-polyfills",
setup(build) {
build.onResolve(
{
filter: /^virtual:deno-std-node-global$/
},
() => ({
path: `https://deno.land/std@${stdVersion}/node/global.ts`,
external: true
})
);
build.onResolve({ filter }, async ({ path }) => {
const [, , moduleName] = path.match(filter);
const polyfill = polyfills[moduleName] ?? true;
if (polyfill === false) {
return;
} else if (polyfill === "empty") {
return {
path: resolve(dirname(filename), "../polyfills/empty.js")
};
} else {
if (!denoPolyfills.has(moduleName)) {
throw new Error("Cannot find the Deno polyfill for " + moduleName);
}
return {
path: `https://deno.land/std@${stdVersion}/node/${moduleName}.ts`,
external: true
};
}
});
build.onLoad({ namespace: "polyfillNodeForDeno", filter: /.*/ }, () => ({
contents: denoGlobalsContents(stdVersion)
}));
if (globals) {
build.initialOptions.footer;
build.initialOptions.inject = build.initialOptions.inject || [];
build.initialOptions.inject.push(
resolve(dirname(filename), "../polyfills/global-for-deno.js"),
resolve(dirname(filename), "../polyfills/__dirname.js"),
resolve(dirname(filename), "../polyfills/__filename.js")
);
}
}
};
}
var jspmPolyiflls = /* @__PURE__ */ new Set([
"_stream_duplex",
"_stream_passthrough",
"_stream_readable",
"_stream_transform",
"_stream_writable",
"assert",
"assert/strict",
"async_hooks",
"buffer",
"child_process",
"cluster",
"console",
"constants",
"crypto",
"dgram",
"diagnostics_channel",
"dns",
"domain",
"events",
"fs",
"fs/promises",
"http",
"http2",
"https",
"module",
"net",
"os",
"path",
"perf_hooks",
"process",
"punycode",
"querystring",
"readline",
"repl",
"stream",
"string_decoder",
"sys",
"timers",
"timers/promises",
"tls",
"tty",
"url",
"util",
"v8",
"vm",
"wasi",
"worker_threads",
"zlib"
]);
var denoPolyfills = /* @__PURE__ */ new Set([
"assert",
"assert/strict",
"buffer",
"console",
"constants",
"crypto",
"child_process",
"dns",
"events",
"fs",
"fs/promises",
"http",
"module",
"net",
"os",
"path",
"perf_hooks",
"process",
"querystring",
"readline",
"stream",
"string_decoder",
"sys",
"timers",
"timers/promises",
"tty",
"url",
"util",
"worker_threads"
]);
var importMetaResolve;
async function resolveImport(specifier) {
if (!importMetaResolve) {
importMetaResolve = (await import("import-meta-resolve")).resolve;
}
const resolved = await importMetaResolve(specifier, importMetaUrl);
return fileURLToPath(resolved);
}
function denoGlobalsContents(stdVersion) {
return `
import "https://deno.land/std@${stdVersion}/node/global.ts";
export const process = globalThis.process;
export const Buffer = globalThis.Buffer;
export const setImmediate = globalThis.setImmediate;
export const clearImmediate = globalThis.clearImmediate;
`;
}
export {
polyfillNode,
polyfillNodeForDeno
};