From 3d54780a9e113274e7508645381fb8d440a1dc9a Mon Sep 17 00:00:00 2001 From: Lars den Bakker Date: Sat, 12 Sep 2020 18:30:59 +0200 Subject: [PATCH] feat(node-resolve): support package entry points --- packages/node-resolve/README.md | 32 ++- packages/node-resolve/package.json | 2 +- packages/node-resolve/src/index.js | 28 ++- .../src/resolveImportSpecifiers.js | 197 +++++++++++++++++ packages/node-resolve/src/util.js | 40 +--- packages/node-resolve/test/browser.js | 2 +- .../fixtures/browser-object-with-false.js | 2 +- .../node-resolve/test/fixtures/exports-cjs.js | 3 + .../fixtures/exports-conditions-fallback.js | 3 + .../test/fixtures/exports-directory.js | 5 + .../test/fixtures/exports-main-directory.js | 5 + .../exports-mappings-and-conditions.js | 5 + .../fixtures/exports-nested-conditions.js | 3 + .../fixtures/exports-non-existing-subpath.js | 3 + .../exports-prevent-unspecified-subpath.js | 3 + .../fixtures/exports-shorthand-fallback.js | 3 + .../fixtures/exports-shorthand-subpath.js | 3 + .../test/fixtures/exports-shorthand.js | 3 + .../test/fixtures/exports-star.js | 5 + .../fixtures/exports-top-level-conditions.js | 3 + .../fixtures/exports-top-level-mappings.js | 4 + .../node_modules/exports-cjs/index-cjs.js | 1 + .../node_modules/exports-cjs/index-esm.js | 1 + .../node_modules/exports-cjs/package.json | 10 + .../index-mapped.js | 1 + .../exports-conditions-fallback/index.js | 1 + .../exports-conditions-fallback/package.json | 10 + .../exports-directory/exported-foo/a.js | 1 + .../exports-directory/exported-foo/b.js | 1 + .../exported-foo/nested/c.js | 1 + .../node_modules/exports-directory/foo/a.js | 1 + .../node_modules/exports-directory/foo/b.js | 1 + .../exports-directory/foo/nested/c.js | 1 + .../exports-directory/package.json | 7 + .../node_modules/exports-main-directory/a.js | 1 + .../exports-main-directory/foo/b.js | 1 + .../exports-main-directory/foo/nested/c.js | 1 + .../exports-main-directory/package.json | 7 + .../bar-mapped.js | 1 + .../exports-mappings-and-conditions/bar.js | 1 + .../foo-mapped.js | 1 + .../exports-mappings-and-conditions/foo.js | 1 + .../index-mapped.js | 1 + .../exports-mappings-and-conditions/index.js | 1 + .../package.json | 21 ++ .../exports-nested-conditions/index-mapped.js | 1 + .../exports-nested-conditions/index.js | 1 + .../exports-nested-conditions/package.json | 11 + .../foo-mapped.js | 1 + .../exports-non-existing-subpath/foo.js | 1 + .../index-mapped.js | 1 + .../exports-non-existing-subpath/index.js | 1 + .../exports-non-existing-subpath/package.json | 8 + .../exports-prevent-direct-imports/bar.js | 1 + .../exports-prevent-direct-imports/foo.js | 1 + .../index-mapped.js | 1 + .../exports-prevent-direct-imports/index.js | 1 + .../package.json | 8 + .../foo-mapped.js | 1 + .../foo.js | 1 + .../index-mapped.js | 1 + .../index.js | 1 + .../package.json | 8 + .../index-mapped.js | 1 + .../exports-shorthand-fallback/index.js | 1 + .../exports-shorthand-fallback/package.json | 5 + .../exports-shorthand/index-mapped.js | 1 + .../node_modules/exports-shorthand/index.js | 1 + .../exports-shorthand/package.json | 5 + .../node_modules/exports-star/foo/a.js | 1 + .../node_modules/exports-star/foo/b.js | 1 + .../node_modules/exports-star/foo/bar/c.js | 1 + .../node_modules/exports-star/package.json | 7 + .../index-mapped.js | 1 + .../exports-top-level-conditions/index.js | 1 + .../exports-top-level-conditions/package.json | 8 + .../exports-top-level-mappings/foo-mapped.js | 1 + .../exports-top-level-mappings/foo.js | 1 + .../index-mapped.js | 1 + .../exports-top-level-mappings/index.js | 1 + .../exports-top-level-mappings/package.json | 8 + .../node-resolve/test/package-entry-points.js | 200 ++++++++++++++++++ packages/node-resolve/types/index.d.ts | 11 + pnpm-lock.yaml | 28 ++- 84 files changed, 703 insertions(+), 59 deletions(-) create mode 100644 packages/node-resolve/src/resolveImportSpecifiers.js create mode 100644 packages/node-resolve/test/fixtures/exports-cjs.js create mode 100644 packages/node-resolve/test/fixtures/exports-conditions-fallback.js create mode 100644 packages/node-resolve/test/fixtures/exports-directory.js create mode 100644 packages/node-resolve/test/fixtures/exports-main-directory.js create mode 100644 packages/node-resolve/test/fixtures/exports-mappings-and-conditions.js create mode 100644 packages/node-resolve/test/fixtures/exports-nested-conditions.js create mode 100644 packages/node-resolve/test/fixtures/exports-non-existing-subpath.js create mode 100644 packages/node-resolve/test/fixtures/exports-prevent-unspecified-subpath.js create mode 100644 packages/node-resolve/test/fixtures/exports-shorthand-fallback.js create mode 100644 packages/node-resolve/test/fixtures/exports-shorthand-subpath.js create mode 100644 packages/node-resolve/test/fixtures/exports-shorthand.js create mode 100644 packages/node-resolve/test/fixtures/exports-star.js create mode 100644 packages/node-resolve/test/fixtures/exports-top-level-conditions.js create mode 100644 packages/node-resolve/test/fixtures/exports-top-level-mappings.js create mode 100644 packages/node-resolve/test/fixtures/node_modules/exports-cjs/index-cjs.js create mode 100644 packages/node-resolve/test/fixtures/node_modules/exports-cjs/index-esm.js create mode 100644 packages/node-resolve/test/fixtures/node_modules/exports-cjs/package.json create mode 100644 packages/node-resolve/test/fixtures/node_modules/exports-conditions-fallback/index-mapped.js create mode 100644 packages/node-resolve/test/fixtures/node_modules/exports-conditions-fallback/index.js create mode 100644 packages/node-resolve/test/fixtures/node_modules/exports-conditions-fallback/package.json create mode 100644 packages/node-resolve/test/fixtures/node_modules/exports-directory/exported-foo/a.js create mode 100644 packages/node-resolve/test/fixtures/node_modules/exports-directory/exported-foo/b.js create mode 100644 packages/node-resolve/test/fixtures/node_modules/exports-directory/exported-foo/nested/c.js create mode 100644 packages/node-resolve/test/fixtures/node_modules/exports-directory/foo/a.js create mode 100644 packages/node-resolve/test/fixtures/node_modules/exports-directory/foo/b.js create mode 100644 packages/node-resolve/test/fixtures/node_modules/exports-directory/foo/nested/c.js create mode 100644 packages/node-resolve/test/fixtures/node_modules/exports-directory/package.json create mode 100644 packages/node-resolve/test/fixtures/node_modules/exports-main-directory/a.js create mode 100644 packages/node-resolve/test/fixtures/node_modules/exports-main-directory/foo/b.js create mode 100644 packages/node-resolve/test/fixtures/node_modules/exports-main-directory/foo/nested/c.js create mode 100644 packages/node-resolve/test/fixtures/node_modules/exports-main-directory/package.json create mode 100644 packages/node-resolve/test/fixtures/node_modules/exports-mappings-and-conditions/bar-mapped.js create mode 100644 packages/node-resolve/test/fixtures/node_modules/exports-mappings-and-conditions/bar.js create mode 100644 packages/node-resolve/test/fixtures/node_modules/exports-mappings-and-conditions/foo-mapped.js create mode 100644 packages/node-resolve/test/fixtures/node_modules/exports-mappings-and-conditions/foo.js create mode 100644 packages/node-resolve/test/fixtures/node_modules/exports-mappings-and-conditions/index-mapped.js create mode 100644 packages/node-resolve/test/fixtures/node_modules/exports-mappings-and-conditions/index.js create mode 100644 packages/node-resolve/test/fixtures/node_modules/exports-mappings-and-conditions/package.json create mode 100644 packages/node-resolve/test/fixtures/node_modules/exports-nested-conditions/index-mapped.js create mode 100644 packages/node-resolve/test/fixtures/node_modules/exports-nested-conditions/index.js create mode 100644 packages/node-resolve/test/fixtures/node_modules/exports-nested-conditions/package.json create mode 100644 packages/node-resolve/test/fixtures/node_modules/exports-non-existing-subpath/foo-mapped.js create mode 100644 packages/node-resolve/test/fixtures/node_modules/exports-non-existing-subpath/foo.js create mode 100644 packages/node-resolve/test/fixtures/node_modules/exports-non-existing-subpath/index-mapped.js create mode 100644 packages/node-resolve/test/fixtures/node_modules/exports-non-existing-subpath/index.js create mode 100644 packages/node-resolve/test/fixtures/node_modules/exports-non-existing-subpath/package.json create mode 100644 packages/node-resolve/test/fixtures/node_modules/exports-prevent-direct-imports/bar.js create mode 100644 packages/node-resolve/test/fixtures/node_modules/exports-prevent-direct-imports/foo.js create mode 100644 packages/node-resolve/test/fixtures/node_modules/exports-prevent-direct-imports/index-mapped.js create mode 100644 packages/node-resolve/test/fixtures/node_modules/exports-prevent-direct-imports/index.js create mode 100644 packages/node-resolve/test/fixtures/node_modules/exports-prevent-direct-imports/package.json create mode 100644 packages/node-resolve/test/fixtures/node_modules/exports-prevent-unspecified-subpath/foo-mapped.js create mode 100644 packages/node-resolve/test/fixtures/node_modules/exports-prevent-unspecified-subpath/foo.js create mode 100644 packages/node-resolve/test/fixtures/node_modules/exports-prevent-unspecified-subpath/index-mapped.js create mode 100644 packages/node-resolve/test/fixtures/node_modules/exports-prevent-unspecified-subpath/index.js create mode 100644 packages/node-resolve/test/fixtures/node_modules/exports-prevent-unspecified-subpath/package.json create mode 100644 packages/node-resolve/test/fixtures/node_modules/exports-shorthand-fallback/index-mapped.js create mode 100644 packages/node-resolve/test/fixtures/node_modules/exports-shorthand-fallback/index.js create mode 100644 packages/node-resolve/test/fixtures/node_modules/exports-shorthand-fallback/package.json create mode 100644 packages/node-resolve/test/fixtures/node_modules/exports-shorthand/index-mapped.js create mode 100644 packages/node-resolve/test/fixtures/node_modules/exports-shorthand/index.js create mode 100644 packages/node-resolve/test/fixtures/node_modules/exports-shorthand/package.json create mode 100644 packages/node-resolve/test/fixtures/node_modules/exports-star/foo/a.js create mode 100644 packages/node-resolve/test/fixtures/node_modules/exports-star/foo/b.js create mode 100644 packages/node-resolve/test/fixtures/node_modules/exports-star/foo/bar/c.js create mode 100644 packages/node-resolve/test/fixtures/node_modules/exports-star/package.json create mode 100644 packages/node-resolve/test/fixtures/node_modules/exports-top-level-conditions/index-mapped.js create mode 100644 packages/node-resolve/test/fixtures/node_modules/exports-top-level-conditions/index.js create mode 100644 packages/node-resolve/test/fixtures/node_modules/exports-top-level-conditions/package.json create mode 100644 packages/node-resolve/test/fixtures/node_modules/exports-top-level-mappings/foo-mapped.js create mode 100644 packages/node-resolve/test/fixtures/node_modules/exports-top-level-mappings/foo.js create mode 100644 packages/node-resolve/test/fixtures/node_modules/exports-top-level-mappings/index-mapped.js create mode 100644 packages/node-resolve/test/fixtures/node_modules/exports-top-level-mappings/index.js create mode 100644 packages/node-resolve/test/fixtures/node_modules/exports-top-level-mappings/package.json create mode 100644 packages/node-resolve/test/package-entry-points.js diff --git a/packages/node-resolve/README.md b/packages/node-resolve/README.md index 9f093239e..0f49f6d70 100755 --- a/packages/node-resolve/README.md +++ b/packages/node-resolve/README.md @@ -34,9 +34,9 @@ export default { input: 'src/index.js', output: { dir: 'output', - format: 'cjs' + format: 'cjs', }, - plugins: [nodeResolve()] + plugins: [nodeResolve()], }; ``` @@ -44,6 +44,17 @@ Then call `rollup` either via the [CLI](https://www.rollupjs.org/guide/en/#comma ## Options +### `exportConditions` + +Type: `Array[...String]`
+Default: `[]` + +Additional conditions of the package.json exports field to match when resolving modules. By default, this plugin looks for the `['default', 'module', 'import']` conditions when resolving imports. + +When using `@rollup/plugin-commonjs` v16 or higher, this plugin will use the `['default', 'module', 'require']` conditions when resolving require statements. + +Setting this option will add extra conditions on top of the default conditions. See https://nodejs.org/api/packages.html#packages_conditional_exports for more information. + ### `browser` Type: `Boolean`
@@ -164,9 +175,9 @@ export default { output: { file: 'bundle.js', format: 'iife', - name: 'MyModule' + name: 'MyModule', }, - plugins: [resolve(), commonjs()] + plugins: [resolve(), commonjs()], }; ``` @@ -187,6 +198,19 @@ export default ({ }) ``` +## Resolving require statements + +According to [NodeJS module resolution](https://nodejs.org/api/packages.html#packages_package_entry_points) `require` statements should resolve using the `require` condition in the package exports field, while es modules should use the `import` condition. + +The node resolve plugin uses `import` by default, you can opt into using the `require` semantics by passing an extra option to the resolve function: + +```js +this.resolve(importee, importer, { + skipSelf: true, + custom: { 'node-resolve': { isRequire: true } }, +}); +``` + ## Meta [CONTRIBUTING](/.github/CONTRIBUTING.md) diff --git a/packages/node-resolve/package.json b/packages/node-resolve/package.json index 4f64b1e58..f4b67bff1 100644 --- a/packages/node-resolve/package.json +++ b/packages/node-resolve/package.json @@ -65,7 +65,7 @@ "@babel/core": "^7.10.5", "@babel/plugin-transform-typescript": "^7.10.5", "@rollup/plugin-babel": "^5.1.0", - "@rollup/plugin-commonjs": "^14.0.0", + "@rollup/plugin-commonjs": "^16.0.0", "@rollup/plugin-json": "^4.1.0", "es5-ext": "^0.10.53", "rollup": "^2.23.0", diff --git a/packages/node-resolve/src/index.js b/packages/node-resolve/src/index.js index 6081a0797..1d5d67fb9 100644 --- a/packages/node-resolve/src/index.js +++ b/packages/node-resolve/src/index.js @@ -7,13 +7,8 @@ import isModule from 'is-module'; import { isDirCached, isFileCached, readCachedFile } from './cache'; import { exists, readFile, realpath } from './fs'; -import { - getMainFields, - getPackageInfo, - getPackageName, - normalizeInput, - resolveImportSpecifiers -} from './util'; +import { resolveImportSpecifiers } from './resolveImportSpecifiers'; +import { getMainFields, getPackageInfo, getPackageName, normalizeInput } from './util'; const builtins = new Set(builtinList); const ES6_BROWSER_EMPTY = '\0node-resolve:empty.js'; @@ -29,6 +24,10 @@ const deepFreeze = (object) => { return object; }; + +const baseConditions = ['default', 'module']; +const baseConditionsEsm = [...baseConditions, 'import']; +const baseConditionsCjs = [...baseConditions, 'require']; const defaults = { customResolveOptions: {}, dedupe: [], @@ -42,6 +41,8 @@ export const DEFAULTS = deepFreeze(deepMerge({}, defaults)); export function nodeResolve(opts = {}) { const options = Object.assign({}, defaults, opts); const { customResolveOptions, extensions, jail } = options; + const conditionsEsm = [...baseConditionsEsm, ...(options.exportConditions || [])]; + const conditionsCjs = [...baseConditionsCjs, ...(options.exportConditions || [])]; const warnings = []; const packageInfoCache = new Map(); const idToPackageInfo = new Map(); @@ -93,7 +94,7 @@ export function nodeResolve(opts = {}) { isDirCached.clear(); }, - async resolveId(importee, importer) { + async resolveId(importee, importer, opts) { if (importee === ES6_BROWSER_EMPTY) { return importee; } @@ -222,7 +223,16 @@ export function nodeResolve(opts = {}) { importSpecifierList.push(importee); resolveOptions = Object.assign(resolveOptions, customResolveOptions); - let resolved = await resolveImportSpecifiers(importSpecifierList, resolveOptions); + const warn = (...args) => this.warn(...args); + const isRequire = + opts && opts.custom && opts.custom['node-resolve'] && opts.custom['node-resolve'].isRequire; + const exportConditions = isRequire ? conditionsCjs : conditionsEsm; + let resolved = await resolveImportSpecifiers( + importSpecifierList, + resolveOptions, + exportConditions, + warn + ); if (!resolved) { return null; } diff --git a/packages/node-resolve/src/resolveImportSpecifiers.js b/packages/node-resolve/src/resolveImportSpecifiers.js new file mode 100644 index 000000000..5f780967e --- /dev/null +++ b/packages/node-resolve/src/resolveImportSpecifiers.js @@ -0,0 +1,197 @@ +import fs from 'fs'; +import path from 'path'; +import { promisify } from 'util'; + +import resolve from 'resolve'; + +import { getPackageName } from './util'; +import { exists, realpath } from './fs'; + +const resolveImportPath = promisify(resolve); +const readFile = promisify(fs.readFile); + +const pathNotFoundError = (subPath, pkgPath) => + new Error(`Package subpath '${subPath}' is not defined by "exports" in ${pkgPath}`); + +function findExportKeyMatch(exportMap, subPath) { + for (const key of Object.keys(exportMap)) { + if (key.endsWith('*')) { + // star match: "./foo/*": "./foo/*.js" + const keyWithoutStar = key.substring(0, key.length - 1); + if (subPath.startsWith(keyWithoutStar)) { + return key; + } + } + + if (key.endsWith('/') && subPath.startsWith(key)) { + // directory match (deprecated by node): "./foo/": "./foo/.js" + return key; + } + + if (key === subPath) { + // literal match + return key; + } + } + return null; +} + +function mapSubPath(pkgJsonPath, subPath, key, value) { + if (typeof value === 'string') { + if (typeof key === 'string' && key.endsWith('*')) { + // star match: "./foo/*": "./foo/*.js" + const keyWithoutStar = key.substring(0, key.length - 1); + const subPathAfterKey = subPath.substring(keyWithoutStar.length); + return value.replace(/\*/g, subPathAfterKey); + } + + if (value.endsWith('/')) { + // directory match (deprecated by node): "./foo/": "./foo/.js" + return `${value}${subPath.substring(key.length)}`; + } + + // mapping is a string, for example { "./foo": "./dist/foo.js" } + return value; + } + + if (Array.isArray(value)) { + // mapping is an array with fallbacks, for example { "./foo": ["foo:bar", "./dist/foo.js"] } + return value.find((v) => v.startsWith('./')); + } + + throw pathNotFoundError(subPath, pkgJsonPath); +} + +function findEntrypoint(pkgJsonPath, subPath, exportMap, conditions, key) { + if (typeof exportMap !== 'object') { + return mapSubPath(pkgJsonPath, subPath, key, exportMap); + } + + // iterate conditions recursively, find the first that matches all conditions + for (const [condition, subExportMap] of Object.entries(exportMap)) { + if (conditions.includes(condition)) { + const mappedSubPath = findEntrypoint(pkgJsonPath, subPath, subExportMap, conditions, key); + if (mappedSubPath) { + return mappedSubPath; + } + } + } + throw pathNotFoundError(subPath, pkgJsonPath); +} + +export function findEntrypointTopLevel(pkgJsonPath, subPath, exportMap, conditions) { + if (typeof exportMap !== 'object') { + // the export map shorthand, for example { exports: "./index.js" } + if (subPath !== '.') { + // shorthand only supports a main entrypoint + throw pathNotFoundError(subPath, pkgJsonPath); + } + return mapSubPath(pkgJsonPath, subPath, null, exportMap); + } + + // export map is an object, the top level can be either conditions or sub path mappings + const keys = Object.keys(exportMap); + const isConditions = keys.every((k) => !k.startsWith('.')); + const isMappings = keys.every((k) => k.startsWith('.')); + + if (!isConditions && !isMappings) { + throw new Error( + `Invalid package config ${pkgJsonPath}, "exports" cannot contain some keys starting with '.'` + + ' and some not. The exports object must either be an object of package subpath keys or an object of main entry' + + ' condition name keys only.' + ); + } + + let key = null; + let exportMapForSubPath; + + if (isConditions) { + // top level is conditions, for example { "import": ..., "require": ..., "module": ... } + if (subPath !== '.') { + // package with top level conditions means it only supports a main entrypoint + throw pathNotFoundError(subPath, pkgJsonPath); + } + exportMapForSubPath = exportMap; + } else { + // top level is sub path mappings, for example { ".": ..., "./foo": ..., "./bar": ... } + key = findExportKeyMatch(exportMap, subPath); + if (!key) { + throw pathNotFoundError(subPath, pkgJsonPath); + } + exportMapForSubPath = exportMap[key]; + } + + return findEntrypoint(pkgJsonPath, subPath, exportMapForSubPath, conditions, key); +} + +async function resolveId(importPath, options, exportConditions, warn) { + const pkgName = getPackageName(importPath); + if (pkgName) { + let pkgJsonPath; + let pkgJson; + try { + pkgJsonPath = await resolveImportPath(`${pkgName}/package.json`, options); + pkgJson = JSON.parse(await readFile(pkgJsonPath, 'utf-8')); + } catch (_) { + // if there is no package.json we defer to regular resolve behavior + } + + if (pkgJsonPath && pkgJson && pkgJson.exports) { + try { + const packageSubPath = + pkgName === importPath ? '.' : `.${importPath.substring(pkgName.length)}`; + const mappedSubPath = findEntrypointTopLevel( + pkgJsonPath, + packageSubPath, + pkgJson.exports, + exportConditions + ); + const pkgDir = path.dirname(pkgJsonPath); + return path.join(pkgDir, mappedSubPath); + } catch (error) { + warn(error); + return null; + } + } + } + + return resolveImportPath(importPath, options); +} + +// 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. +export function resolveImportSpecifiers( + importSpecifierList, + resolveOptions, + exportConditions, + warn +) { + let promise = Promise.resolve(); + + for (let i = 0; i < importSpecifierList.length; i++) { + // eslint-disable-next-line no-loop-func + promise = promise.then(async (value) => { + // if we've already resolved to something, just return it. + if (value) { + return value; + } + + let result = await resolveId(importSpecifierList[i], resolveOptions, exportConditions, warn); + if (!resolveOptions.preserveSymlinks) { + if (await exists(result)) { + result = await realpath(result); + } + } + return result; + }); + + // swallow MODULE_NOT_FOUND errors + promise = promise.catch((error) => { + if (error.code !== 'MODULE_NOT_FOUND') { + throw error; + } + }); + } + + return promise; +} diff --git a/packages/node-resolve/src/util.js b/packages/node-resolve/src/util.js index 1c2628afd..1af107a8d 100644 --- a/packages/node-resolve/src/util.js +++ b/packages/node-resolve/src/util.js @@ -1,13 +1,8 @@ import { dirname, extname, resolve } from 'path'; -import { promisify } from 'util'; import { createFilter } from '@rollup/pluginutils'; -import resolveModule from 'resolve'; - -import { exists, realpath, realpathSync } from './fs'; - -const resolveId = promisify(resolveModule); +import { realpathSync } from './fs'; // returns the imported package name for bare module imports export function getPackageName(id) { @@ -158,36 +153,3 @@ export function normalizeInput(input) { // otherwise it's a string return [input]; } - -// 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. -export function resolveImportSpecifiers(importSpecifierList, resolveOptions) { - let promise = Promise.resolve(); - - for (let i = 0; i < importSpecifierList.length; i++) { - // eslint-disable-next-line no-loop-func - promise = promise.then(async (value) => { - // if we've already resolved to something, just return it. - if (value) { - return value; - } - - let result = await resolveId(importSpecifierList[i], resolveOptions); - if (!resolveOptions.preserveSymlinks) { - if (await exists(result)) { - result = await realpath(result); - } - } - return result; - }); - - // swallow MODULE_NOT_FOUND errors - promise = promise.catch((error) => { - if (error.code !== 'MODULE_NOT_FOUND') { - throw error; - } - }); - } - - return promise; -} diff --git a/packages/node-resolve/test/browser.js b/packages/node-resolve/test/browser.js index 69a63dfe7..3719223ed 100644 --- a/packages/node-resolve/test/browser.js +++ b/packages/node-resolve/test/browser.js @@ -190,7 +190,7 @@ test('supports `false` in browser field', async (t) => { await testBundle(t, bundle); }); -test('pkg.browser with mapping to prevent bundle by specifying a value of false', async (t) => { +test.only('pkg.browser with mapping to prevent bundle by specifying a value of false', async (t) => { const bundle = await rollup({ input: 'browser-object-with-false.js', plugins: [nodeResolve({ browser: true }), commonjs()] diff --git a/packages/node-resolve/test/fixtures/browser-object-with-false.js b/packages/node-resolve/test/fixtures/browser-object-with-false.js index 938b3416c..9183eff46 100755 --- a/packages/node-resolve/test/fixtures/browser-object-with-false.js +++ b/packages/node-resolve/test/fixtures/browser-object-with-false.js @@ -12,7 +12,7 @@ const clientHttp = new Client('http:'); t.is(clientWs.name, 'websocket-tracker'); t.is(clientHttp.name, 'NULL'); t.is(HTTPTracker, ES6_BROWSER_EMPTY); -t.is(HTTPTrackerWithSubPath, ES6_BROWSER_EMPTY); +t.deepEqual(HTTPTrackerWithSubPath, { default: {} }); // expose export default 'ok'; diff --git a/packages/node-resolve/test/fixtures/exports-cjs.js b/packages/node-resolve/test/fixtures/exports-cjs.js new file mode 100644 index 000000000..9e18e0188 --- /dev/null +++ b/packages/node-resolve/test/fixtures/exports-cjs.js @@ -0,0 +1,3 @@ +const main = require('exports-cjs'); + +module.exports = main; diff --git a/packages/node-resolve/test/fixtures/exports-conditions-fallback.js b/packages/node-resolve/test/fixtures/exports-conditions-fallback.js new file mode 100644 index 000000000..dcc23b1d5 --- /dev/null +++ b/packages/node-resolve/test/fixtures/exports-conditions-fallback.js @@ -0,0 +1,3 @@ +import main from 'exports-conditions-fallback'; + +export default main; diff --git a/packages/node-resolve/test/fixtures/exports-directory.js b/packages/node-resolve/test/fixtures/exports-directory.js new file mode 100644 index 000000000..3d4c351f3 --- /dev/null +++ b/packages/node-resolve/test/fixtures/exports-directory.js @@ -0,0 +1,5 @@ +import a from 'exports-directory/foo/a.js'; +import b from 'exports-directory/foo/b.js'; +import c from 'exports-directory/foo/nested/c.js'; + +export default { a, b, c }; diff --git a/packages/node-resolve/test/fixtures/exports-main-directory.js b/packages/node-resolve/test/fixtures/exports-main-directory.js new file mode 100644 index 000000000..b1ff09727 --- /dev/null +++ b/packages/node-resolve/test/fixtures/exports-main-directory.js @@ -0,0 +1,5 @@ +import a from 'exports-main-directory/a.js'; +import b from 'exports-main-directory/foo/b.js'; +import c from 'exports-main-directory/foo/nested/c.js'; + +export default { a, b, c }; diff --git a/packages/node-resolve/test/fixtures/exports-mappings-and-conditions.js b/packages/node-resolve/test/fixtures/exports-mappings-and-conditions.js new file mode 100644 index 000000000..8e67bda41 --- /dev/null +++ b/packages/node-resolve/test/fixtures/exports-mappings-and-conditions.js @@ -0,0 +1,5 @@ +import main from 'exports-mappings-and-conditions'; +import foo from 'exports-mappings-and-conditions/foo'; +import bar from 'exports-mappings-and-conditions/bar'; + +export default { main, foo, bar }; diff --git a/packages/node-resolve/test/fixtures/exports-nested-conditions.js b/packages/node-resolve/test/fixtures/exports-nested-conditions.js new file mode 100644 index 000000000..b1a30f4fc --- /dev/null +++ b/packages/node-resolve/test/fixtures/exports-nested-conditions.js @@ -0,0 +1,3 @@ +import main from 'exports-nested-conditions'; + +export default main; diff --git a/packages/node-resolve/test/fixtures/exports-non-existing-subpath.js b/packages/node-resolve/test/fixtures/exports-non-existing-subpath.js new file mode 100644 index 000000000..0a4fb26a4 --- /dev/null +++ b/packages/node-resolve/test/fixtures/exports-non-existing-subpath.js @@ -0,0 +1,3 @@ +import bar from 'exports-non-existing-subpath/bar'; + +export default bar; diff --git a/packages/node-resolve/test/fixtures/exports-prevent-unspecified-subpath.js b/packages/node-resolve/test/fixtures/exports-prevent-unspecified-subpath.js new file mode 100644 index 000000000..39e34e0e7 --- /dev/null +++ b/packages/node-resolve/test/fixtures/exports-prevent-unspecified-subpath.js @@ -0,0 +1,3 @@ +import bar from 'exports-top-level-mappings/bar'; + +export default bar; diff --git a/packages/node-resolve/test/fixtures/exports-shorthand-fallback.js b/packages/node-resolve/test/fixtures/exports-shorthand-fallback.js new file mode 100644 index 000000000..7405c6992 --- /dev/null +++ b/packages/node-resolve/test/fixtures/exports-shorthand-fallback.js @@ -0,0 +1,3 @@ +import exportsMapEntry from 'exports-shorthand'; + +export default exportsMapEntry; diff --git a/packages/node-resolve/test/fixtures/exports-shorthand-subpath.js b/packages/node-resolve/test/fixtures/exports-shorthand-subpath.js new file mode 100644 index 000000000..7273f5f73 --- /dev/null +++ b/packages/node-resolve/test/fixtures/exports-shorthand-subpath.js @@ -0,0 +1,3 @@ +import exportsMapEntry from 'exports-shorthand/foo'; + +export default exportsMapEntry; diff --git a/packages/node-resolve/test/fixtures/exports-shorthand.js b/packages/node-resolve/test/fixtures/exports-shorthand.js new file mode 100644 index 000000000..7405c6992 --- /dev/null +++ b/packages/node-resolve/test/fixtures/exports-shorthand.js @@ -0,0 +1,3 @@ +import exportsMapEntry from 'exports-shorthand'; + +export default exportsMapEntry; diff --git a/packages/node-resolve/test/fixtures/exports-star.js b/packages/node-resolve/test/fixtures/exports-star.js new file mode 100644 index 000000000..f71eeee4a --- /dev/null +++ b/packages/node-resolve/test/fixtures/exports-star.js @@ -0,0 +1,5 @@ +import a from 'exports-star/foo/a'; +import b from 'exports-star/foo/b'; +import c from 'exports-star/foo/bar/c'; + +export default { a, b, c }; diff --git a/packages/node-resolve/test/fixtures/exports-top-level-conditions.js b/packages/node-resolve/test/fixtures/exports-top-level-conditions.js new file mode 100644 index 000000000..1b2d8d621 --- /dev/null +++ b/packages/node-resolve/test/fixtures/exports-top-level-conditions.js @@ -0,0 +1,3 @@ +import main from 'exports-top-level-conditions'; + +export default main; diff --git a/packages/node-resolve/test/fixtures/exports-top-level-mappings.js b/packages/node-resolve/test/fixtures/exports-top-level-mappings.js new file mode 100644 index 000000000..63d50f1e4 --- /dev/null +++ b/packages/node-resolve/test/fixtures/exports-top-level-mappings.js @@ -0,0 +1,4 @@ +import main from 'exports-top-level-mappings'; +import foo from 'exports-top-level-mappings/foo'; + +export default { main, foo }; diff --git a/packages/node-resolve/test/fixtures/node_modules/exports-cjs/index-cjs.js b/packages/node-resolve/test/fixtures/node_modules/exports-cjs/index-cjs.js new file mode 100644 index 000000000..1f9d31a5e --- /dev/null +++ b/packages/node-resolve/test/fixtures/node_modules/exports-cjs/index-cjs.js @@ -0,0 +1 @@ +module.exports = 'CJS'; \ No newline at end of file diff --git a/packages/node-resolve/test/fixtures/node_modules/exports-cjs/index-esm.js b/packages/node-resolve/test/fixtures/node_modules/exports-cjs/index-esm.js new file mode 100644 index 000000000..f6e979ebf --- /dev/null +++ b/packages/node-resolve/test/fixtures/node_modules/exports-cjs/index-esm.js @@ -0,0 +1 @@ +module.exports = 'ESM'; \ No newline at end of file diff --git a/packages/node-resolve/test/fixtures/node_modules/exports-cjs/package.json b/packages/node-resolve/test/fixtures/node_modules/exports-cjs/package.json new file mode 100644 index 000000000..65cee8751 --- /dev/null +++ b/packages/node-resolve/test/fixtures/node_modules/exports-cjs/package.json @@ -0,0 +1,10 @@ +{ + "name": "exports-top-level-mappings", + "main": "index.js", + "exports": { + ".": { + "require": "./index-cjs.js", + "import": "./index-esm.js" + } + } +} diff --git a/packages/node-resolve/test/fixtures/node_modules/exports-conditions-fallback/index-mapped.js b/packages/node-resolve/test/fixtures/node_modules/exports-conditions-fallback/index-mapped.js new file mode 100644 index 000000000..dc5589590 --- /dev/null +++ b/packages/node-resolve/test/fixtures/node_modules/exports-conditions-fallback/index-mapped.js @@ -0,0 +1 @@ +export default 'MAIN MAPPED'; diff --git a/packages/node-resolve/test/fixtures/node_modules/exports-conditions-fallback/index.js b/packages/node-resolve/test/fixtures/node_modules/exports-conditions-fallback/index.js new file mode 100644 index 000000000..aaf1b3fe1 --- /dev/null +++ b/packages/node-resolve/test/fixtures/node_modules/exports-conditions-fallback/index.js @@ -0,0 +1 @@ +export default 'MAIN'; diff --git a/packages/node-resolve/test/fixtures/node_modules/exports-conditions-fallback/package.json b/packages/node-resolve/test/fixtures/node_modules/exports-conditions-fallback/package.json new file mode 100644 index 000000000..aff5ec2a8 --- /dev/null +++ b/packages/node-resolve/test/fixtures/node_modules/exports-conditions-fallback/package.json @@ -0,0 +1,10 @@ +{ + "name": "exports-conditions-fallback", + "main": "index.js", + "exports": { + "node": { + "require": "./index.js" + }, + "default": "./index-mapped.js" + } +} diff --git a/packages/node-resolve/test/fixtures/node_modules/exports-directory/exported-foo/a.js b/packages/node-resolve/test/fixtures/node_modules/exports-directory/exported-foo/a.js new file mode 100644 index 000000000..b7119a4f2 --- /dev/null +++ b/packages/node-resolve/test/fixtures/node_modules/exports-directory/exported-foo/a.js @@ -0,0 +1 @@ +export default 'exported-foo a'; diff --git a/packages/node-resolve/test/fixtures/node_modules/exports-directory/exported-foo/b.js b/packages/node-resolve/test/fixtures/node_modules/exports-directory/exported-foo/b.js new file mode 100644 index 000000000..6d0e833a7 --- /dev/null +++ b/packages/node-resolve/test/fixtures/node_modules/exports-directory/exported-foo/b.js @@ -0,0 +1 @@ +export default 'exported-foo b'; diff --git a/packages/node-resolve/test/fixtures/node_modules/exports-directory/exported-foo/nested/c.js b/packages/node-resolve/test/fixtures/node_modules/exports-directory/exported-foo/nested/c.js new file mode 100644 index 000000000..27265328a --- /dev/null +++ b/packages/node-resolve/test/fixtures/node_modules/exports-directory/exported-foo/nested/c.js @@ -0,0 +1 @@ +export default 'exported-foo c'; diff --git a/packages/node-resolve/test/fixtures/node_modules/exports-directory/foo/a.js b/packages/node-resolve/test/fixtures/node_modules/exports-directory/foo/a.js new file mode 100644 index 000000000..f3e609902 --- /dev/null +++ b/packages/node-resolve/test/fixtures/node_modules/exports-directory/foo/a.js @@ -0,0 +1 @@ +export default 'foo a'; diff --git a/packages/node-resolve/test/fixtures/node_modules/exports-directory/foo/b.js b/packages/node-resolve/test/fixtures/node_modules/exports-directory/foo/b.js new file mode 100644 index 000000000..798313b69 --- /dev/null +++ b/packages/node-resolve/test/fixtures/node_modules/exports-directory/foo/b.js @@ -0,0 +1 @@ +export default 'foo b'; diff --git a/packages/node-resolve/test/fixtures/node_modules/exports-directory/foo/nested/c.js b/packages/node-resolve/test/fixtures/node_modules/exports-directory/foo/nested/c.js new file mode 100644 index 000000000..041c1a3b9 --- /dev/null +++ b/packages/node-resolve/test/fixtures/node_modules/exports-directory/foo/nested/c.js @@ -0,0 +1 @@ +export default 'foo c'; diff --git a/packages/node-resolve/test/fixtures/node_modules/exports-directory/package.json b/packages/node-resolve/test/fixtures/node_modules/exports-directory/package.json new file mode 100644 index 000000000..c68136251 --- /dev/null +++ b/packages/node-resolve/test/fixtures/node_modules/exports-directory/package.json @@ -0,0 +1,7 @@ +{ + "name": "exports-directory", + "main": "index.js", + "exports": { + "./foo/": "./exported-foo/" + } +} diff --git a/packages/node-resolve/test/fixtures/node_modules/exports-main-directory/a.js b/packages/node-resolve/test/fixtures/node_modules/exports-main-directory/a.js new file mode 100644 index 000000000..bcc62b225 --- /dev/null +++ b/packages/node-resolve/test/fixtures/node_modules/exports-main-directory/a.js @@ -0,0 +1 @@ +export default 'exported a'; diff --git a/packages/node-resolve/test/fixtures/node_modules/exports-main-directory/foo/b.js b/packages/node-resolve/test/fixtures/node_modules/exports-main-directory/foo/b.js new file mode 100644 index 000000000..f9c84f907 --- /dev/null +++ b/packages/node-resolve/test/fixtures/node_modules/exports-main-directory/foo/b.js @@ -0,0 +1 @@ +export default 'exported b'; diff --git a/packages/node-resolve/test/fixtures/node_modules/exports-main-directory/foo/nested/c.js b/packages/node-resolve/test/fixtures/node_modules/exports-main-directory/foo/nested/c.js new file mode 100644 index 000000000..b2e193530 --- /dev/null +++ b/packages/node-resolve/test/fixtures/node_modules/exports-main-directory/foo/nested/c.js @@ -0,0 +1 @@ +export default 'exported c'; diff --git a/packages/node-resolve/test/fixtures/node_modules/exports-main-directory/package.json b/packages/node-resolve/test/fixtures/node_modules/exports-main-directory/package.json new file mode 100644 index 000000000..f46729a48 --- /dev/null +++ b/packages/node-resolve/test/fixtures/node_modules/exports-main-directory/package.json @@ -0,0 +1,7 @@ +{ + "name": "exports-main-directory", + "main": "index.js", + "exports": { + "./": "./" + } +} diff --git a/packages/node-resolve/test/fixtures/node_modules/exports-mappings-and-conditions/bar-mapped.js b/packages/node-resolve/test/fixtures/node_modules/exports-mappings-and-conditions/bar-mapped.js new file mode 100644 index 000000000..592f4b05b --- /dev/null +++ b/packages/node-resolve/test/fixtures/node_modules/exports-mappings-and-conditions/bar-mapped.js @@ -0,0 +1 @@ +export default 'BAR MAPPED'; diff --git a/packages/node-resolve/test/fixtures/node_modules/exports-mappings-and-conditions/bar.js b/packages/node-resolve/test/fixtures/node_modules/exports-mappings-and-conditions/bar.js new file mode 100644 index 000000000..d742342f6 --- /dev/null +++ b/packages/node-resolve/test/fixtures/node_modules/exports-mappings-and-conditions/bar.js @@ -0,0 +1 @@ +export default 'BAR'; diff --git a/packages/node-resolve/test/fixtures/node_modules/exports-mappings-and-conditions/foo-mapped.js b/packages/node-resolve/test/fixtures/node_modules/exports-mappings-and-conditions/foo-mapped.js new file mode 100644 index 000000000..8b87f90ae --- /dev/null +++ b/packages/node-resolve/test/fixtures/node_modules/exports-mappings-and-conditions/foo-mapped.js @@ -0,0 +1 @@ +export default 'FOO MAPPED'; diff --git a/packages/node-resolve/test/fixtures/node_modules/exports-mappings-and-conditions/foo.js b/packages/node-resolve/test/fixtures/node_modules/exports-mappings-and-conditions/foo.js new file mode 100644 index 000000000..20fc97bf8 --- /dev/null +++ b/packages/node-resolve/test/fixtures/node_modules/exports-mappings-and-conditions/foo.js @@ -0,0 +1 @@ +export default 'FOO'; diff --git a/packages/node-resolve/test/fixtures/node_modules/exports-mappings-and-conditions/index-mapped.js b/packages/node-resolve/test/fixtures/node_modules/exports-mappings-and-conditions/index-mapped.js new file mode 100644 index 000000000..dc5589590 --- /dev/null +++ b/packages/node-resolve/test/fixtures/node_modules/exports-mappings-and-conditions/index-mapped.js @@ -0,0 +1 @@ +export default 'MAIN MAPPED'; diff --git a/packages/node-resolve/test/fixtures/node_modules/exports-mappings-and-conditions/index.js b/packages/node-resolve/test/fixtures/node_modules/exports-mappings-and-conditions/index.js new file mode 100644 index 000000000..aaf1b3fe1 --- /dev/null +++ b/packages/node-resolve/test/fixtures/node_modules/exports-mappings-and-conditions/index.js @@ -0,0 +1 @@ +export default 'MAIN'; diff --git a/packages/node-resolve/test/fixtures/node_modules/exports-mappings-and-conditions/package.json b/packages/node-resolve/test/fixtures/node_modules/exports-mappings-and-conditions/package.json new file mode 100644 index 000000000..5a2e55562 --- /dev/null +++ b/packages/node-resolve/test/fixtures/node_modules/exports-mappings-and-conditions/package.json @@ -0,0 +1,21 @@ +{ + "name": "exports-mappings-and-conditions", + "main": "index.js", + "exports": { + ".": { + "require": "./index.js'", + "module": "./index-mapped.js" + }, + "./foo": { + "node": { + "require": "./foo.js", + "default": "./foo.js" + }, + "module": { + "require": "./foo.js", + "default": "./foo-mapped.js" + } + }, + "./bar": "./bar-mapped.js" + } +} diff --git a/packages/node-resolve/test/fixtures/node_modules/exports-nested-conditions/index-mapped.js b/packages/node-resolve/test/fixtures/node_modules/exports-nested-conditions/index-mapped.js new file mode 100644 index 000000000..dc5589590 --- /dev/null +++ b/packages/node-resolve/test/fixtures/node_modules/exports-nested-conditions/index-mapped.js @@ -0,0 +1 @@ +export default 'MAIN MAPPED'; diff --git a/packages/node-resolve/test/fixtures/node_modules/exports-nested-conditions/index.js b/packages/node-resolve/test/fixtures/node_modules/exports-nested-conditions/index.js new file mode 100644 index 000000000..aaf1b3fe1 --- /dev/null +++ b/packages/node-resolve/test/fixtures/node_modules/exports-nested-conditions/index.js @@ -0,0 +1 @@ +export default 'MAIN'; diff --git a/packages/node-resolve/test/fixtures/node_modules/exports-nested-conditions/package.json b/packages/node-resolve/test/fixtures/node_modules/exports-nested-conditions/package.json new file mode 100644 index 000000000..729dae830 --- /dev/null +++ b/packages/node-resolve/test/fixtures/node_modules/exports-nested-conditions/package.json @@ -0,0 +1,11 @@ +{ + "name": "exports-nested-conditions", + "main": "index.js", + "exports": { + "module": { + "node": "./index.js", + "browser": "./index.js", + "default": "./index-mapped.js" + } + } +} diff --git a/packages/node-resolve/test/fixtures/node_modules/exports-non-existing-subpath/foo-mapped.js b/packages/node-resolve/test/fixtures/node_modules/exports-non-existing-subpath/foo-mapped.js new file mode 100644 index 000000000..8b87f90ae --- /dev/null +++ b/packages/node-resolve/test/fixtures/node_modules/exports-non-existing-subpath/foo-mapped.js @@ -0,0 +1 @@ +export default 'FOO MAPPED'; diff --git a/packages/node-resolve/test/fixtures/node_modules/exports-non-existing-subpath/foo.js b/packages/node-resolve/test/fixtures/node_modules/exports-non-existing-subpath/foo.js new file mode 100644 index 000000000..20fc97bf8 --- /dev/null +++ b/packages/node-resolve/test/fixtures/node_modules/exports-non-existing-subpath/foo.js @@ -0,0 +1 @@ +export default 'FOO'; diff --git a/packages/node-resolve/test/fixtures/node_modules/exports-non-existing-subpath/index-mapped.js b/packages/node-resolve/test/fixtures/node_modules/exports-non-existing-subpath/index-mapped.js new file mode 100644 index 000000000..dc5589590 --- /dev/null +++ b/packages/node-resolve/test/fixtures/node_modules/exports-non-existing-subpath/index-mapped.js @@ -0,0 +1 @@ +export default 'MAIN MAPPED'; diff --git a/packages/node-resolve/test/fixtures/node_modules/exports-non-existing-subpath/index.js b/packages/node-resolve/test/fixtures/node_modules/exports-non-existing-subpath/index.js new file mode 100644 index 000000000..aaf1b3fe1 --- /dev/null +++ b/packages/node-resolve/test/fixtures/node_modules/exports-non-existing-subpath/index.js @@ -0,0 +1 @@ +export default 'MAIN'; diff --git a/packages/node-resolve/test/fixtures/node_modules/exports-non-existing-subpath/package.json b/packages/node-resolve/test/fixtures/node_modules/exports-non-existing-subpath/package.json new file mode 100644 index 000000000..0f7855cd6 --- /dev/null +++ b/packages/node-resolve/test/fixtures/node_modules/exports-non-existing-subpath/package.json @@ -0,0 +1,8 @@ +{ + "name": "exports-non-existing-subpath", + "main": "index.js", + "exports": { + ".": "./index-mapped.js", + "./foo": "./foo-mapped.js" + } +} diff --git a/packages/node-resolve/test/fixtures/node_modules/exports-prevent-direct-imports/bar.js b/packages/node-resolve/test/fixtures/node_modules/exports-prevent-direct-imports/bar.js new file mode 100644 index 000000000..d742342f6 --- /dev/null +++ b/packages/node-resolve/test/fixtures/node_modules/exports-prevent-direct-imports/bar.js @@ -0,0 +1 @@ +export default 'BAR'; diff --git a/packages/node-resolve/test/fixtures/node_modules/exports-prevent-direct-imports/foo.js b/packages/node-resolve/test/fixtures/node_modules/exports-prevent-direct-imports/foo.js new file mode 100644 index 000000000..20fc97bf8 --- /dev/null +++ b/packages/node-resolve/test/fixtures/node_modules/exports-prevent-direct-imports/foo.js @@ -0,0 +1 @@ +export default 'FOO'; diff --git a/packages/node-resolve/test/fixtures/node_modules/exports-prevent-direct-imports/index-mapped.js b/packages/node-resolve/test/fixtures/node_modules/exports-prevent-direct-imports/index-mapped.js new file mode 100644 index 000000000..dc5589590 --- /dev/null +++ b/packages/node-resolve/test/fixtures/node_modules/exports-prevent-direct-imports/index-mapped.js @@ -0,0 +1 @@ +export default 'MAIN MAPPED'; diff --git a/packages/node-resolve/test/fixtures/node_modules/exports-prevent-direct-imports/index.js b/packages/node-resolve/test/fixtures/node_modules/exports-prevent-direct-imports/index.js new file mode 100644 index 000000000..aaf1b3fe1 --- /dev/null +++ b/packages/node-resolve/test/fixtures/node_modules/exports-prevent-direct-imports/index.js @@ -0,0 +1 @@ +export default 'MAIN'; diff --git a/packages/node-resolve/test/fixtures/node_modules/exports-prevent-direct-imports/package.json b/packages/node-resolve/test/fixtures/node_modules/exports-prevent-direct-imports/package.json new file mode 100644 index 000000000..23db68cb9 --- /dev/null +++ b/packages/node-resolve/test/fixtures/node_modules/exports-prevent-direct-imports/package.json @@ -0,0 +1,8 @@ +{ + "name": "exports-prevent-direct-imports", + "main": "index.js", + "exports": { + ".": "./index.js", + "./foo.js": "./foo.js" + } +} diff --git a/packages/node-resolve/test/fixtures/node_modules/exports-prevent-unspecified-subpath/foo-mapped.js b/packages/node-resolve/test/fixtures/node_modules/exports-prevent-unspecified-subpath/foo-mapped.js new file mode 100644 index 000000000..8b87f90ae --- /dev/null +++ b/packages/node-resolve/test/fixtures/node_modules/exports-prevent-unspecified-subpath/foo-mapped.js @@ -0,0 +1 @@ +export default 'FOO MAPPED'; diff --git a/packages/node-resolve/test/fixtures/node_modules/exports-prevent-unspecified-subpath/foo.js b/packages/node-resolve/test/fixtures/node_modules/exports-prevent-unspecified-subpath/foo.js new file mode 100644 index 000000000..20fc97bf8 --- /dev/null +++ b/packages/node-resolve/test/fixtures/node_modules/exports-prevent-unspecified-subpath/foo.js @@ -0,0 +1 @@ +export default 'FOO'; diff --git a/packages/node-resolve/test/fixtures/node_modules/exports-prevent-unspecified-subpath/index-mapped.js b/packages/node-resolve/test/fixtures/node_modules/exports-prevent-unspecified-subpath/index-mapped.js new file mode 100644 index 000000000..dc5589590 --- /dev/null +++ b/packages/node-resolve/test/fixtures/node_modules/exports-prevent-unspecified-subpath/index-mapped.js @@ -0,0 +1 @@ +export default 'MAIN MAPPED'; diff --git a/packages/node-resolve/test/fixtures/node_modules/exports-prevent-unspecified-subpath/index.js b/packages/node-resolve/test/fixtures/node_modules/exports-prevent-unspecified-subpath/index.js new file mode 100644 index 000000000..aaf1b3fe1 --- /dev/null +++ b/packages/node-resolve/test/fixtures/node_modules/exports-prevent-unspecified-subpath/index.js @@ -0,0 +1 @@ +export default 'MAIN'; diff --git a/packages/node-resolve/test/fixtures/node_modules/exports-prevent-unspecified-subpath/package.json b/packages/node-resolve/test/fixtures/node_modules/exports-prevent-unspecified-subpath/package.json new file mode 100644 index 000000000..2862a5771 --- /dev/null +++ b/packages/node-resolve/test/fixtures/node_modules/exports-prevent-unspecified-subpath/package.json @@ -0,0 +1,8 @@ +{ + "name": "exports-prevent-unspecified-subpath", + "main": "index.js", + "exports": { + ".": "./index-mapped.js", + "./foo": "./foo-mapped.js" + } +} diff --git a/packages/node-resolve/test/fixtures/node_modules/exports-shorthand-fallback/index-mapped.js b/packages/node-resolve/test/fixtures/node_modules/exports-shorthand-fallback/index-mapped.js new file mode 100644 index 000000000..dc5589590 --- /dev/null +++ b/packages/node-resolve/test/fixtures/node_modules/exports-shorthand-fallback/index-mapped.js @@ -0,0 +1 @@ +export default 'MAIN MAPPED'; diff --git a/packages/node-resolve/test/fixtures/node_modules/exports-shorthand-fallback/index.js b/packages/node-resolve/test/fixtures/node_modules/exports-shorthand-fallback/index.js new file mode 100644 index 000000000..aaf1b3fe1 --- /dev/null +++ b/packages/node-resolve/test/fixtures/node_modules/exports-shorthand-fallback/index.js @@ -0,0 +1 @@ +export default 'MAIN'; diff --git a/packages/node-resolve/test/fixtures/node_modules/exports-shorthand-fallback/package.json b/packages/node-resolve/test/fixtures/node_modules/exports-shorthand-fallback/package.json new file mode 100644 index 000000000..de989359d --- /dev/null +++ b/packages/node-resolve/test/fixtures/node_modules/exports-shorthand-fallback/package.json @@ -0,0 +1,5 @@ +{ + "name": "exports-shorthand-fallback", + "main": "index.js", + "exports": ["./index-mapped.js", "./not-index-mapped.js"] +} diff --git a/packages/node-resolve/test/fixtures/node_modules/exports-shorthand/index-mapped.js b/packages/node-resolve/test/fixtures/node_modules/exports-shorthand/index-mapped.js new file mode 100644 index 000000000..dc5589590 --- /dev/null +++ b/packages/node-resolve/test/fixtures/node_modules/exports-shorthand/index-mapped.js @@ -0,0 +1 @@ +export default 'MAIN MAPPED'; diff --git a/packages/node-resolve/test/fixtures/node_modules/exports-shorthand/index.js b/packages/node-resolve/test/fixtures/node_modules/exports-shorthand/index.js new file mode 100644 index 000000000..aaf1b3fe1 --- /dev/null +++ b/packages/node-resolve/test/fixtures/node_modules/exports-shorthand/index.js @@ -0,0 +1 @@ +export default 'MAIN'; diff --git a/packages/node-resolve/test/fixtures/node_modules/exports-shorthand/package.json b/packages/node-resolve/test/fixtures/node_modules/exports-shorthand/package.json new file mode 100644 index 000000000..97f25f41e --- /dev/null +++ b/packages/node-resolve/test/fixtures/node_modules/exports-shorthand/package.json @@ -0,0 +1,5 @@ +{ + "name": "exports-shorthand", + "main": "index.js", + "exports": "./index-mapped.js" +} diff --git a/packages/node-resolve/test/fixtures/node_modules/exports-star/foo/a.js b/packages/node-resolve/test/fixtures/node_modules/exports-star/foo/a.js new file mode 100644 index 000000000..5a373d2fa --- /dev/null +++ b/packages/node-resolve/test/fixtures/node_modules/exports-star/foo/a.js @@ -0,0 +1 @@ +export default 'A'; diff --git a/packages/node-resolve/test/fixtures/node_modules/exports-star/foo/b.js b/packages/node-resolve/test/fixtures/node_modules/exports-star/foo/b.js new file mode 100644 index 000000000..43431cbc9 --- /dev/null +++ b/packages/node-resolve/test/fixtures/node_modules/exports-star/foo/b.js @@ -0,0 +1 @@ +export default 'B'; diff --git a/packages/node-resolve/test/fixtures/node_modules/exports-star/foo/bar/c.js b/packages/node-resolve/test/fixtures/node_modules/exports-star/foo/bar/c.js new file mode 100644 index 000000000..d152c0607 --- /dev/null +++ b/packages/node-resolve/test/fixtures/node_modules/exports-star/foo/bar/c.js @@ -0,0 +1 @@ +export default 'C'; diff --git a/packages/node-resolve/test/fixtures/node_modules/exports-star/package.json b/packages/node-resolve/test/fixtures/node_modules/exports-star/package.json new file mode 100644 index 000000000..eabd64006 --- /dev/null +++ b/packages/node-resolve/test/fixtures/node_modules/exports-star/package.json @@ -0,0 +1,7 @@ +{ + "name": "exports-star", + "main": "index.js", + "exports": { + "./foo/*": "./foo/*.js" + } +} diff --git a/packages/node-resolve/test/fixtures/node_modules/exports-top-level-conditions/index-mapped.js b/packages/node-resolve/test/fixtures/node_modules/exports-top-level-conditions/index-mapped.js new file mode 100644 index 000000000..dc5589590 --- /dev/null +++ b/packages/node-resolve/test/fixtures/node_modules/exports-top-level-conditions/index-mapped.js @@ -0,0 +1 @@ +export default 'MAIN MAPPED'; diff --git a/packages/node-resolve/test/fixtures/node_modules/exports-top-level-conditions/index.js b/packages/node-resolve/test/fixtures/node_modules/exports-top-level-conditions/index.js new file mode 100644 index 000000000..aaf1b3fe1 --- /dev/null +++ b/packages/node-resolve/test/fixtures/node_modules/exports-top-level-conditions/index.js @@ -0,0 +1 @@ +export default 'MAIN'; diff --git a/packages/node-resolve/test/fixtures/node_modules/exports-top-level-conditions/package.json b/packages/node-resolve/test/fixtures/node_modules/exports-top-level-conditions/package.json new file mode 100644 index 000000000..c753831d2 --- /dev/null +++ b/packages/node-resolve/test/fixtures/node_modules/exports-top-level-conditions/package.json @@ -0,0 +1,8 @@ +{ + "name": "exports-top-level-conditions", + "main": "index.js", + "exports": { + "require": "./index.js", + "module": "./index-mapped.js" + } +} diff --git a/packages/node-resolve/test/fixtures/node_modules/exports-top-level-mappings/foo-mapped.js b/packages/node-resolve/test/fixtures/node_modules/exports-top-level-mappings/foo-mapped.js new file mode 100644 index 000000000..8b87f90ae --- /dev/null +++ b/packages/node-resolve/test/fixtures/node_modules/exports-top-level-mappings/foo-mapped.js @@ -0,0 +1 @@ +export default 'FOO MAPPED'; diff --git a/packages/node-resolve/test/fixtures/node_modules/exports-top-level-mappings/foo.js b/packages/node-resolve/test/fixtures/node_modules/exports-top-level-mappings/foo.js new file mode 100644 index 000000000..20fc97bf8 --- /dev/null +++ b/packages/node-resolve/test/fixtures/node_modules/exports-top-level-mappings/foo.js @@ -0,0 +1 @@ +export default 'FOO'; diff --git a/packages/node-resolve/test/fixtures/node_modules/exports-top-level-mappings/index-mapped.js b/packages/node-resolve/test/fixtures/node_modules/exports-top-level-mappings/index-mapped.js new file mode 100644 index 000000000..dc5589590 --- /dev/null +++ b/packages/node-resolve/test/fixtures/node_modules/exports-top-level-mappings/index-mapped.js @@ -0,0 +1 @@ +export default 'MAIN MAPPED'; diff --git a/packages/node-resolve/test/fixtures/node_modules/exports-top-level-mappings/index.js b/packages/node-resolve/test/fixtures/node_modules/exports-top-level-mappings/index.js new file mode 100644 index 000000000..aaf1b3fe1 --- /dev/null +++ b/packages/node-resolve/test/fixtures/node_modules/exports-top-level-mappings/index.js @@ -0,0 +1 @@ +export default 'MAIN'; diff --git a/packages/node-resolve/test/fixtures/node_modules/exports-top-level-mappings/package.json b/packages/node-resolve/test/fixtures/node_modules/exports-top-level-mappings/package.json new file mode 100644 index 000000000..deffe5419 --- /dev/null +++ b/packages/node-resolve/test/fixtures/node_modules/exports-top-level-mappings/package.json @@ -0,0 +1,8 @@ +{ + "name": "exports-top-level-mappings", + "main": "index.js", + "exports": { + ".": "./index-mapped.js", + "./foo": "./foo-mapped.js" + } +} diff --git a/packages/node-resolve/test/package-entry-points.js b/packages/node-resolve/test/package-entry-points.js new file mode 100644 index 000000000..9311ecae4 --- /dev/null +++ b/packages/node-resolve/test/package-entry-points.js @@ -0,0 +1,200 @@ +const { join } = require('path'); + +const test = require('ava'); +const { rollup } = require('rollup'); +const commonjs = require('@rollup/plugin-commonjs'); + +const { testBundle } = require('../../../util/test'); + +const { nodeResolve } = require('..'); + +process.chdir(join(__dirname, 'fixtures')); + +test('handles export map shorthand', async (t) => { + const bundle = await rollup({ + input: 'exports-shorthand.js', + onwarn: () => { + t.fail('No warnings were expected'); + }, + plugins: [nodeResolve()] + }); + const { module } = await testBundle(t, bundle); + + t.is(module.exports, 'MAIN MAPPED'); +}); + +test('handles export map with fallback', async (t) => { + const bundle = await rollup({ + input: 'exports-shorthand-fallback.js', + onwarn: () => { + t.fail('No warnings were expected'); + }, + plugins: [nodeResolve()] + }); + const { module } = await testBundle(t, bundle); + + t.is(module.exports, 'MAIN MAPPED'); +}); + +test('handles export map with top level mappings', async (t) => { + const bundle = await rollup({ + input: 'exports-top-level-mappings.js', + onwarn: () => { + t.fail('No warnings were expected'); + }, + plugins: [nodeResolve()] + }); + const { module } = await testBundle(t, bundle); + + t.is(module.exports.main, 'MAIN MAPPED'); + t.is(module.exports.foo, 'FOO MAPPED'); +}); + +test('handles export map with top level conditions', async (t) => { + const bundle = await rollup({ + input: 'exports-top-level-conditions.js', + onwarn: () => { + t.fail('No warnings were expected'); + }, + plugins: [nodeResolve()] + }); + const { module } = await testBundle(t, bundle); + + t.is(module.exports, 'MAIN MAPPED'); +}); + +test('handles export map with nested conditions', async (t) => { + const bundle = await rollup({ + input: 'exports-nested-conditions.js', + onwarn: () => { + t.fail('No warnings were expected'); + }, + plugins: [nodeResolve()] + }); + const { module } = await testBundle(t, bundle); + + t.is(module.exports, 'MAIN MAPPED'); +}); + +test('handles conditions with a fallback', async (t) => { + const bundle = await rollup({ + input: 'exports-conditions-fallback.js', + onwarn: () => { + t.fail('No warnings were expected'); + }, + plugins: [nodeResolve()] + }); + const { module } = await testBundle(t, bundle); + + t.is(module.exports, 'MAIN MAPPED'); +}); + +test('handles top level mappings with conditions', async (t) => { + const bundle = await rollup({ + input: 'exports-mappings-and-conditions.js', + onwarn: () => { + t.fail('No warnings were expected'); + }, + plugins: [nodeResolve()] + }); + const { module } = await testBundle(t, bundle); + + t.is(module.exports.main, 'MAIN MAPPED'); + t.is(module.exports.foo, 'FOO MAPPED'); + t.is(module.exports.bar, 'BAR MAPPED'); +}); + +test('handles directory exports', async (t) => { + const bundle = await rollup({ + input: 'exports-directory.js', + onwarn: () => { + t.fail('No warnings were expected'); + }, + plugins: [nodeResolve()] + }); + const { module } = await testBundle(t, bundle); + + t.is(module.exports.a, 'exported-foo a'); + t.is(module.exports.b, 'exported-foo b'); + t.is(module.exports.c, 'exported-foo c'); +}); + +test('handles main directory exports', async (t) => { + const bundle = await rollup({ + input: 'exports-main-directory.js', + onwarn: () => { + t.fail('No warnings were expected'); + }, + plugins: [nodeResolve()] + }); + const { module } = await testBundle(t, bundle); + + t.is(module.exports.a, 'exported a'); + t.is(module.exports.b, 'exported b'); + t.is(module.exports.c, 'exported c'); +}); + +test('logs a warning when using shorthand and importing a subpath', async (t) => { + t.plan(1); + const errors = []; + await rollup({ + input: 'exports-shorthand-subpath.js', + onwarn: (error) => { + errors.push(error); + }, + plugins: [nodeResolve()] + }); + t.true(errors[0].message.includes('Package subpath \'./foo\' is not defined by "exports" in')); +}); + +test('logs a warning when a subpath cannot be found', async (t) => { + t.plan(1); + const errors = []; + await rollup({ + input: 'exports-non-existing-subpath.js', + onwarn: (error) => { + errors.push(error); + }, + plugins: [nodeResolve()] + }); + t.true(errors[0].message.includes('Package subpath \'./bar\' is not defined by "exports" in')); +}); + +test('prevents importing files not specified in exports map', async (t) => { + t.plan(1); + const errors = []; + await rollup({ + input: 'exports-prevent-unspecified-subpath.js', + onwarn: (error) => { + errors.push(error); + }, + plugins: [nodeResolve()] + }); + t.true(errors[0].message.includes('Package subpath \'./bar\' is not defined by "exports" in')); +}); + +test('uses "require" condition when a module is referenced with require', async (t) => { + const bundle = await rollup({ + input: 'exports-cjs.js', + onwarn: () => { + t.fail('No warnings were expected'); + }, + plugins: [commonjs(), nodeResolve()] + }); + const { module } = await testBundle(t, bundle); + + t.is(module.exports, 'CJS'); +}); + +test('can use star pattern in exports field', async (t) => { + const bundle = await rollup({ + input: 'exports-star.js', + onwarn: () => { + t.fail('No warnings were expected'); + }, + plugins: [nodeResolve()] + }); + const { module } = await testBundle(t, bundle); + + t.deepEqual(module.exports, { a: 'A', b: 'B', c: 'C' }); +}); diff --git a/packages/node-resolve/types/index.d.ts b/packages/node-resolve/types/index.d.ts index d2fed0f77..f58031979 100755 --- a/packages/node-resolve/types/index.d.ts +++ b/packages/node-resolve/types/index.d.ts @@ -9,6 +9,17 @@ export const DEFAULTS: { }; export interface RollupNodeResolveOptions { + /** + * Additional conditions of the package.json exports field to match when resolving modules. + * By default, this plugin looks for the `'default', 'module', 'import']` conditions when resolving imports. + * + * When using `@rollup/plugin-commonjs` v16 or higher, this plugin will use the + * `['default', 'module', 'import']` conditions when resolving require statements. + * + * Setting this option will add extra conditions on top of the default conditions. + * See https://nodejs.org/api/packages.html#packages_conditional_exports for more information. + */ + exportConditions?: string[]; /** * If `true`, instructs the plugin to use the `"browser"` property in `package.json` * files to specify alternative files to load for bundling. This is useful when diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 5a9d401be..f36a816e9 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -328,7 +328,7 @@ importers: '@babel/core': 7.12.3 '@babel/plugin-transform-typescript': 7.12.1_@babel+core@7.12.3 '@rollup/plugin-babel': 5.2.1_@babel+core@7.12.3+rollup@2.32.1 - '@rollup/plugin-commonjs': 14.0.0_rollup@2.32.1 + '@rollup/plugin-commonjs': 16.0.0_rollup@2.32.1 '@rollup/plugin-json': 4.1.0_rollup@2.32.1 es5-ext: 0.10.53 rollup: 2.32.1 @@ -338,7 +338,7 @@ importers: '@babel/core': ^7.10.5 '@babel/plugin-transform-typescript': ^7.10.5 '@rollup/plugin-babel': ^5.1.0 - '@rollup/plugin-commonjs': ^14.0.0 + '@rollup/plugin-commonjs': ^16.0.0 '@rollup/plugin-json': ^4.1.0 '@rollup/pluginutils': ^3.1.0 '@types/resolve': 1.17.1 @@ -506,7 +506,7 @@ importers: rollup: ^2.23.0 source-map-support: ^0.5.19 tosource: ^1.0.0 -lockfileVersion: 5.1 +lockfileVersion: 5.2 packages: /@ava/babel/1.0.1: dependencies: @@ -1659,6 +1659,23 @@ packages: rollup: ^2.3.4 resolution: integrity: sha512-+PSmD9ePwTAeU106i9FRdc+Zb3XUWyW26mo5Atr2mk82hor8+nPwkztEjFo8/B1fJKfaQDg9aM2bzQkjhi7zOw== + /@rollup/plugin-commonjs/16.0.0_rollup@2.32.1: + dependencies: + '@rollup/pluginutils': 3.1.0_rollup@2.32.1 + commondir: 1.0.1 + estree-walker: 2.0.1 + glob: 7.1.6 + is-reference: 1.2.1 + magic-string: 0.25.7 + resolve: 1.18.1 + rollup: 2.32.1 + dev: true + engines: + node: '>= 8.0.0' + peerDependencies: + rollup: ^2.30.0 + resolution: + integrity: sha512-LuNyypCP3msCGVQJ7ki8PqYdpjfEkE/xtFa5DqlF+7IBD0JsfMZ87C58heSwIMint58sAUZbt3ITqOmdQv/dXw== /@rollup/plugin-json/4.1.0_rollup@2.32.1: dependencies: '@rollup/pluginutils': 3.1.0_rollup@2.32.1 @@ -3794,7 +3811,6 @@ packages: resolution: integrity: sha512-1fMXF3YP4pZZVozF8j/ZLfvnR8NSIljt56UhbZ5PeeDmmGHpgpdwQt7ITlGvYaQukCvuBRMLEiKiYC+oeIg4cg== /estree-walker/2.0.1: - dev: false resolution: integrity: sha512-tF0hv+Yi2Ot1cwj9eYHtxC0jB9bmjacjQs6ZBTj82H8JwUywFuc+7E83NWfNMwHXZc11mjfFcVXPe9gEP4B8dg== /esutils/2.0.3: @@ -3965,6 +3981,7 @@ packages: resolution: integrity: sha1-FQStJSMVjKpA20onh8sBQRmU6k8= /fsevents/2.1.3: + dev: true engines: node: ^8.16.0 || ^10.6.0 || >=11.0.0 optional: true @@ -4141,6 +4158,7 @@ packages: /graphql/14.7.0: dependencies: iterall: 1.3.0 + dev: true engines: node: '>= 6.x' resolution: @@ -4746,6 +4764,7 @@ packages: resolution: integrity: sha512-9tZvz7AiR3PEDNGiV9vIouQ/EAcqMXFmkcA1CDFTwOB98OZVDL0PH9glHotf5Ugp6GCOTypfzGWI/OqjWNCRUw== /iterall/1.3.0: + dev: true resolution: integrity: sha512-QZ9qOMdF+QLHxy1QIpUHUU1D5pS2CG2P69LF6L6CPjPYA/XMOmKV3PZpawHoAjHNyB0swdVTRxdYT4tbBbxqwg== /js-string-escape/1.0.1: @@ -6600,6 +6619,7 @@ packages: resolution: integrity: sha512-EEp9NhnUkwY8aif6bxgovPHMoMoNr2FulJziTndpt5H9RdwC47GSGuII9XxpSdzVGM0GWrNPHV6ie1LTNJPaLQ== /rollup/2.32.1: + dev: true engines: node: '>=10.0.0' hasBin: true