diff --git a/src/index.js b/src/index.js index d2f75b5..d27afb8 100644 --- a/src/index.js +++ b/src/index.js @@ -77,6 +77,32 @@ const alwaysNull = () => null; const resolveIdAsync = (file, opts) => new Promise((fulfil, reject) => resolveId(file, opts, (err, contents) => err ? reject(err) : fulfil(contents))); +// Resolve module specifiers in order. Promise resolves to the first +// module that resolves successfully, or the error that resulted from +// the last attempted module resolution. +function resolveImportSpecifiers (importSpecifierList, resolveOptions) { + let p = Promise.resolve(); + for (let i = 0; i < importSpecifierList.length; i++) { + p = p.then(v => { + // if we've already resolved to something, just return it. + if (v) return v; + + return resolveIdAsync(importSpecifierList[i], resolveOptions); + }); + + if (i < importSpecifierList.length - 1) { + // swallow MODULE_NOT_FOUND errors from all but the last resolution + p = p.catch(err => { + if (err.code !== 'MODULE_NOT_FOUND') { + throw err; + } + }); + } + } + + return p; +} + export default function nodeResolve ( options = {} ) { const mainFields = getMainFields(options); const useBrowserOverrides = mainFields.indexOf('browser') !== -1; @@ -239,29 +265,36 @@ export default function nodeResolve ( options = {} ) { resolveOptions.preserveSymlinks = preserveSymlinks; } + const importSpecifierList = []; + + if (importer === undefined && !importee[0].match(/^\.?\.?\//)) { + // For module graph roots (i.e. when importer is undefined), we + // need to handle 'path fragments` like `foo/bar` that are commonly + // found in rollup config files. If importee doesn't look like a + // relative or absolute path, we make it relative and attempt to + // resolve it. If we don't find anything, we try resolving it as we + // got it. + importSpecifierList.push('./' + importee); + } + const importeeIsBuiltin = builtins.has(importee); - const forceLocalLookup = importeeIsBuiltin && (!preferBuiltins || !isPreferBuiltinsSet); - let importSpecifier = importee; - if (forceLocalLookup) { - // need to attempt to look up a local module - importSpecifier += '/'; + if (importeeIsBuiltin && (!preferBuiltins || !isPreferBuiltinsSet)) { + // The `resolve` library will not resolve packages with the same + // name as a node built-in module. If we're resolving something + // that's a builtin, and we don't prefer to find built-ins, we + // first try to look up a local module with that name. If we don't + // find anything, we resolve the builtin which just returns back + // the built-in's name. + importSpecifierList.push(importee + '/'); } - return resolveIdAsync( - importSpecifier, - Object.assign( resolveOptions, customResolveOptions ) - ) - .catch(err => { - if (forceLocalLookup && err.code === 'MODULE_NOT_FOUND') { - // didn't find a local module, so fall back to the importee - // (i.e. the builtin's name) - return importee; - } + importSpecifierList.push(importee); - // some other error, just forward it - throw err; - }) + return resolveImportSpecifiers( + importSpecifierList, + Object.assign(resolveOptions, customResolveOptions) + ) .then(resolved => { if ( resolved && packageBrowserField ) { if ( packageBrowserField.hasOwnProperty(resolved) ) { diff --git a/test/package.json b/test/package.json new file mode 100644 index 0000000..5d2dbc8 --- /dev/null +++ b/test/package.json @@ -0,0 +1,15 @@ +{ + "name": "test", + "version": "1.0.0", + "description": "", + "main": "test.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "keywords": [], + "author": "", + "license": "ISC", + "browser": { + "dummy-module": "component-type" + } +} diff --git a/test/samples/browser-local/main.js b/test/samples/browser-local/main.js new file mode 100644 index 0000000..0560c2d --- /dev/null +++ b/test/samples/browser-local/main.js @@ -0,0 +1,4 @@ +// test browser mapped imports from the main entrypoint +import s from 'dummy-module'; + +export default s; \ No newline at end of file diff --git a/test/test.js b/test/test.js index d0b52f6..95d612b 100644 --- a/test/test.js +++ b/test/test.js @@ -337,6 +337,20 @@ describe( 'rollup-plugin-node-resolve', function () { }); }); + it('respects local browser field', function () { + return rollup.rollup({ + input: 'samples/browser-local/main.js', + onwarn: expectNoWarnings, + plugins: [ + nodeResolve({ + mainFields: ['browser', 'main'] + }) + ] + }).then(executeBundle).then(module => { + assert.equal(module.exports, 'component-type'); + }); + }); + it( 'warns when importing builtins', function () { return rollup.rollup({ input: 'samples/builtins/main.js',