Skip to content

Commit

Permalink
Make initial ModuleInfo.meta mutable and maintain object identity (#4328
Browse files Browse the repository at this point in the history
)
  • Loading branch information
lukastaegert committed Jan 4, 2022
1 parent a54b798 commit 2fea0d7
Show file tree
Hide file tree
Showing 6 changed files with 95 additions and 8 deletions.
22 changes: 21 additions & 1 deletion docs/05-plugin-development.md
Expand Up @@ -1055,7 +1055,7 @@ Note the convention that custom options should be added using a property corresp
#### Custom module meta-data
Plugins can annotate modules with custom meta-data which can be accessed by themselves and other plugins via the [`resolveId`](guide/en/#resolveid), [`load`](guide/en/#load), and [`transform`](guide/en/#transform) hooks. This meta-data should always be JSON.stringifyable and will be persisted in the cache e.g. in watch mode.
Plugins can annotate modules with custom meta-data which can be set by themselves and other plugins via the [`resolveId`](guide/en/#resolveid), [`load`](guide/en/#load), and [`transform`](guide/en/#transform) hooks and accessed via [`this.getModuleInfo`](guide/en/#thisgetmoduleinfo), [`this.load`](guide/en/#thisload) and the [`moduleParsed`](guide/en/#moduleparsed) hook. This meta-data should always be JSON.stringifyable and will be persisted in the cache e.g. in watch mode.
```js
function annotatingPlugin() {
Expand Down Expand Up @@ -1087,6 +1087,26 @@ Note the convention that plugins that add or modify data should use a property c
If several plugins add meta-data or meta-data is added in different hooks, then these `meta` objects will be merged shallowly. That means if plugin `first` adds `{meta: {first: {resolved: "first"}}}` in the resolveId hook and `{meta: {first: {loaded: "first"}}}` in the load hook while plugin `second` adds `{meta: {second: {transformed: "second"}}}` in the `transform` hook, then the resulting `meta` object will be `{first: {loaded: "first"}, second: {transformed: "second"}}`. Here the result of the `resolveId` hook will be overwritten by the result of the `load` hook as the plugin was both storing them under its `first` top-level property. The `transform` data of the other plugin on the other hand will be placed next to it.
The `meta` object of a module is created as soon as Rollup starts loading a module and is updated for each lifecycle hook of the module. If you store a reference to this object, you can also update it manually. To access the meta object of a module that has not been loaded yet, you can trigger its creation and loading the module via [`this.load`](guide/en/#thisload):
```js
function plugin() {
return {
name: 'test',
buildStart() {
// trigger loading a module. We could also pass an initial "meta" object
// here, but it would be ignored if the module was already loaded via
// other means
this.load({ id: 'my-id' });
// the module info is now available, we do not need to await this.load
const meta = this.getModuleInfo('my-id').meta;
// we can also modify meta manually now
meta.test = { some: 'data' };
}
};
}
```
#### Direct plugin communication
For any other kind of inter-plugin communication, we recommend the pattern below. Note that `api` will never conflict with any upcoming plugin hooks.
Expand Down
2 changes: 1 addition & 1 deletion src/Module.ts
Expand Up @@ -840,7 +840,7 @@ export default class Module {
this.info.syntheticNamedExports = syntheticNamedExports;
}
if (meta != null) {
this.info.meta = { ...this.info.meta, ...meta };
Object.assign(this.info.meta, meta);
}
}

Expand Down
4 changes: 2 additions & 2 deletions src/ModuleLoader.ts
Expand Up @@ -204,7 +204,7 @@ export class ModuleLoader {
return {
external,
id: resolvedId.id,
meta: resolvedId.meta || EMPTY_OBJECT,
meta: resolvedId.meta || {},
moduleSideEffects:
resolvedId.moduleSideEffects ?? this.hasModuleSideEffects(resolvedId.id, !!external),
syntheticNamedExports: resolvedId.syntheticNamedExports ?? false
Expand Down Expand Up @@ -555,7 +555,7 @@ export class ModuleLoader {
return {
external: true,
id: source,
meta: EMPTY_OBJECT,
meta: {},
moduleSideEffects: this.hasModuleSideEffects(source, true),
syntheticNamedExports: false
};
Expand Down
66 changes: 66 additions & 0 deletions test/function/samples/modify-meta/_config.js
@@ -0,0 +1,66 @@
const assert = require('assert');
const path = require('path');
const ID_MAIN = path.join(__dirname, 'main.js');

let initialMeta;

module.exports = {
description: 'allows to freely modify moduleInfo.meta and maintain object identity',
options: {
plugins: [
{
name: 'first',
buildStart() {
this.load({ id: ID_MAIN });
initialMeta = this.getModuleInfo(ID_MAIN).meta;
initialMeta.buildStart = true;
},
load(id) {
assert.strictEqual(id, ID_MAIN);
const meta = this.getModuleInfo(ID_MAIN).meta;
assert.deepStrictEqual(meta, { buildStart: true }, 'load');
assert.strictEqual(meta, initialMeta);
meta.load1a = true;
return { code: `assert.ok(true);`, meta: { load1b: true } };
},
transform(code, id) {
assert.strictEqual(id, ID_MAIN);
const meta = this.getModuleInfo(ID_MAIN).meta;
assert.deepStrictEqual(
meta,
{ buildStart: true, load1a: true, load1b: true },
'transform'
);
assert.strictEqual(meta, initialMeta);
meta.transform1a = true;
return { code: `assert.ok(true);`, meta: { transform1b: true } };
},
buildEnd(error) {
if (error) {
throw error;
}
const meta = this.getModuleInfo(ID_MAIN).meta;
assert.deepStrictEqual(
meta,
{
buildStart: true,
load1a: true,
load1b: true,
transform1a: true,
transform1b: true,
transform2: true
},
'buildEnd'
);
}
},
{
name: 'second',
transform(code, id) {
assert.strictEqual(id, ID_MAIN);
return { code: `assert.ok(true);`, meta: { transform2: true } };
}
}
]
}
};
1 change: 1 addition & 0 deletions test/function/samples/modify-meta/main.js
@@ -0,0 +1 @@
assert.ok(true);
8 changes: 4 additions & 4 deletions test/incremental/index.js
Expand Up @@ -293,18 +293,17 @@ describe('incremental', () => {
},

load(id) {
assert.deepStrictEqual(this.getModuleInfo(id).meta, { test: { resolved: id } });
return { code: modules[id], meta: { test: { loaded: id } } };
},

transform(code, id) {
transformCalls++;
assert.deepStrictEqual(this.getModuleInfo(id).meta, { test: { loaded: id } });
assert.deepStrictEqual(this.getModuleInfo(id).meta, { test: { loaded: id } }, 'transform');
return { code, meta: { test: { transformed: id } } };
},

moduleParsed({ id, meta }) {
assert.deepStrictEqual(meta, { test: { transformed: id } });
assert.deepStrictEqual(meta, { test: { transformed: id } }, 'moduleParsed');
moduleParsedCalls++;
},

Expand All @@ -314,7 +313,8 @@ describe('incremental', () => {
[
{ id: 'entry', meta: { test: { transformed: 'entry' } } },
{ id: 'foo', meta: { test: { transformed: 'foo' } } }
]
],
'buildEnd'
);
}
};
Expand Down

0 comments on commit 2fea0d7

Please sign in to comment.