diff --git a/CHANGELOG.md b/CHANGELOG.md index 1b7ed6c8e832..61216bb469c4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,7 @@ ## Changelog ##### Unreleased - Added `inverse` option to `core-js-compat`, [#1119](https://github.com/zloirock/core-js/issues/1119) +- Added `format` option to `core-js-builder`, [#1120](https://github.com/zloirock/core-js/issues/1120) ##### [3.25.5 - 2022.10.04](https://github.com/zloirock/core-js/releases/tag/v3.25.5) - Fixed regression with an error on reuse of some built-in methods from another realm, [#1133](https://github.com/zloirock/core-js/issues/1133) diff --git a/package.json b/package.json index d47c592bab21..c37356698286 100644 --- a/package.json +++ b/package.json @@ -137,14 +137,15 @@ "test-entries-basic": "zx tests/commonjs.mjs", "test-entries-content": "zx tests/commonjs-entries-content.mjs", "test-entries-standalone": "run-s init test-entries", + "test-builder": "zx tests/builder/builder.mjs", "test-compat-tools": "run-p test-compat-tool test-compat-targets-parser test-compat-get-modules-list-for-target-version", "test-compat-tool": "zx tests/compat-tools/compat.mjs", "test-compat-targets-parser": "zx tests/compat-tools/targets-parser.mjs", "test-compat-get-modules-list-for-target-version": "zx tests/compat-tools/get-modules-list-for-target-version.mjs", "test262": "test262-harness -t \"$(node -pe 'os.cpus().length')\" --host-args='--unhandled-rejections=none' --preprocessor=./tests/test262.js --prelude=./packages/core-js-bundle/index.js --test262-dir=node_modules/test262 'node_modules/test262/test/built-ins/**/*.js'", - "test": "run-s init test-lint bundle test-unit test-promises test-observables test-entries test-compat-tools check", + "test": "run-s init test-lint bundle test-unit test-promises test-observables test-entries test-compat-tools test-builder check", "ci-karma": "run-s init bundle test-unit-karma", - "ci-tests": "run-s init bundle test-unit-node test-promises test-observables test-entries test-compat-tools", + "ci-tests": "run-s init bundle test-unit-node test-promises test-observables test-entries test-compat-tools test-builder", "clean-dependencies": "node scripts/clean-dependencies.mjs", "refresh": "npm run clean-dependencies && npm it", "downloads": "zx scripts/downloads-by-versions.mjs", diff --git a/packages/core-js-builder/README.md b/packages/core-js-builder/README.md index 96d5847dd764..b36a7a8d3f61 100644 --- a/packages/core-js-builder/README.md +++ b/packages/core-js-builder/README.md @@ -12,13 +12,23 @@ For some cases could be useful to exclude some `core-js` features or generate a import builder from 'core-js-builder'; const bundle = await builder({ - modules: ['core-js/actual', 'esnext.reflect'], // entries / modules / namespaces, by default - all `core-js` modules - exclude: [/^es\.math\./, 'es.number.constructor'], // a blacklist of entries / modules / namespaces, by default - empty list - targets: '> 0.5%, not dead, ie 9-11', // optional browserslist or core-js-compat format query - summary: { // shows summary for the bundle, disabled by default: - console: { size: true, modules: false }, // in the console, you could specify required parts or set `true` for enable all of them - comment: { size: false, modules: true }, // in the comment in the target file, similarly to `summary.console` + // entry / module / namespace / an array of them, by default - all `core-js` modules + modules: ['core-js/actual', /^esnext\.reflect\./], + // a blacklist of entries / modules / namespaces, by default - empty list + exclude: [/^es\.math\./, 'es.number.constructor'], + // optional browserslist or core-js-compat format query + targets: '> 0.5%, not dead, ie 9-11', + // shows summary for the bundle, disabled by default + summary: { + // in the console, you could specify required parts or set `true` for enable all of them + console: { size: true, modules: false }, + // in the comment in the target file, similarly to `summary.console` + comment: { size: false, modules: true }, }, - filename: PATH_TO_MY_COREJS_BUNDLE, // optional target filename, if it's missed a file will not be created + // output format, 'bundle' by default, can be 'cjs' or 'esm', and in this case + // the result will not be bundled and will contain imports of required modules + format: 'bundle', + // optional target filename, if it's missed a file will not be created + filename: PATH_TO_MY_COREJS_BUNDLE, }); ``` diff --git a/packages/core-js-builder/index.js b/packages/core-js-builder/index.js index 7cca7bcb0e1f..411ce39ab752 100644 --- a/packages/core-js-builder/index.js +++ b/packages/core-js-builder/index.js @@ -29,44 +29,53 @@ module.exports = async function ({ blacklist = null, // TODO: Obsolete, remove from `core-js@4` exclude = [], targets = null, + format = 'bundle', filename = null, summary = {}, } = {}) { + if (!['bundle', 'cjs', 'esm'].includes(format)) throw TypeError('Incorrect output type'); summary = { comment: normalizeSummary(summary.comment), console: normalizeSummary(summary.console) }; const TITLE = filename != null ? filename : '`core-js`'; let script = banner; - let code = ''; + let code = '\n'; const { list, targets: compatTargets } = compat({ targets, modules, exclude: exclude || blacklist }); if (list.length) { - const tempFileName = `core-js-${ Math.random().toString(36).slice(2) }.js`; - const tempFile = join(tmpdir, tempFileName); + if (format === 'bundle') { + const tempFileName = `core-js-${ Math.random().toString(36).slice(2) }.js`; + const tempFile = join(tmpdir, tempFileName); - await webpack({ - mode: 'none', - node: { - global: false, - process: false, - setImmediate: false, - }, - entry: list.map(it => require.resolve(`core-js/modules/${ it }`)), - output: { - filename: tempFileName, - hashFunction: 'md5', - path: tmpdir, - }, - }); + await webpack({ + mode: 'none', + node: { + global: false, + process: false, + setImmediate: false, + }, + entry: list.map(it => require.resolve(`core-js/modules/${ it }`)), + output: { + filename: tempFileName, + hashFunction: 'md5', + path: tmpdir, + }, + }); - const file = await readFile(tempFile); + const file = await readFile(tempFile); - await unlink(tempFile); + await unlink(tempFile); - code = `!function (undefined) { 'use strict'; ${ - // compress `__webpack_require__` with `keep_fnames` option - String(file).replace(/function __webpack_require__/, 'var __webpack_require__ = function ') - } }();`; + code = `!function (undefined) { 'use strict'; ${ + // compress `__webpack_require__` with `keep_fnames` option + String(file).replace(/function __webpack_require__/, 'var __webpack_require__ = function ') + } }();\n`; + } else { + const template = it => format === 'esm' + ? `import 'core-js/modules/${ it }.js';\n` + : `require('core-js/modules/${ it }');\n`; + code = list.map(template).join(''); + } } if (summary.comment.size) script += `/*\n * size: ${ (code.length / 1024).toFixed(2) }KB w/o comments\n */`; @@ -81,9 +90,9 @@ module.exports = async function ({ if (summary.console.modules) { console.log(`\u001B[32mbundling \u001B[36m${ TITLE }\u001B[32m, modules:\u001B[0m`); - for (const it of list) { + if (list.length) for (const it of list) { console.log(`\u001B[36m${ it + (targets ? ` \u001B[32mfor \u001B[36m${ JSON.stringify(compatTargets[it]) }` : '') }\u001B[0m`); - } + } else console.log('\u001B[36mnothing\u001B[0m'); } if (filename != null) { diff --git a/tests/builder/builder.mjs b/tests/builder/builder.mjs new file mode 100644 index 000000000000..61fc5c8aadf7 --- /dev/null +++ b/tests/builder/builder.mjs @@ -0,0 +1,19 @@ +import { ok } from 'assert/strict'; +import builder from 'core-js-builder'; + +const polyfills = await builder({ + modules: 'core-js/actual', + exclude: [/group-by/, 'esnext.typed-array.to-spliced'], + targets: { node: 16 }, + format: 'esm', +}); + +ok(polyfills.includes("import 'core-js/modules/es.error.cause.js';"), 'actual node 16 #1'); +ok(polyfills.includes("import 'core-js/modules/es.array.push.js';"), 'actual node 16 #2'); +ok(polyfills.includes("import 'core-js/modules/esnext.array.group.js';"), 'actual node 16 #3'); +ok(polyfills.includes("import 'core-js/modules/web.structured-clone.js';"), 'actual node 16 #4'); +ok(!polyfills.includes("import 'core-js/modules/es.weak-set.js';"), 'actual node 16 #5'); +ok(!polyfills.includes("import 'core-js/modules/esnext.weak-set.from.js';"), 'actual node 16 #6'); +ok(!polyfills.includes("import 'core-js/modules/esnext.array.group-by.js';"), 'actual node 16 #7'); + +echo(chalk.green('builder tested'));