From f711ab265b73fdf73534615101627d44b01e2091 Mon Sep 17 00:00:00 2001 From: Lee Byron Date: Thu, 29 Mar 2018 14:44:49 -0700 Subject: [PATCH] Support .mjs files by default. Since rollup prefers ESM formatted modules, it should look for node's new .mjs file extension before looking for .js files by default. This offers support for deployed modules intended to be used in node's ESM mode. Folks can work around this today by manually supplying the `extensions` option, however it would be great if this worked by default. Note that looking for `.mjs` before `.js` is important for rollup which prefers ESM, however the `resolve` dependency should not use the same order by default since it is used in many other tools which do not yet support ESM or would not expect it by default. Encountered this as the root cause behind https://github.com/graphql/graphql-js/issues/1293 --- README.md | 4 ++-- src/index.js | 9 ++++++--- test/node_modules/dual-cjs-mjs/entry.js | 1 + test/node_modules/dual-cjs-mjs/entry.mjs | 1 + test/node_modules/dual-cjs-mjs/package.json | 3 +++ test/node_modules/module-mjs/entry.mjs | 1 + test/node_modules/module-mjs/package.json | 3 +++ test/samples/dual-cjs-mjs/main.js | 3 +++ test/samples/module-mjs/main.js | 3 +++ test/test.js | 22 +++++++++++++++++++++ 10 files changed, 45 insertions(+), 5 deletions(-) create mode 100644 test/node_modules/dual-cjs-mjs/entry.js create mode 100644 test/node_modules/dual-cjs-mjs/entry.mjs create mode 100644 test/node_modules/dual-cjs-mjs/package.json create mode 100644 test/node_modules/module-mjs/entry.mjs create mode 100644 test/node_modules/module-mjs/package.json create mode 100644 test/samples/dual-cjs-mjs/main.js create mode 100644 test/samples/module-mjs/main.js diff --git a/README.md b/README.md index c4d7ff6..fbb4b40 100644 --- a/README.md +++ b/README.md @@ -44,7 +44,7 @@ export default { browser: true, // Default: false // not all files you want to resolve are .js files - extensions: [ '.js', '.json' ], // Default: ['.js'] + extensions: [ '.mjs', '.js', '.jsx', '.json' ], // Default: [ '.mjs', '.js', '.json', '.node' ] // whether to prefer built-in modules (e.g. `fs`, `path`) or // local ones with the same names @@ -53,7 +53,7 @@ export default { // Lock the module search in this path (like a chroot). Module defined // outside this path will be marked as external jail: '/my/jail/path', // Default: '/' - + // Set to an array of strings and/or regexps to lock the module search // to modules that match at least one entry. Modules not matching any // entry will be marked as external diff --git a/src/index.js b/src/index.js index 60cbe13..825930a 100644 --- a/src/index.js +++ b/src/index.js @@ -6,7 +6,9 @@ import fs from 'fs'; const ES6_BROWSER_EMPTY = resolve( __dirname, '../src/empty.js' ); const CONSOLE_WARN = ( ...args ) => console.warn( ...args ); // eslint-disable-line no-console -const exts = [ '.js', '.json', '.node' ]; +// It is important that .mjs occur before .js so that Rollup will interpret npm modules +// which deploy both ESM .mjs and CommonJS .js files as ESM. +const DEFAULT_EXTS = [ '.mjs', '.js', '.json', '.node' ]; let readFileCache = {}; const readFileAsync = file => new Promise((fulfil, reject) => fs.readFile(file, (err, contents) => err ? reject(err) : fulfil(contents))); @@ -110,6 +112,7 @@ export default function nodeResolve ( options = {} ) { return new Promise( ( fulfil, reject ) => { let disregardResult = false; let packageBrowserField = false; + const extensions = options.extensions || DEFAULT_EXTS; const resolveOptions = { basedir: dirname( importer ), @@ -123,7 +126,7 @@ export default function nodeResolve ( options = {} ) { const absoluteKey = resolve( pkgRoot, key ); browser[ absoluteKey ] = resolved; if ( !extname(key) ) { - exts.reduce( ( browser, ext ) => { + extensions.reduce( ( browser, ext ) => { browser[ absoluteKey + ext ] = browser[ key ]; return browser; }, browser ); @@ -146,7 +149,7 @@ export default function nodeResolve ( options = {} ) { }, readFile: cachedReadFile, isFile: cachedIsFile, - extensions: options.extensions + extensions: extensions }; if (preserveSymlinks !== undefined) { diff --git a/test/node_modules/dual-cjs-mjs/entry.js b/test/node_modules/dual-cjs-mjs/entry.js new file mode 100644 index 0000000..8d278e0 --- /dev/null +++ b/test/node_modules/dual-cjs-mjs/entry.js @@ -0,0 +1 @@ +module.exports = 'DUAL-CJS'; diff --git a/test/node_modules/dual-cjs-mjs/entry.mjs b/test/node_modules/dual-cjs-mjs/entry.mjs new file mode 100644 index 0000000..f4c86d1 --- /dev/null +++ b/test/node_modules/dual-cjs-mjs/entry.mjs @@ -0,0 +1 @@ +export default 'DUAL-MJS'; diff --git a/test/node_modules/dual-cjs-mjs/package.json b/test/node_modules/dual-cjs-mjs/package.json new file mode 100644 index 0000000..bf2e355 --- /dev/null +++ b/test/node_modules/dual-cjs-mjs/package.json @@ -0,0 +1,3 @@ +{ + "main": "entry" +} \ No newline at end of file diff --git a/test/node_modules/module-mjs/entry.mjs b/test/node_modules/module-mjs/entry.mjs new file mode 100644 index 0000000..9773a84 --- /dev/null +++ b/test/node_modules/module-mjs/entry.mjs @@ -0,0 +1 @@ +export default 'MODULE-MJS'; diff --git a/test/node_modules/module-mjs/package.json b/test/node_modules/module-mjs/package.json new file mode 100644 index 0000000..bf2e355 --- /dev/null +++ b/test/node_modules/module-mjs/package.json @@ -0,0 +1,3 @@ +{ + "main": "entry" +} \ No newline at end of file diff --git a/test/samples/dual-cjs-mjs/main.js b/test/samples/dual-cjs-mjs/main.js new file mode 100644 index 0000000..c6ed8f7 --- /dev/null +++ b/test/samples/dual-cjs-mjs/main.js @@ -0,0 +1,3 @@ +import module from 'dual-cjs-mjs'; + +export default module; // MODULE diff --git a/test/samples/module-mjs/main.js b/test/samples/module-mjs/main.js new file mode 100644 index 0000000..9d2a79d --- /dev/null +++ b/test/samples/module-mjs/main.js @@ -0,0 +1,3 @@ +import module from 'module-mjs'; + +export default module; // MODULE diff --git a/test/test.js b/test/test.js index 1613ec9..47d44b8 100644 --- a/test/test.js +++ b/test/test.js @@ -436,6 +436,28 @@ describe( 'rollup-plugin-node-resolve', function () { }); }); + it('finds and uses an .mjs module', function () { + return rollup.rollup({ + input: 'samples/module-mjs/main.js', + plugins: [ + nodeResolve({ preferBuiltins: false }) + ] + }).then( executeBundle ).then( module => { + assert.equal( module.exports, 'MODULE-MJS' ); + }); + }); + + it('finds and uses a dual-distributed .js & .mjs module', function () { + return rollup.rollup({ + input: 'samples/dual-cjs-mjs/main.js', + plugins: [ + nodeResolve({ preferBuiltins: false }) + ] + }).then( executeBundle ).then( module => { + assert.equal( module.exports, 'DUAL-MJS' ); + }); + }); + describe( 'symlinks', () => { function createMissingDirectories () { createDirectory( './samples/symlinked/first/node_modules' );