Skip to content

Commit 61adedf

Browse files
authored
Add importedIdResolutions to moduleInfo (#4354)
1 parent 2256dcd commit 61adedf

13 files changed

Lines changed: 316 additions & 2 deletions

File tree

docs/05-plugin-development.md

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,7 @@ This hook is called each time a module has been fully parsed by Rollup. See [`th
122122

123123
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`.
124124

125-
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.
125+
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.
126126

127127
#### `options`
128128

@@ -677,15 +677,25 @@ type ModuleInfo = {
677677
isExternal: boolean; // for external modules that are referenced but not included in the graph
678678
isIncluded: boolean | null; // is the module included after tree-shaking, `null` if external or not yet available
679679
importedIds: string[]; // the module ids statically imported by this module
680+
importedIdResolutions: ResolvedId[]; // how statically imported ids were resolved, for use with this.load
680681
importers: string[]; // the ids of all modules that statically import this module
681682
dynamicallyImportedIds: string[]; // the module ids imported by this module via dynamic import()
683+
dynamicallyImportedIdResolutions: ResolvedId[]; // how ids imported via dynamic import() were resolved
682684
dynamicImporters: string[]; // the ids of all modules that import this module via dynamic import()
683685
implicitlyLoadedAfterOneOf: string[]; // implicit relationships, declared via this.emitFile
684686
implicitlyLoadedBefore: string[]; // implicit relationships, declared via this.emitFile
685687
hasModuleSideEffects: boolean | 'no-treeshake'; // are imports of this module included if nothing is imported from it
686688
meta: { [plugin: string]: any }; // custom module meta-data
687689
syntheticNamedExports: boolean | string; // final value of synthetic named exports
688690
};
691+
692+
type ResolvedId = {
693+
id: string; // the id of the imported module
694+
external: boolean | 'absolute'; // is this module external, "absolute" means it will not be rendered as relative in the module
695+
moduleSideEffects: boolean | 'no-treeshake'; // are side effects of the module observed, is tree-shaking enabled
696+
syntheticNamedExports: boolean | string; // does the module allow importing non-existing named exports
697+
meta: { [plugin: string]: any }; // custom module meta-data when resolving the module
698+
};
689699
```
690700
691701
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.
@@ -706,7 +716,7 @@ Loads and parses the module corresponding to the given id, attaching additional
706716
707717
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.
708718
709-
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.
719+
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.
710720
711721
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:
712722

src/ExternalModule.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ export default class ExternalModule {
4141
this.info = {
4242
ast: null,
4343
code: null,
44+
dynamicallyImportedIdResolutions: EMPTY_ARRAY,
4445
dynamicallyImportedIds: EMPTY_ARRAY,
4546
get dynamicImporters() {
4647
return dynamicImporters.sort();
@@ -49,6 +50,7 @@ export default class ExternalModule {
4950
id,
5051
implicitlyLoadedAfterOneOf: EMPTY_ARRAY,
5152
implicitlyLoadedBefore: EMPTY_ARRAY,
53+
importedIdResolutions: EMPTY_ARRAY,
5254
importedIds: EMPTY_ARRAY,
5355
get importers() {
5456
return importers.sort();

src/Module.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ import {
3838
NormalizedInputOptions,
3939
PartialNull,
4040
PreserveEntrySignaturesOption,
41+
ResolvedId,
4142
ResolvedIdMap,
4243
RollupError,
4344
RollupLogProps,
@@ -259,6 +260,11 @@ export default class Module {
259260
this.info = {
260261
ast: null,
261262
code: null,
263+
get dynamicallyImportedIdResolutions() {
264+
return module.dynamicImports
265+
.map(({ argument }) => typeof argument === 'string' && module.resolvedIds[argument])
266+
.filter(Boolean) as ResolvedId[];
267+
},
262268
get dynamicallyImportedIds() {
263269
const dynamicallyImportedIds: string[] = [];
264270
for (const { id } of module.dynamicImports) {
@@ -279,6 +285,9 @@ export default class Module {
279285
get implicitlyLoadedBefore() {
280286
return Array.from(module.implicitlyLoadedBefore, getId).sort();
281287
},
288+
get importedIdResolutions() {
289+
return Array.from(module.sources, source => module.resolvedIds[source]).filter(Boolean);
290+
},
282291
get importedIds() {
283292
return Array.from(module.sources, source => module.resolvedIds[source]?.id).filter(Boolean);
284293
},

src/rollup/types.d.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,11 +160,13 @@ interface ModuleInfo {
160160
ast: AcornNode | null;
161161
code: string | null;
162162
dynamicImporters: readonly string[];
163+
dynamicallyImportedIdResolutions: readonly ResolvedId[];
163164
dynamicallyImportedIds: readonly string[];
164165
hasModuleSideEffects: boolean | 'no-treeshake';
165166
id: string;
166167
implicitlyLoadedAfterOneOf: readonly string[];
167168
implicitlyLoadedBefore: readonly string[];
169+
importedIdResolutions: readonly ResolvedId[];
168170
importedIds: readonly string[];
169171
importers: readonly string[];
170172
isEntry: boolean;

test/chunking-form/samples/implicit-dependencies/implicitly-dependent-emitted-entry/_config.js

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,12 +70,22 @@ module.exports = {
7070
sourceType: 'module'
7171
},
7272
code: "import { value } from './lib';\nconsole.log(value);\n",
73+
dynamicallyImportedIdResolutions: [],
7374
dynamicallyImportedIds: [],
7475
dynamicImporters: [],
7576
hasModuleSideEffects: true,
7677
id: ID_MAIN,
7778
implicitlyLoadedAfterOneOf: [],
7879
implicitlyLoadedBefore: [],
80+
importedIdResolutions: [
81+
{
82+
external: false,
83+
id: ID_LIB,
84+
meta: {},
85+
moduleSideEffects: true,
86+
syntheticNamedExports: false
87+
}
88+
],
7989
importedIds: [ID_LIB],
8090
importers: [],
8191
isEntry: true,
@@ -130,12 +140,22 @@ module.exports = {
130140
sourceType: 'module'
131141
},
132142
code: "import { value } from './lib';\nconsole.log(value);\n",
143+
dynamicallyImportedIdResolutions: [],
133144
dynamicallyImportedIds: [],
134145
dynamicImporters: [],
135146
hasModuleSideEffects: true,
136147
id: ID_DEP,
137148
implicitlyLoadedAfterOneOf: [],
138149
implicitlyLoadedBefore: [],
150+
importedIdResolutions: [
151+
{
152+
external: false,
153+
id: ID_LIB,
154+
meta: {},
155+
moduleSideEffects: true,
156+
syntheticNamedExports: false
157+
}
158+
],
139159
importedIds: [ID_LIB],
140160
importers: [],
141161
isEntry: true,

test/chunking-form/samples/implicit-dependencies/implicitly-dependent-entry/_config.js

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,12 +66,22 @@ module.exports = {
6666
sourceType: 'module'
6767
},
6868
code: "import { value } from './lib';\nconsole.log(value);\n",
69+
dynamicallyImportedIdResolutions: [],
6970
dynamicallyImportedIds: [],
7071
dynamicImporters: [],
7172
hasModuleSideEffects: true,
7273
id: ID_MAIN,
7374
implicitlyLoadedAfterOneOf: [],
7475
implicitlyLoadedBefore: [],
76+
importedIdResolutions: [
77+
{
78+
external: false,
79+
id: ID_LIB,
80+
meta: {},
81+
moduleSideEffects: true,
82+
syntheticNamedExports: false
83+
}
84+
],
7585
importedIds: [ID_LIB],
7686
importers: [],
7787
isEntry: true,
@@ -126,12 +136,22 @@ module.exports = {
126136
sourceType: 'module'
127137
},
128138
code: "import { value } from './lib';\nconsole.log(value);\n",
139+
dynamicallyImportedIdResolutions: [],
129140
dynamicallyImportedIds: [],
130141
dynamicImporters: [],
131142
hasModuleSideEffects: true,
132143
id: ID_DEP,
133144
implicitlyLoadedAfterOneOf: [],
134145
implicitlyLoadedBefore: [],
146+
importedIdResolutions: [
147+
{
148+
external: false,
149+
id: ID_LIB,
150+
meta: {},
151+
moduleSideEffects: true,
152+
syntheticNamedExports: false
153+
}
154+
],
135155
importedIds: [ID_LIB],
136156
importers: [],
137157
isEntry: true,

test/chunking-form/samples/implicit-dependencies/multiple-dependencies/_config.js

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,12 +114,36 @@ module.exports = {
114114
sourceType: 'module'
115115
},
116116
code: "import { lib1 } from './lib1';\nimport { lib1b } from './lib1b';\nimport { lib2 } from './lib2';\nconsole.log('main1', lib1, lib1b, lib2);\n",
117+
dynamicallyImportedIdResolutions: [],
117118
dynamicallyImportedIds: [],
118119
dynamicImporters: [],
119120
hasModuleSideEffects: true,
120121
id: ID_MAIN1,
121122
implicitlyLoadedAfterOneOf: [],
122123
implicitlyLoadedBefore: [ID_DEP],
124+
importedIdResolutions: [
125+
{
126+
external: false,
127+
id: ID_LIB1,
128+
meta: {},
129+
moduleSideEffects: true,
130+
syntheticNamedExports: false
131+
},
132+
{
133+
external: false,
134+
id: ID_LIB1B,
135+
meta: {},
136+
moduleSideEffects: true,
137+
syntheticNamedExports: false
138+
},
139+
{
140+
external: false,
141+
id: ID_LIB2,
142+
meta: {},
143+
moduleSideEffects: true,
144+
syntheticNamedExports: false
145+
}
146+
],
123147
importedIds: [ID_LIB1, ID_LIB1B, ID_LIB2],
124148
importers: [],
125149
isEntry: true,
@@ -209,12 +233,36 @@ module.exports = {
209233
sourceType: 'module'
210234
},
211235
code: "import { lib1 } from './lib1';\nimport { lib1b } from './lib1b';\nimport { lib3 } from './lib3';\nconsole.log('main2', lib1, lib1b, lib3);\n",
236+
dynamicallyImportedIdResolutions: [],
212237
dynamicallyImportedIds: [],
213238
dynamicImporters: [],
214239
hasModuleSideEffects: true,
215240
id: ID_MAIN2,
216241
implicitlyLoadedAfterOneOf: [],
217242
implicitlyLoadedBefore: [ID_DEP],
243+
importedIdResolutions: [
244+
{
245+
external: false,
246+
id: ID_LIB1,
247+
meta: {},
248+
moduleSideEffects: true,
249+
syntheticNamedExports: false
250+
},
251+
{
252+
external: false,
253+
id: ID_LIB1B,
254+
meta: {},
255+
moduleSideEffects: true,
256+
syntheticNamedExports: false
257+
},
258+
{
259+
external: false,
260+
id: ID_LIB3,
261+
meta: {},
262+
moduleSideEffects: true,
263+
syntheticNamedExports: false
264+
}
265+
],
218266
importedIds: [ID_LIB1, ID_LIB1B, ID_LIB3],
219267
importers: [],
220268
isEntry: true,
@@ -303,12 +351,36 @@ module.exports = {
303351
sourceType: 'module'
304352
},
305353
code: "import { lib1 } from './lib1';\nimport { lib2 } from './lib2';\nimport { lib3 } from './lib3';\nconsole.log(lib1, lib2, lib3);\n",
354+
dynamicallyImportedIdResolutions: [],
306355
dynamicallyImportedIds: [],
307356
dynamicImporters: [],
308357
hasModuleSideEffects: true,
309358
id: ID_DEP,
310359
implicitlyLoadedAfterOneOf: [ID_MAIN1, ID_MAIN2],
311360
implicitlyLoadedBefore: [],
361+
importedIdResolutions: [
362+
{
363+
external: false,
364+
id: ID_LIB1,
365+
meta: {},
366+
moduleSideEffects: true,
367+
syntheticNamedExports: false
368+
},
369+
{
370+
external: false,
371+
id: ID_LIB2,
372+
meta: {},
373+
moduleSideEffects: true,
374+
syntheticNamedExports: false
375+
},
376+
{
377+
external: false,
378+
id: ID_LIB3,
379+
meta: {},
380+
moduleSideEffects: true,
381+
syntheticNamedExports: false
382+
}
383+
],
312384
importedIds: [ID_LIB1, ID_LIB2, ID_LIB3],
313385
importers: [],
314386
isEntry: false,

test/chunking-form/samples/implicit-dependencies/single-dependency/_config.js

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,12 +65,22 @@ module.exports = {
6565
sourceType: 'module'
6666
},
6767
code: "import { value } from './lib';\nconsole.log(value);\n",
68+
dynamicallyImportedIdResolutions: [],
6869
dynamicallyImportedIds: [],
6970
dynamicImporters: [],
7071
hasModuleSideEffects: true,
7172
id: ID_MAIN,
7273
implicitlyLoadedAfterOneOf: [],
7374
implicitlyLoadedBefore: [ID_DEP],
75+
importedIdResolutions: [
76+
{
77+
external: false,
78+
id: ID_LIB,
79+
meta: {},
80+
moduleSideEffects: true,
81+
syntheticNamedExports: false
82+
}
83+
],
7484
importedIds: [ID_LIB],
7585
importers: [],
7686
isEntry: true,
@@ -125,12 +135,22 @@ module.exports = {
125135
sourceType: 'module'
126136
},
127137
code: "import { value } from './lib';\nconsole.log(value);\n",
138+
dynamicallyImportedIdResolutions: [],
128139
dynamicallyImportedIds: [],
129140
dynamicImporters: [],
130141
hasModuleSideEffects: true,
131142
id: ID_DEP,
132143
implicitlyLoadedAfterOneOf: [ID_MAIN],
133144
implicitlyLoadedBefore: [],
145+
importedIdResolutions: [
146+
{
147+
external: false,
148+
id: ID_LIB,
149+
meta: {},
150+
moduleSideEffects: true,
151+
syntheticNamedExports: false
152+
}
153+
],
134154
importedIds: [ID_LIB],
135155
importers: [],
136156
isEntry: false,

0 commit comments

Comments
 (0)