Created
October 7, 2022 22:40
-
-
Save connorjclark/5535d586af717e1d503cc71de31d840c to your computer and use it in GitHub Desktop.
This file contains 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
// This is @esbuild-plugins/node-modules-polyfill, but using a better library | |
// for polyfills. It was done in this PR which has not merged: | |
// https://github.com/remorses/esbuild-plugins/pull/19 | |
import fs from 'fs'; | |
import path from 'path'; | |
import escapeStringRegexp from 'escape-string-regexp'; | |
import esbuild from 'esbuild'; | |
import {getModules as builtinsPolyfills} from 'rollup-plugin-polyfill-node/dist/modules.js'; | |
import polyfillLib from 'rollup-plugin-polyfill-node/dist/polyfills.js'; | |
// import { NodeResolvePlugin } from '@esbuild-plugins/node-resolve' | |
const NAME = 'node-modules-polyfills'; | |
const NAMESPACE = NAME; | |
function removeEndingSlash(importee) { | |
if (importee && importee.slice(-1) === '/') { | |
importee = importee.slice(0, -1); | |
} | |
return importee; | |
} | |
function nodeModulesPolyfillPlugin( | |
options = {} | |
) { | |
const {namespace = NAMESPACE, name = NAME} = options; | |
if (namespace.endsWith('commonjs')) { | |
throw new Error(`namespace ${namespace} must not end with commonjs`); | |
} | |
// this namespace is needed to make ES modules expose their default export to require: require('assert') will give you import('assert').default | |
const commonjsNamespace = namespace + '-commonjs'; | |
const polyfilledBuiltins = builtinsPolyfills(); | |
const polyfilledBuiltinsNames = [...polyfilledBuiltins.keys()]; | |
return { | |
name, | |
setup: function setup({onLoad, onResolve, initialOptions}) { | |
// polyfills contain global keyword, it must be defined | |
if (initialOptions?.define && !initialOptions.define?.global) { | |
initialOptions.define['global'] = 'globalThis'; | |
} else if (!initialOptions?.define) { | |
initialOptions.define = {global: 'globalThis'}; | |
} | |
// TODO these polyfill module cannot import anything, is that ok? | |
async function loader( | |
args | |
) { | |
try { | |
const isCommonjs = args.namespace.endsWith('commonjs'); | |
const key = removeEndingSlash(args.path); | |
const contents = polyfilledBuiltins.get(key) || polyfillLib[key + '.js']; | |
const resolveDir = path.dirname(key); | |
if (isCommonjs) { | |
return { | |
loader: 'js', | |
contents: commonJsTemplate({ | |
importPath: args.path, | |
}), | |
resolveDir, | |
}; | |
} | |
return { | |
loader: 'js', | |
contents, | |
resolveDir, | |
}; | |
} catch (e) { | |
console.error('node-modules-polyfill', e); | |
return { | |
contents: `export {}`, | |
loader: 'js', | |
}; | |
} | |
} | |
onLoad({filter: /.*/, namespace}, loader); | |
onLoad({filter: /.*/, namespace: commonjsNamespace}, loader); | |
const filter = new RegExp( | |
polyfilledBuiltinsNames.map(escapeStringRegexp).join('|') // TODO builtins could end with slash, keep in mind in regex | |
); | |
async function resolver(args) { | |
const ignoreRequire = args.namespace === commonjsNamespace; | |
let key; | |
if (args.path.startsWith('\0polyfill-node.')) { | |
key = args.path.replace('\0polyfill-node.', ''); | |
} else { | |
if (args.path.startsWith('.')) { | |
key = path.join(path.dirname(args.importer), args.path); | |
} else { | |
key = args.path; | |
} | |
} | |
if (!polyfilledBuiltins.has(key) && !polyfillLib[key + '.js']) { | |
return; | |
} | |
const isCommonjs = | |
!ignoreRequire && args.kind === 'require-call'; | |
return { | |
namespace: isCommonjs ? commonjsNamespace : namespace, | |
path: key, | |
}; | |
} | |
onResolve({filter}, resolver); | |
onResolve({ filter: /.*/, namespace }, resolver); | |
}, | |
}; | |
} | |
function commonJsTemplate({importPath}) { | |
return ` | |
const polyfill = require('${importPath}') | |
if (polyfill && polyfill.default) { | |
module.exports = polyfill.default | |
for (let k in polyfill) { | |
module.exports[k] = polyfill[k] | |
} | |
} else if (polyfill) { | |
module.exports = polyfill | |
} | |
`; | |
} | |
export {nodeModulesPolyfillPlugin}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment