diff --git a/src/cli.js b/src/cli.js index 6e4a8e53..429ae953 100755 --- a/src/cli.js +++ b/src/cli.js @@ -5,7 +5,7 @@ const glob = require("glob"); const shebangRegEx = require("./utils/shebang"); const rimraf = require("rimraf"); const crypto = require("crypto"); -const { writeFileSync, unlink, existsSync, symlinkSync } = require("fs"); +const { writeFileSync, unlink, existsSync, symlinkSync, mkdir } = require("fs"); const mkdirp = require("mkdirp"); const { version: nccVersion } = require('../package.json'); @@ -24,6 +24,8 @@ Commands: Options: -o, --out [file] Output directory for build (defaults to dist) + + --esm Create an ES Module build output -m, --minify Minify output -C, --no-cache Skip build cache population -s, --source-map Generate source map @@ -129,6 +131,7 @@ async function runCmd (argv, stdout, stderr) { args = require("arg")({ "--debug": Boolean, "-d": "--debug", + "--esm": Boolean, "--external": [String], "-e": "--external", "--out": String, @@ -218,6 +221,8 @@ async function runCmd (argv, stdout, stderr) { ); if (existsSync(outDir)) rimraf.sync(outDir); + mkdirp.sync(outDir); + writeFileSync(eval('resolve')(outDir, 'package.json'), args['--esm'] ? '{ "type": "module" }' : '{}'); run = true; // fallthrough @@ -228,12 +233,13 @@ async function runCmd (argv, stdout, stderr) { let startTime = Date.now(); let ps; const buildFile = eval("require.resolve")(resolve(args._[1] || ".")); - const ext = buildFile.endsWith('.cjs') ? '.cjs' : '.js'; + const ext = !args['--esm'] && buildFile.endsWith('.cjs') ? '.cjs' : '.js'; const ncc = require("./index.js")( buildFile, { debugLog: args["--debug"], minify: args["--minify"], + esm: args["--esm"], externals: args["--external"], sourceMap: args["--source-map"] || run, sourceMapRegister: args["--no-source-map-register"] ? false : undefined, diff --git a/src/index.js b/src/index.js index 34639417..6fba5be8 100644 --- a/src/index.js +++ b/src/index.js @@ -36,8 +36,9 @@ function ncc ( { cache, customEmit = undefined, + esm = false, externals = [], - filename = 'index' + (entry.endsWith('.cjs') ? '.cjs' : '.js'), + filename = 'index' + (!esm && entry.endsWith('.cjs') ? '.cjs' : '.js'), minify = false, sourceMap = false, sourceMapRegister = true, @@ -233,7 +234,8 @@ function ncc ( }, amd: false, experiments: { - topLevelAwait: true + topLevelAwait: true, + outputModule: true }, optimization: { nodeEnv: false, @@ -258,8 +260,9 @@ function ncc ( path: "/", // Webpack only emits sourcemaps for files ending in .js filename: ext === '.cjs' ? filename + '.js' : filename, - libraryTarget: "commonjs2", - strictModuleExceptionHandling: true + libraryTarget: esm ? 'module' : 'commonjs2', + strictModuleExceptionHandling: true, + module: esm }, resolve: { extensions: SUPPORTED_EXTENSIONS, @@ -465,12 +468,13 @@ function ncc ( let result; try { result = await terser.minify(code, { + module: esm, compress: false, mangle: { keep_classnames: true, keep_fnames: true }, - sourceMap: sourceMap ? { + sourceMap: map ? { content: map, filename, url: `${filename}.map` @@ -483,10 +487,10 @@ function ncc ( ({ code, map } = { code: result.code, - map: sourceMap ? JSON.parse(result.map) : undefined + map: map ? JSON.parse(result.map) : undefined }); } - catch { + catch (e) { console.log('An error occurred while minifying. The result will not be minified.'); } } @@ -511,9 +515,10 @@ function ncc ( `if (cachedData) process.on('exit', () => { try { writeFileSync(basename + '.cache', script.createCachedData()); } catch(e) {} });\n`; } - if (sourceMap && sourceMapRegister) { - code = `require('./sourcemap-register${ext}');` + code; - assets[`sourcemap-register${ext}`] = { source: fs.readFileSync(`${__dirname}/sourcemap-register.js.cache.js`), permissions: defaultPermissions }; + if (map && sourceMapRegister) { + const registerExt = esm ? '.cjs' : ext; + code = (esm ? `import './sourcemap-register${registerExt}';` : `require('./sourcemap-register${registerExt}');`) + code; + assets[`sourcemap-register${registerExt}`] = { source: fs.readFileSync(`${__dirname}/sourcemap-register.js.cache.js`), permissions: defaultPermissions }; } if (shebangMatch) { diff --git a/test/cli.js b/test/cli.js index b907500e..c633419e 100644 --- a/test/cli.js +++ b/test/cli.js @@ -103,5 +103,12 @@ expect (code, stdout) { return code === 0 && stdout.indexOf('ncc built-in') !== -1; }, + }, + { + args: ["build", "-o", "tmp", "test/fixtures/module.cjs", "--esm"], + expect (code, stdout) { + const fs = require('fs'); + return code === 0 && fs.readFileSync('tmp/index.js', 'utf8').toString().indexOf('export {') !== -1; + } } ]