diff --git a/browser/fs.ts b/browser/fs.ts index 5cc22ebd873..fbd18d02214 100644 --- a/browser/fs.ts +++ b/browser/fs.ts @@ -1,5 +1,10 @@ -const nope = (method: string) => (..._args: any[]): any => { - throw new Error(`Cannot use fs.${method} inside browser`); +const nope = (method: string) => (..._args: any[]): never => { + throw Object.assign( + new Error( + `Cannot access the file system (via "fs.${method}") when using the browser build of Rollup. Make sure you supply a plugin with custom resolveId and load hooks to Rollup.` + ), + { code: 'NO_FS_IN_BROWSER', url: 'https://rollupjs.org/guide/en/#a-simple-example' } + ); }; export const lstatSync = nope('lstatSync'); diff --git a/docs/05-plugin-development.md b/docs/05-plugin-development.md index ead6c2d045d..79d89d714c8 100644 --- a/docs/05-plugin-development.md +++ b/docs/05-plugin-development.md @@ -496,7 +496,8 @@ Returns additional information about the module in question in the form id: string, // the id of the module, for convenience isEntry: boolean, // is this a user- or plugin-defined entry point isExternal: boolean, // for external modules that are not included in the graph - importedIds: string[], // the module ids imported by this module + importedIds: string[], // the module ids statically imported by this module + dynamicallyImportedIds: string[], // the module ids imported by this module via dynamic import() hasModuleSideEffects: boolean // are imports of this module included if nothing is imported from it } ``` diff --git a/src/Chunk.ts b/src/Chunk.ts index d829d6ba0d9..63ffad9f3e7 100644 --- a/src/Chunk.ts +++ b/src/Chunk.ts @@ -706,10 +706,7 @@ export default class Chunk { } const renderedResolution = resolution instanceof Module - ? `'${this.getRelativePath( - (resolution.facadeChunk || resolution.chunk!).id!, - stripKnownJsExtensions - )}'` + ? `'${this.getRelativePath(resolution.facadeChunk!.id!, stripKnownJsExtensions)}'` : resolution instanceof ExternalModule ? `'${ resolution.renormalizeRenderPath diff --git a/src/ModuleLoader.ts b/src/ModuleLoader.ts index 8415b17c78e..be384eceb11 100644 --- a/src/ModuleLoader.ts +++ b/src/ModuleLoader.ts @@ -13,6 +13,7 @@ import { ResolveIdResult, TransformModuleJSON } from './rollup/types'; +import { resolveId } from './utils/defaultPlugin'; import { errBadLoader, errCannotAssignModuleToChunk, @@ -30,7 +31,6 @@ import { readFile } from './utils/fs'; import { isRelative, resolve } from './utils/path'; import { PluginDriver } from './utils/PluginDriver'; import relativeId from './utils/relativeId'; -import { resolveId } from './utils/resolveId'; import { timeEnd, timeStart } from './utils/timers'; import transform from './utils/transform'; diff --git a/src/rollup/types.d.ts b/src/rollup/types.d.ts index 712affcb83a..bcadf429261 100644 --- a/src/rollup/types.d.ts +++ b/src/rollup/types.d.ts @@ -164,6 +164,7 @@ export interface PluginContext extends MinimalPluginContext { getModuleInfo: ( moduleId: string ) => { + dynamicallyImportedIds: string[]; hasModuleSideEffects: boolean; id: string; importedIds: string[]; diff --git a/src/utils/PluginContext.ts b/src/utils/PluginContext.ts index 3d832cb5652..09c94ff3635 100644 --- a/src/utils/PluginContext.ts +++ b/src/utils/PluginContext.ts @@ -127,14 +127,23 @@ export function getPluginContexts( if (foundModule == null) { throw new Error(`Unable to find module ${moduleId}`); } - + const importedIds: string[] = []; + const dynamicallyImportedIds: string[] = []; + if (foundModule instanceof Module) { + for (const source of foundModule.sources) { + importedIds.push(foundModule.resolvedIds[source].id); + } + for (const { resolution } of foundModule.dynamicImports) { + if (resolution instanceof Module || resolution instanceof ExternalModule) { + dynamicallyImportedIds.push(resolution.id); + } + } + } return { + dynamicallyImportedIds, hasModuleSideEffects: foundModule.moduleSideEffects, id: foundModule.id, - importedIds: - foundModule instanceof ExternalModule - ? [] - : Array.from(foundModule.sources).map(id => foundModule.resolvedIds[id].id), + importedIds, isEntry: foundModule instanceof Module && foundModule.isEntryPoint, isExternal: foundModule instanceof ExternalModule }; diff --git a/src/utils/resolveId.ts b/src/utils/defaultPlugin.ts similarity index 84% rename from src/utils/resolveId.ts rename to src/utils/defaultPlugin.ts index 57f5ee7abe6..4fb6e911041 100644 --- a/src/utils/resolveId.ts +++ b/src/utils/defaultPlugin.ts @@ -1,4 +1,3 @@ -import { error } from './error'; import { lstatSync, readdirSync, realpathSync } from './fs'; import { basename, dirname, isAbsolute, resolve } from './path'; import { PluginDriver } from './PluginDriver'; @@ -13,14 +12,6 @@ export async function resolveId( const pluginResult = await pluginDriver.hookFirst('resolveId', [source, importer], null, skip); if (pluginResult != null) return pluginResult; - if (typeof process === 'undefined') { - return error({ - code: 'MISSING_PROCESS', - message: `It looks like you're using Rollup in a non-Node.js environment. This means you must supply a plugin with custom resolveId and load functions`, - url: 'https://rollupjs.org/guide/en/#a-simple-example' - }); - } - // external modules (non-entry modules that start with neither '.' or '/') // are skipped at this stage. if (importer !== undefined && !isAbsolute(source) && source[0] !== '.') return null; diff --git a/test/function/index.js b/test/function/index.js index 4cb614eb7b4..6ae7178b447 100644 --- a/test/function/index.js +++ b/test/function/index.js @@ -3,8 +3,7 @@ const assert = require('assert'); const rollup = require('../../dist/rollup'); const { compareError, compareWarnings, extend, runTestSuiteWithSamples } = require('../utils.js'); -function requireWithContext(code, context) { - const module = { exports: {} }; +function requireWithContext(code, context, module) { const contextWithExports = Object.assign({}, context, { module, exports: module.exports }); const contextKeys = Object.keys(contextWithExports); const contextValues = contextKeys.map(key => contextWithExports[key]); @@ -19,14 +18,20 @@ function requireWithContext(code, context) { } function runCodeSplitTest(codeMap, entryId, configContext) { + const exportsMap = Object.create(null); + const requireFromOutputVia = importer => importee => { const outputId = path.posix.join(path.posix.dirname(importer), importee); + if (outputId in exportsMap) { + return exportsMap[outputId]; + } const code = codeMap[outputId]; if (typeof code !== 'undefined') { - return requireWithContext( + return (exportsMap[outputId] = requireWithContext( code, - Object.assign({ require: requireFromOutputVia(outputId) }, context) - ); + Object.assign({ require: requireFromOutputVia(outputId) }, context), + (exportsMap[outputId] = { exports: {} }) + )); } else { return require(importee); } @@ -35,10 +40,7 @@ function runCodeSplitTest(codeMap, entryId, configContext) { const context = Object.assign({ assert }, configContext); let exports; try { - exports = requireWithContext( - codeMap[entryId], - Object.assign({ require: requireFromOutputVia(entryId) }, context) - ); + exports = requireFromOutputVia(entryId)(entryId); } catch (error) { return { error, exports: error.exports }; } diff --git a/test/function/samples/plugin-module-information/_config.js b/test/function/samples/plugin-module-information/_config.js index 6a9a20b4734..95df5f38c80 100644 --- a/test/function/samples/plugin-module-information/_config.js +++ b/test/function/samples/plugin-module-information/_config.js @@ -15,6 +15,7 @@ module.exports = { plugins: { load(id) { assert.deepStrictEqual(this.getModuleInfo(id), { + dynamicallyImportedIds: [], hasModuleSideEffects: true, id, importedIds: [], @@ -24,15 +25,17 @@ module.exports = { }, renderStart() { rendered = true; - assert.deepStrictEqual(Array.from(this.moduleIds), [ID_MAIN, ID_FOO, ID_NESTED, ID_PATH]); + assert.deepStrictEqual(Array.from(this.moduleIds), [ID_MAIN, ID_FOO, ID_PATH, ID_NESTED]); assert.deepStrictEqual(this.getModuleInfo(ID_MAIN), { + dynamicallyImportedIds: [ID_NESTED, ID_PATH], hasModuleSideEffects: true, id: ID_MAIN, - importedIds: [ID_FOO, ID_NESTED], + importedIds: [ID_FOO], isEntry: true, isExternal: false }); assert.deepStrictEqual(this.getModuleInfo(ID_FOO), { + dynamicallyImportedIds: [], hasModuleSideEffects: true, id: ID_FOO, importedIds: [ID_PATH], @@ -40,6 +43,7 @@ module.exports = { isExternal: false }); assert.deepStrictEqual(this.getModuleInfo(ID_NESTED), { + dynamicallyImportedIds: [], hasModuleSideEffects: true, id: ID_NESTED, importedIds: [ID_FOO], @@ -47,6 +51,7 @@ module.exports = { isExternal: false }); assert.deepStrictEqual(this.getModuleInfo(ID_PATH), { + dynamicallyImportedIds: [], hasModuleSideEffects: true, id: ID_PATH, importedIds: [], diff --git a/test/function/samples/plugin-module-information/main.js b/test/function/samples/plugin-module-information/main.js index 73b23d68a98..8176c87a7c7 100644 --- a/test/function/samples/plugin-module-information/main.js +++ b/test/function/samples/plugin-module-information/main.js @@ -1,4 +1,3 @@ -export {foo} from './foo.js'; -import { nested } from './nested/nested'; - -export {nested}; +export { foo } from './foo.js'; +export const nested = import('./nested/nested'); +export const path = import('path');