Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add importedIdResolutions and dynamicallyImportedIdResolutions to moduleInfo #4354

Merged
merged 1 commit into from Jan 21, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
14 changes: 12 additions & 2 deletions docs/05-plugin-development.md
Expand Up @@ -122,7 +122,7 @@ This hook is called each time a module has been fully parsed by Rollup. See [`th

In contrast to the [`transform`](guide/en/#transform) hook, this hook is never cached and can be used to get information about both cached and other modules, including the final shape of the `meta` property, the `code` and the `ast`.

This hook will wait until all imports are resolved so that the information in `moduleInfo.importedIds` and `moduleInfo.dynamicallyImportedIds` is complete and accurate. Note however that information about importing modules may be incomplete as additional importers could be discovered later. If you need this information, use the [`buildEnd`](guide/en/#buildend) hook.
This hook will wait until all imports are resolved so that the information in `moduleInfo.importedIds`, `moduleInfo.dynamicallyImportedIds`, `moduleInfo.importedIdResolutions`, and `moduleInfo.dynamicallyImportedIdResolutions` is complete and accurate. Note however that information about importing modules may be incomplete as additional importers could be discovered later. If you need this information, use the [`buildEnd`](guide/en/#buildend) hook.

#### `options`

Expand Down Expand Up @@ -677,15 +677,25 @@ type ModuleInfo = {
isExternal: boolean; // for external modules that are referenced but not included in the graph
isIncluded: boolean | null; // is the module included after tree-shaking, `null` if external or not yet available
importedIds: string[]; // the module ids statically imported by this module
importedIdResolutions: ResolvedId[]; // how statically imported ids were resolved, for use with this.load
importers: string[]; // the ids of all modules that statically import this module
dynamicallyImportedIds: string[]; // the module ids imported by this module via dynamic import()
dynamicallyImportedIdResolutions: ResolvedId[]; // how ids imported via dynamic import() were resolved
dynamicImporters: string[]; // the ids of all modules that import this module via dynamic import()
implicitlyLoadedAfterOneOf: string[]; // implicit relationships, declared via this.emitFile
implicitlyLoadedBefore: string[]; // implicit relationships, declared via this.emitFile
hasModuleSideEffects: boolean | 'no-treeshake'; // are imports of this module included if nothing is imported from it
meta: { [plugin: string]: any }; // custom module meta-data
syntheticNamedExports: boolean | string; // final value of synthetic named exports
};

type ResolvedId = {
id: string; // the id of the imported module
external: boolean | 'absolute'; // is this module external, "absolute" means it will not be rendered as relative in the module
moduleSideEffects: boolean | 'no-treeshake'; // are side effects of the module observed, is tree-shaking enabled
syntheticNamedExports: boolean | string; // does the module allow importing non-existing named exports
meta: { [plugin: string]: any }; // custom module meta-data when resolving the module
};
```

During the build, this object represents currently available information about the module. Before the [`buildEnd`](guide/en/#buildend) hook, this information may be incomplete as e.g. the `importedIds` are not yet resolved or additional `importers` are discovered.
Expand All @@ -706,7 +716,7 @@ Loads and parses the module corresponding to the given id, attaching additional

This allows you to inspect the final content of modules before deciding how to resolve them in the [`resolveId`](guide/en/#resolveid) hook and e.g. resolve to a proxy module instead. If the module becomes part of the graph later, there is no additional overhead from using this context function as the module will not be parsed again. The signature allows you to directly pass the return value of [`this.resolve`](guide/en/#thisresolve) to this function as long as it is neither `null` nor external.

The returned promise will resolve once the module has been fully transformed and parsed but before any imports have been resolved. That means that the resulting `ModuleInfo` will have empty `importedIds` and `dynamicallyImportedIds`. This helps to avoid deadlock situations when awaiting `this.load` in a `resolveId` hook. If you are interested in `importedIds` and `dynamicallyImportedIds`, you should implement a `moduleParsed` hook.
The returned promise will resolve once the module has been fully transformed and parsed but before any imports have been resolved. That means that the resulting `ModuleInfo` will have empty `importedIds`, `dynamicallyImportedIds`, `importedIdResolutions` and `dynamicallyImportedIdResolutions`. This helps to avoid deadlock situations when awaiting `this.load` in a `resolveId` hook. If you are interested in `importedIds` and `dynamicallyImportedIds`, you should implement a `moduleParsed` hook.

Note that with regard to the `moduleSideEffects`, `syntheticNamedExports` and `meta` options, the same restrictions apply as for the `resolveId` hook: Their values only have an effect if the module has not been loaded yet. Thus, it is very important to use `this.resolve` first to find out if any plugins want to set special values for these options in their `resolveId` hook, and pass these options on to `this.load` if appropriate. The example below showcases how this can be handled to add a proxy module for modules containing a special code comment:

Expand Down
2 changes: 2 additions & 0 deletions src/ExternalModule.ts
Expand Up @@ -41,6 +41,7 @@ export default class ExternalModule {
this.info = {
ast: null,
code: null,
dynamicallyImportedIdResolutions: EMPTY_ARRAY,
dynamicallyImportedIds: EMPTY_ARRAY,
get dynamicImporters() {
return dynamicImporters.sort();
Expand All @@ -49,6 +50,7 @@ export default class ExternalModule {
id,
implicitlyLoadedAfterOneOf: EMPTY_ARRAY,
implicitlyLoadedBefore: EMPTY_ARRAY,
importedIdResolutions: EMPTY_ARRAY,
importedIds: EMPTY_ARRAY,
get importers() {
return importers.sort();
Expand Down
9 changes: 9 additions & 0 deletions src/Module.ts
Expand Up @@ -38,6 +38,7 @@ import {
NormalizedInputOptions,
PartialNull,
PreserveEntrySignaturesOption,
ResolvedId,
ResolvedIdMap,
RollupError,
RollupLogProps,
Expand Down Expand Up @@ -259,6 +260,11 @@ export default class Module {
this.info = {
ast: null,
code: null,
get dynamicallyImportedIdResolutions() {
return module.dynamicImports
.map(({ argument }) => typeof argument === 'string' && module.resolvedIds[argument])
.filter(Boolean) as ResolvedId[];
},
get dynamicallyImportedIds() {
const dynamicallyImportedIds: string[] = [];
for (const { id } of module.dynamicImports) {
Expand All @@ -279,6 +285,9 @@ export default class Module {
get implicitlyLoadedBefore() {
return Array.from(module.implicitlyLoadedBefore, getId).sort();
},
get importedIdResolutions() {
return Array.from(module.sources, source => module.resolvedIds[source]).filter(Boolean);
},
get importedIds() {
return Array.from(module.sources, source => module.resolvedIds[source]?.id).filter(Boolean);
},
Expand Down
2 changes: 2 additions & 0 deletions src/rollup/types.d.ts
Expand Up @@ -160,11 +160,13 @@ interface ModuleInfo {
ast: AcornNode | null;
code: string | null;
dynamicImporters: readonly string[];
dynamicallyImportedIdResolutions: readonly ResolvedId[];
dynamicallyImportedIds: readonly string[];
hasModuleSideEffects: boolean | 'no-treeshake';
id: string;
implicitlyLoadedAfterOneOf: readonly string[];
implicitlyLoadedBefore: readonly string[];
importedIdResolutions: readonly ResolvedId[];
importedIds: readonly string[];
importers: readonly string[];
isEntry: boolean;
Expand Down
Expand Up @@ -70,12 +70,22 @@ module.exports = {
sourceType: 'module'
},
code: "import { value } from './lib';\nconsole.log(value);\n",
dynamicallyImportedIdResolutions: [],
dynamicallyImportedIds: [],
dynamicImporters: [],
hasModuleSideEffects: true,
id: ID_MAIN,
implicitlyLoadedAfterOneOf: [],
implicitlyLoadedBefore: [],
importedIdResolutions: [
{
external: false,
id: ID_LIB,
meta: {},
moduleSideEffects: true,
syntheticNamedExports: false
}
],
importedIds: [ID_LIB],
importers: [],
isEntry: true,
Expand Down Expand Up @@ -130,12 +140,22 @@ module.exports = {
sourceType: 'module'
},
code: "import { value } from './lib';\nconsole.log(value);\n",
dynamicallyImportedIdResolutions: [],
dynamicallyImportedIds: [],
dynamicImporters: [],
hasModuleSideEffects: true,
id: ID_DEP,
implicitlyLoadedAfterOneOf: [],
implicitlyLoadedBefore: [],
importedIdResolutions: [
{
external: false,
id: ID_LIB,
meta: {},
moduleSideEffects: true,
syntheticNamedExports: false
}
],
importedIds: [ID_LIB],
importers: [],
isEntry: true,
Expand Down
Expand Up @@ -66,12 +66,22 @@ module.exports = {
sourceType: 'module'
},
code: "import { value } from './lib';\nconsole.log(value);\n",
dynamicallyImportedIdResolutions: [],
dynamicallyImportedIds: [],
dynamicImporters: [],
hasModuleSideEffects: true,
id: ID_MAIN,
implicitlyLoadedAfterOneOf: [],
implicitlyLoadedBefore: [],
importedIdResolutions: [
{
external: false,
id: ID_LIB,
meta: {},
moduleSideEffects: true,
syntheticNamedExports: false
}
],
importedIds: [ID_LIB],
importers: [],
isEntry: true,
Expand Down Expand Up @@ -126,12 +136,22 @@ module.exports = {
sourceType: 'module'
},
code: "import { value } from './lib';\nconsole.log(value);\n",
dynamicallyImportedIdResolutions: [],
dynamicallyImportedIds: [],
dynamicImporters: [],
hasModuleSideEffects: true,
id: ID_DEP,
implicitlyLoadedAfterOneOf: [],
implicitlyLoadedBefore: [],
importedIdResolutions: [
{
external: false,
id: ID_LIB,
meta: {},
moduleSideEffects: true,
syntheticNamedExports: false
}
],
importedIds: [ID_LIB],
importers: [],
isEntry: true,
Expand Down
Expand Up @@ -114,12 +114,36 @@ module.exports = {
sourceType: 'module'
},
code: "import { lib1 } from './lib1';\nimport { lib1b } from './lib1b';\nimport { lib2 } from './lib2';\nconsole.log('main1', lib1, lib1b, lib2);\n",
dynamicallyImportedIdResolutions: [],
dynamicallyImportedIds: [],
dynamicImporters: [],
hasModuleSideEffects: true,
id: ID_MAIN1,
implicitlyLoadedAfterOneOf: [],
implicitlyLoadedBefore: [ID_DEP],
importedIdResolutions: [
{
external: false,
id: ID_LIB1,
meta: {},
moduleSideEffects: true,
syntheticNamedExports: false
},
{
external: false,
id: ID_LIB1B,
meta: {},
moduleSideEffects: true,
syntheticNamedExports: false
},
{
external: false,
id: ID_LIB2,
meta: {},
moduleSideEffects: true,
syntheticNamedExports: false
}
],
importedIds: [ID_LIB1, ID_LIB1B, ID_LIB2],
importers: [],
isEntry: true,
Expand Down Expand Up @@ -209,12 +233,36 @@ module.exports = {
sourceType: 'module'
},
code: "import { lib1 } from './lib1';\nimport { lib1b } from './lib1b';\nimport { lib3 } from './lib3';\nconsole.log('main2', lib1, lib1b, lib3);\n",
dynamicallyImportedIdResolutions: [],
dynamicallyImportedIds: [],
dynamicImporters: [],
hasModuleSideEffects: true,
id: ID_MAIN2,
implicitlyLoadedAfterOneOf: [],
implicitlyLoadedBefore: [ID_DEP],
importedIdResolutions: [
{
external: false,
id: ID_LIB1,
meta: {},
moduleSideEffects: true,
syntheticNamedExports: false
},
{
external: false,
id: ID_LIB1B,
meta: {},
moduleSideEffects: true,
syntheticNamedExports: false
},
{
external: false,
id: ID_LIB3,
meta: {},
moduleSideEffects: true,
syntheticNamedExports: false
}
],
importedIds: [ID_LIB1, ID_LIB1B, ID_LIB3],
importers: [],
isEntry: true,
Expand Down Expand Up @@ -303,12 +351,36 @@ module.exports = {
sourceType: 'module'
},
code: "import { lib1 } from './lib1';\nimport { lib2 } from './lib2';\nimport { lib3 } from './lib3';\nconsole.log(lib1, lib2, lib3);\n",
dynamicallyImportedIdResolutions: [],
dynamicallyImportedIds: [],
dynamicImporters: [],
hasModuleSideEffects: true,
id: ID_DEP,
implicitlyLoadedAfterOneOf: [ID_MAIN1, ID_MAIN2],
implicitlyLoadedBefore: [],
importedIdResolutions: [
{
external: false,
id: ID_LIB1,
meta: {},
moduleSideEffects: true,
syntheticNamedExports: false
},
{
external: false,
id: ID_LIB2,
meta: {},
moduleSideEffects: true,
syntheticNamedExports: false
},
{
external: false,
id: ID_LIB3,
meta: {},
moduleSideEffects: true,
syntheticNamedExports: false
}
],
importedIds: [ID_LIB1, ID_LIB2, ID_LIB3],
importers: [],
isEntry: false,
Expand Down
Expand Up @@ -65,12 +65,22 @@ module.exports = {
sourceType: 'module'
},
code: "import { value } from './lib';\nconsole.log(value);\n",
dynamicallyImportedIdResolutions: [],
dynamicallyImportedIds: [],
dynamicImporters: [],
hasModuleSideEffects: true,
id: ID_MAIN,
implicitlyLoadedAfterOneOf: [],
implicitlyLoadedBefore: [ID_DEP],
importedIdResolutions: [
{
external: false,
id: ID_LIB,
meta: {},
moduleSideEffects: true,
syntheticNamedExports: false
}
],
importedIds: [ID_LIB],
importers: [],
isEntry: true,
Expand Down Expand Up @@ -125,12 +135,22 @@ module.exports = {
sourceType: 'module'
},
code: "import { value } from './lib';\nconsole.log(value);\n",
dynamicallyImportedIdResolutions: [],
dynamicallyImportedIds: [],
dynamicImporters: [],
hasModuleSideEffects: true,
id: ID_DEP,
implicitlyLoadedAfterOneOf: [ID_MAIN],
implicitlyLoadedBefore: [],
importedIdResolutions: [
{
external: false,
id: ID_LIB,
meta: {},
moduleSideEffects: true,
syntheticNamedExports: false
}
],
importedIds: [ID_LIB],
importers: [],
isEntry: false,
Expand Down