Skip to content

Commit

Permalink
add support for .cjs outputs
Browse files Browse the repository at this point in the history
  • Loading branch information
guybedford committed Feb 20, 2020
1 parent 9a29955 commit 294b8b3
Show file tree
Hide file tree
Showing 4 changed files with 39 additions and 23 deletions.
3 changes: 3 additions & 0 deletions readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,9 @@ $ ncc build input.js -o dist

Outputs the Node.js compact build of `input.js` into `dist/index.js`.

> Note: If the input file is using a `.cjs` extension, then so will the corresponding output file.
> This is useful for packages that want to use `.js` files as modules in native Node.js using
> a `"type": "module"` in the package.json file.
#### Commands:
```
Expand Down
20 changes: 11 additions & 9 deletions src/cli.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#!/usr/bin/env node

const { resolve, relative, dirname, sep } = require("path");
const { resolve, relative, dirname, sep, extname } = require("path");
const glob = require("glob");
const shebangRegEx = require("./utils/shebang");
const rimraf = require("rimraf");
Expand Down Expand Up @@ -50,7 +50,7 @@ else {
api = true;
}

function renderSummary(code, map, assets, outDir, buildTime) {
function renderSummary(code, map, assets, ext, outDir, buildTime) {
if (outDir && !outDir.endsWith(sep)) outDir += sep;
const codeSize = Math.round(Buffer.byteLength(code, "utf8") / 1024);
const mapSize = map ? Math.round(Buffer.byteLength(map, "utf8") / 1024) : 0;
Expand All @@ -74,10 +74,10 @@ function renderSummary(code, map, assets, outDir, buildTime) {

let indexRender = `${codeSize
.toString()
.padStart(sizePadding, " ")}kB ${outDir}${"index.js"}`;
.padStart(sizePadding, " ")}kB ${outDir}index${ext}`;
let indexMapRender = map ? `${mapSize
.toString()
.padStart(sizePadding, " ")}kB ${outDir}${"index.js.map"}` : '';
.padStart(sizePadding, " ")}kB ${outDir}index${ext}.map` : '';

let output = "",
first = true;
Expand Down Expand Up @@ -215,6 +215,7 @@ 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 ncc = require("./index.js")(
buildFile,
{
Expand All @@ -241,16 +242,16 @@ async function runCmd (argv, stdout, stderr) {

outDir = outDir || resolve("dist");
mkdirp.sync(outDir);
// remove all existing ".js" files in the out directory
// remove all existing ".js", ".mjs" and ".cjs" files in the out directory
await Promise.all(
(await new Promise((resolve, reject) =>
glob(outDir + '/**/*.js', (err, files) => err ? reject(err) : resolve(files))
glob(outDir + '/**/*.(js|mjs|cjs)', (err, files) => err ? reject(err) : resolve(files))
)).map(file =>
new Promise((resolve, reject) => unlink(file, err => err ? reject(err) : resolve())
))
);
writeFileSync(outDir + "/index.js", code, { mode: code.match(shebangRegEx) ? 0o777 : 0o666 });
if (map) writeFileSync(outDir + "/index.js.map", map);
writeFileSync(`${outDir}/index${ext}`, code, { mode: code.match(shebangRegEx) ? 0o777 : 0o666 });
if (map) writeFileSync(`${outDir}/index${ext}.map`, map);

for (const asset of Object.keys(assets)) {
const assetPath = outDir + "/" + asset;
Expand All @@ -269,6 +270,7 @@ async function runCmd (argv, stdout, stderr) {
code,
map,
assets,
ext,
run ? "" : relative(process.cwd(), outDir),
Date.now() - startTime,
) + '\n'
Expand All @@ -292,7 +294,7 @@ async function runCmd (argv, stdout, stderr) {
} while (nodeModulesDir = resolve(nodeModulesDir, "../../node_modules"));
if (nodeModulesDir)
symlinkSync(nodeModulesDir, outDir + "/node_modules", "junction");
ps = require("child_process").fork(outDir + "/index.js", {
ps = require("child_process").fork(`${outDir}/index${ext}`, {
stdio: api ? 'pipe' : 'inherit'
});
if (api) {
Expand Down
27 changes: 13 additions & 14 deletions src/index.js
Original file line number Diff line number Diff line change
@@ -1,22 +1,19 @@
const resolve = require("resolve");
const fs = require("graceful-fs");
const crypto = require("crypto");
const { sep, join, dirname } = require("path");
const { join, dirname, extname } = require("path");
const webpack = require("webpack");
const MemoryFS = require("memory-fs");
const terser = require("terser");
const tsconfigPaths = require("tsconfig-paths");
const TsconfigPathsPlugin = require("tsconfig-paths-webpack-plugin");
const shebangRegEx = require('./utils/shebang');
const { pkgNameRegEx } = require("./utils/get-package-base");
const nccCacheDir = require("./utils/ncc-cache-dir");
const { version: nccVersion } = require('../package.json');

// support glob graceful-fs
fs.gracefulify(require("fs"));

const nodeBuiltins = new Set([...require("repl")._builtinLibs, "constants", "module", "timers", "console", "_stream_writable", "_stream_readable", "_stream_duplex"]);

const SUPPORTED_EXTENSIONS = [".js", ".json", ".node", ".mjs", ".ts", ".tsx"];

const hashOf = name => {
Expand All @@ -36,7 +33,7 @@ module.exports = (
{
cache,
externals = [],
filename = "index.js",
filename = 'index' + (entry.endsWith('.cjs') ? '.cjs' : '.js'),
minify = false,
sourceMap = false,
sourceMapRegister = true,
Expand All @@ -49,6 +46,8 @@ module.exports = (
transpileOnly = false
} = {}
) => {
const ext = extname(filename);

if (!quiet) {
console.log(`ncc: Version ${nccVersion}`);
console.log(`ncc: Compiling file ${filename}`);
Expand All @@ -61,11 +60,11 @@ module.exports = (
const existingAssetNames = [filename];
if (sourceMap) {
existingAssetNames.push(`${filename}.map`);
existingAssetNames.push('sourcemap-register.js');
existingAssetNames.push(`sourcemap-register${ext}`);
}
if (v8cache) {
existingAssetNames.push(`${filename}.cache`);
existingAssetNames.push(`${filename}.cache.js`);
existingAssetNames.push(`${filename}.cache${ext}`);
}
const resolvePlugins = [];
// add TsconfigPathsPlugin to support `paths` resolution in tsconfig
Expand Down Expand Up @@ -95,7 +94,7 @@ module.exports = (
if (!err.missing || !err.missing.length)
return callback(err);
// make not found errors runtime errors
callback(null, __dirname + '/@@notfound.js' + '?' + (externalMap.get(request) || request));
callback(null, `${__dirname}/@@notfound${ext}?${(externalMap.get(request) || request)}`);
});
};
}
Expand Down Expand Up @@ -150,7 +149,7 @@ module.exports = (
module: {
rules: [
{
test: /@@notfound\.js$/,
test: /@@notfound\.(m|c)?js$/,
use: [{
loader: eval('__dirname + "/loaders/notfound-loader.js"')
}]
Expand Down Expand Up @@ -376,24 +375,24 @@ module.exports = (

if (v8cache) {
const { Script } = require('vm');
assets[filename + '.cache'] = { source: new Script(code).createCachedData(), permissions: defaultPermissions };
assets[filename + '.cache.js'] = { source: code, permissions: defaultPermissions };
assets[`${filename}.cache`] = { source: new Script(code).createCachedData(), permissions: defaultPermissions };
assets[`${filename}.cache${ext}`] = { source: code, permissions: defaultPermissions };
if (map) {
assets[filename + '.map'] = { source: JSON.stringify(map), permissions: defaultPermissions };
map = undefined;
}
code =
`const { readFileSync, writeFileSync } = require('fs'), { Script } = require('vm'), { wrap } = require('module');\n` +
`const source = readFileSync(__dirname + '/${filename}.cache.js', 'utf-8');\n` +
`const source = readFileSync(__dirname + '/${filename}.cache${ext}', 'utf-8');\n` +
`const cachedData = !process.pkg && require('process').platform !== 'win32' && readFileSync(__dirname + '/${filename}.cache');\n` +
`const script = new Script(wrap(source), cachedData ? { cachedData } : {});\n` +
`(script.runInThisContext())(exports, require, module, __filename, __dirname);\n` +
`if (cachedData) process.on('exit', () => { try { writeFileSync(__dirname + '/${filename}.cache', script.createCachedData()); } catch(e) {} });\n`;
}

if (sourceMap && sourceMapRegister) {
code = `require('./sourcemap-register.js');` + code;
assets['sourcemap-register.js'] = { source: fs.readFileSync(__dirname + "/sourcemap-register.js.cache.js"), permissions: defaultPermissions };
code = `require('./sourcemap-register${ext}');` + code;
assets[`sourcemap-register${ext}`] = { source: fs.readFileSync(`${__dirname}/sourcemap-register${ext}.cache${ext}`), permissions: defaultPermissions };
}

if (shebangMatch) {
Expand Down
12 changes: 12 additions & 0 deletions test/cli.js
Original file line number Diff line number Diff line change
Expand Up @@ -51,5 +51,17 @@
{
args: ["run", "-t", "test/fixtures/with-type-errors/ts-error.ts"],
expect: { code: 0 }
},
{
args: ["build", "-o", "tmp", "test/fixtures/test.cjs"],
expect (code, stdout, stderr) {
return stdout.toString().indexOf('tmp/index.cjs') !== -1;
}
},
{
args: ["build", "-o", "tmp", "test/fixtures/test.mjs"],
expect (code, stdout, stderr) {
return stdout.toString().indexOf('tmp/index.js') !== -1;
}
}
]

0 comments on commit 294b8b3

Please sign in to comment.