UNPKG

esbuild-plugins-node-modules-polyfill

Version:
228 lines (223 loc) 10.1 kB
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' }); //#region \0rolldown/runtime.js var __create = Object.create; var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __getProtoOf = Object.getPrototypeOf; var __hasOwnProp = Object.prototype.hasOwnProperty; var __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") { for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) { key = keys[i]; if (!__hasOwnProp.call(to, key) && key !== except) { __defProp(to, key, { get: ((k) => from[k]).bind(null, key), enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } } } return to; }; var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, mod)); //#endregion let node_module = require("node:module"); let node_path = require("node:path"); node_path = __toESM(node_path); let node_process = require("node:process"); node_process = __toESM(node_process); let local_pkg = require("local-pkg"); let esbuild = require("esbuild"); let resolve_exports = require("resolve.exports"); //#region src/lib/utils/util.ts const escapeRegex = (str) => str.replace(/[$()*+.?[\\\]^{|}]/g, "\\$&").replace(/-/g, "\\x2d"); const commonJsTemplate = ({ importPath }) => `export * from '${importPath}'`; const normalizeNodeBuiltinPath = (path) => path.replace(/^node:/, "").replace(/\/$/, ""); //#endregion //#region src/lib/polyfill.ts async function polyfillPath(importPath) { if (!node_module.builtinModules.includes(importPath)) throw new Error(`Node.js does not have ${importPath} in its builtin modules`); const jspmPath = (0, node_path.resolve)(require.resolve(`@jspm/core/nodelibs/${importPath}`), "../../.." + (importPath.includes("/") ? "/.." : "")); const exportPath = (0, resolve_exports.resolve)(await (0, local_pkg.loadPackageJSON)(jspmPath), `./nodelibs/${importPath}`, { browser: true }); const exportFullPath = (0, local_pkg.resolveModule)((0, node_path.join)(jspmPath, exportPath?.[0] ?? "")); if (!exportPath || !exportFullPath) throw new Error("resolving failed, please try creating an issue in https://github.com/imranbarbhuiya/esbuild-plugins-node-modules-polyfill"); return exportFullPath; } const polyfillPathCache = /* @__PURE__ */ new Map(); const polyfillOverrides = /* @__PURE__ */ new Map(); const setPolyfillOverrides = (overrides) => { polyfillOverrides.clear(); for (const [moduleName, customPath] of Object.entries(overrides)) { const normalizedModuleName = normalizeNodeBuiltinPath(moduleName); polyfillOverrides.set(normalizedModuleName, customPath); } }; const getCachedPolyfillPath = (importPath) => { const normalizedImportPath = normalizeNodeBuiltinPath(importPath); const override = polyfillOverrides.get(normalizedImportPath); if (override) return Promise.resolve(override); const cachedPromise = polyfillPathCache.get(normalizedImportPath); if (cachedPromise) return cachedPromise; const promise = polyfillPath(normalizedImportPath); polyfillPathCache.set(normalizedImportPath, promise); return promise; }; const polyfillContentAndTransform = async (importPath) => { return (await (0, esbuild.build)({ write: false, format: "esm", bundle: true, entryPoints: [await getCachedPolyfillPath(importPath)] })).outputFiles[0].text.replace(/eval\(/g, "(0,eval)("); }; const polyfillContentCache = /* @__PURE__ */ new Map(); const getCachedPolyfillContent = (importPath) => { const normalizedImportPath = normalizeNodeBuiltinPath(importPath); const cachedPromise = polyfillContentCache.get(normalizedImportPath); if (cachedPromise) return cachedPromise; const promise = polyfillContentAndTransform(normalizedImportPath); polyfillContentCache.set(normalizedImportPath, promise); return promise; }; //#endregion //#region src/lib/plugin.ts const NAME = "node-modules-polyfills"; const loader = async (args) => { try { const isCommonjs = args.namespace.endsWith("commonjs"); const resolved = await getCachedPolyfillPath(args.path); const resolveDir = node_path.default.dirname(resolved); if (isCommonjs) return { loader: "js", contents: commonJsTemplate({ importPath: args.path }), resolveDir }; return { loader: "js", contents: await getCachedPolyfillContent(args.path), resolveDir }; } catch (error) { console.error("node-modules-polyfill", error); return { contents: `export {}`, loader: "js" }; } }; const nodeModulesPolyfillPlugin = (options = {}) => { const { globals = {}, modules: modulesOption = node_module.builtinModules, fallback = "none", formatError, namespace = NAME, name = NAME, overrides = {} } = options; if (namespace.endsWith("commonjs")) throw new Error(`namespace ${namespace} must not end with commonjs`); if (namespace.endsWith("empty")) throw new Error(`namespace ${namespace} must not end with empty`); if (namespace.endsWith("error")) throw new Error(`namespace ${namespace} must not end with error`); if (Object.keys(overrides).length > 0) setPolyfillOverrides(overrides); const modules = Array.isArray(modulesOption) ? Object.fromEntries(modulesOption.map((mod) => [mod, true])) : modulesOption; const commonjsNamespace = `${namespace}-commonjs`; const emptyNamespace = `${namespace}-empty`; const errorNamespace = `${namespace}-error`; const shouldDetectErrorModules = fallback === "error" || Object.values(modules).includes("error"); return { name, setup: ({ onLoad, onResolve, onEnd, initialOptions }) => { if (shouldDetectErrorModules && initialOptions.write !== false) throw new Error(`The "write" build option must be set to false when using the "error" polyfill type`); const root = initialOptions.absWorkingDir ?? node_process.default.cwd(); if (initialOptions.define && !initialOptions.define.global) initialOptions.define.global = "globalThis"; else if (!initialOptions.define) initialOptions.define = { global: "globalThis" }; initialOptions.inject = initialOptions.inject ?? []; if (globals.Buffer) initialOptions.inject.push(node_path.default.resolve(__dirname, "../globals/Buffer.js")); if (globals.process) initialOptions.inject.push(node_path.default.resolve(__dirname, "../globals/process.js")); onLoad({ filter: /.*/, namespace: emptyNamespace }, () => ({ loader: "js", contents: "module.exports = {}" })); onLoad({ filter: /.*/, namespace: errorNamespace }, (args) => ({ loader: "js", contents: `module.exports = ${JSON.stringify(`__POLYFILL_ERROR_START__::MODULE::${args.path}::IMPORTER::${args.pluginData.importer}::__POLYFILL_ERROR_END__`)}` })); onLoad({ filter: /.*/, namespace }, loader); onLoad({ filter: /.*/, namespace: commonjsNamespace }, loader); const bundledModules = fallback === "none" ? Object.keys(modules).filter((moduleName) => node_module.builtinModules.includes(moduleName)) : node_module.builtinModules; const filter = new RegExp(`^(?:node:)?(?:${bundledModules.map(escapeRegex).join("|")})$`); const resolver = async (args) => { const result = { empty: { namespace: emptyNamespace, path: args.path, sideEffects: false }, error: { namespace: errorNamespace, path: args.path, sideEffects: false, pluginData: { importer: node_path.default.relative(root, args.importer).replace(/\\/g, "/") } }, none: void 0 }; if (initialOptions.platform === "browser") { const browserFieldValue = (await (0, local_pkg.loadPackageJSON)(args.resolveDir))?.browser; if (typeof browserFieldValue === "string") return; const browserFieldValueForModule = browserFieldValue?.[args.path]; if (browserFieldValueForModule === false) return result.empty; if (browserFieldValueForModule !== void 0) return; } const moduleName = normalizeNodeBuiltinPath(args.path); const polyfillOption = modules[moduleName] ?? modules[`node:${moduleName}`]; if (!polyfillOption) return result[fallback]; if (polyfillOption === "error" || polyfillOption === "empty") return result[polyfillOption]; if (!await getCachedPolyfillPath(moduleName).catch(() => null)) return result[fallback]; return { namespace: !(args.namespace === commonjsNamespace) && args.kind === "require-call" ? commonjsNamespace : namespace, path: args.path, sideEffects: false }; }; onResolve({ filter }, resolver); onEnd(async ({ outputFiles = [] }) => { if (!shouldDetectErrorModules) return; const errors = []; const { outfile, outExtension = {} } = initialOptions; const jsExtension = outfile ? node_path.default.extname(outfile) : outExtension[".js"] || ".js"; const jsFiles = outputFiles.filter((file) => node_path.default.extname(file.path) === jsExtension); for (const file of jsFiles) { const matches = file.text.matchAll(/__POLYFILL_ERROR_START__::MODULE::(?<moduleName>.+?)::IMPORTER::(?<importer>.+?)::__POLYFILL_ERROR_END__/g); for (const { groups } of matches) { const { moduleName, importer } = groups; const polyfillExists = await getCachedPolyfillPath(moduleName).catch(() => null) !== null; errors.push({ pluginName: name, text: polyfillExists ? `Polyfill has not been configured for "${moduleName}", imported by "${importer}"` : `Polyfill does not exist for "${moduleName}", imported by "${importer}"`, ...formatError ? await formatError({ moduleName, importer, polyfillExists }) : {} }); } } return { errors }; }); } }; }; //#endregion exports.commonJsTemplate = commonJsTemplate; exports.escapeRegex = escapeRegex; exports.nodeModulesPolyfillPlugin = nodeModulesPolyfillPlugin; exports.normalizeNodeBuiltinPath = normalizeNodeBuiltinPath; //# sourceMappingURL=index.js.map