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

Per output plugins #3218

Merged
merged 15 commits into from Nov 12, 2019
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
7 changes: 3 additions & 4 deletions cli/run/build.ts
Expand Up @@ -66,10 +66,9 @@ export default function build(
});
}

return outputOptions.reduce(
(prev, output) => prev.then(() => bundle.write(output) as Promise<any>),
Promise.resolve()
).then(() => bundle)
return Promise.all(outputOptions.map(output => bundle.write(output) as Promise<any>)).then(
() => bundle
);
})
.then((bundle: RollupBuild | null) => {
if (!silent) {
Expand Down
1 change: 1 addition & 0 deletions docs/01-command-line-reference.md
Expand Up @@ -66,6 +66,7 @@ export default { // can be an array (for multiple inputs)
format, // required
globals,
name,
plugins,

// advanced output options
assetFileNames,
Expand Down
1 change: 1 addition & 0 deletions docs/02-javascript-api.md
Expand Up @@ -116,6 +116,7 @@ const outputOptions = {
format, // required
globals,
name,
plugins,

// advanced output options
assetFileNames,
Expand Down
59 changes: 56 additions & 3 deletions docs/04-tutorial.md
Expand Up @@ -227,17 +227,70 @@ Run Rollup with `npm run build`. The result should look like this:
```js
'use strict';

const version = "1.0.0";
var version = "1.0.0";

const main = function () {
function main () {
console.log('version ' + version);
};
}

module.exports = main;
```

_Note: Only the data we actually need gets imported – `name` and `devDependencies` and other parts of `package.json` are ignored. That's **tree-shaking** in action._

### Using output plugins

Some plugins can also be applied specifically to some outputs. See [plugin hooks](guide/en/#hooks) for the technical details of what output-specific plugins can do. In a nut-shell, those plugins can only modify code after the main analysis of Rollup has completed. Rollup will warn if an incompatible plugin is used as an output-specific plugin. One possible use-case is minification of bundles to be consumed in a browser.

Let us extend the previous example to provide a minified build together with the non-minified one. To that end, we install `rollup-plugin-terser`:

```console
npm install --save-dev rollup-plugin-terser
```

Edit your `rollup.config.js` file to add a second minified output. As format, we choose `iife`. This format wraps the code so that it can be consumed via a `script` tag in the browser while avoiding unwanted interactions with other code. As we have an export, we need to provide the name of a global variable that will be created by our bundle so that other code can access our export via this variable.

```js
// rollup.config.js
import json from 'rollup-plugin-json';
import {terser} from 'rollup-plugin-terser';

export default {
input: 'src/main.js',
output: [
{
file: 'bundle.js',
format: 'cjs'
},
{
file: 'bundle.min.js',
format: 'iife',
name: 'version',
plugins: [terser()]
}
],
plugins: [ json() ]
};
```

Besides `bundle.js`, Rollup will now create a second file `bundle.min.js`:

```js
var version = (function () {
'use strict';

var version = "1.0.0";

function main () {
console.log('version ' + version);
}

return main;

}());
```


### Code Splitting

To use the code splitting feature, we got back to the original example and modify `src/main.js` to load `src/foo.js` dynamically instead of statically:
Expand Down
77 changes: 51 additions & 26 deletions docs/05-plugin-development.md
Expand Up @@ -72,9 +72,12 @@ In addition to properties defining the identity of your plugin, you may also spe
* `sequential`: If this hook returns a promise, then other hooks of this kind will only be executed once this hook has resolved
* `parallel`: If this hook returns a promise, then other hooks of this kind will not wait for this hook to be resolved

Furthermore, hooks can be run either during the `build` phase of the Rollup build, which is triggered by `rollup.rollup()`, or during the `generate` phase, which is triggered by `bundle.generate()` or `bundle.write()`. Plugins that only use `generate` phase hooks can also be passed in via the output options to `bundle.generate()` or `bundle.write()` and therefore run only for certain outputs.

#### `augmentChunkHash`
Type: `(preRenderedChunk: PreRenderedChunk) => string`<br>
Kind: `sync, sequential`
Kind: `sync, sequential`<br>
Phase: `generate`

Can be used to augment the hash of individual chunks. Called for each Rollup output chunk. Returning a falsy value will not modify the hash.

Expand All @@ -91,31 +94,36 @@ augmentChunkHash(chunkInfo) {

#### `banner`
Type: `string | (() => string)`<br>
Kind: `async, parallel`
Kind: `async, parallel`<br>
Phase: `generate`

Cf. [`output.banner/output.footer`](guide/en/#outputbanneroutputfooter).

#### `buildEnd`
Type: `(error?: Error) => void`<br>
Kind: `async, parallel`
Kind: `async, parallel`<br>
Phase: `build`

Called when rollup has finished bundling, but before `generate` or `write` is called; you can also return a Promise. If an error occurred during the build, it is passed on to this hook.

#### `buildStart`
Type: `(options: InputOptions) => void`<br>
Kind: `async, parallel`
Kind: `async, parallel`<br>
Phase: `build`

Called on each `rollup.rollup` build.
Called on each `rollup.rollup` build. This is the recommended hook to use when you need access to the options passed to `rollup.rollup()` as it will take the transformations by all [`options`](guide/en/#options) hooks into account.

#### `footer`
Type: `string | (() => string)`<br>
Kind: `async, parallel`
Kind: `async, parallel`<br>
Phase: `generate`

Cf. [`output.banner/output.footer`](guide/en/#outputbanneroutputfooter).

#### `generateBundle`
Type: `(options: OutputOptions, bundle: { [fileName: string]: AssetInfo | ChunkInfo }, isWrite: boolean) => void`<br>
Kind: `async, sequential`
Kind: `async, sequential`<br>
Phase: `generate`

Called at the end of `bundle.generate()` or immediately before the files are written in `bundle.write()`. To modify the files after they have been written, use the [`writeBundle`](guide/en/#writebundle) hook. `bundle` provides the full list of files being written or generated along with their details:

Expand Down Expand Up @@ -155,13 +163,15 @@ You can prevent files from being emitted by deleting them from the bundle object

#### `intro`
Type: `string | (() => string)`<br>
Kind: `async, parallel`
Kind: `async, parallel`<br>
Phase: `generate`

Cf. [`output.intro/output.outro`](guide/en/#outputintrooutputoutro).

#### `load`
Type: `(id: string) => string | null | { code: string, map?: string | SourceMap, ast? : ESTree.Program, moduleSideEffects?: boolean | null }`<br>
Kind: `async, first`
Kind: `async, first`<br>
Phase: `build`

Defines a custom loader. Returning `null` defers to other `load` functions (and eventually the default behavior of loading from the file system). To prevent additional parsing overhead in case e.g. this hook already used `this.parse` to generate an AST for some reason, this hook can optionally return a `{ code, ast }` object. The `ast` must be a standard ESTree AST with `start` and `end` properties for each node.

Expand All @@ -171,43 +181,52 @@ You can use [`this.getModuleInfo`](guide/en/#thisgetmoduleinfomoduleid-string--m

#### `options`
Type: `(options: InputOptions) => InputOptions | null`<br>
Kind: `sync, sequential`
Kind: `sync, sequential`<br>
Phase: `build`

Replaces or manipulates the options object passed to `rollup.rollup`. Returning `null` does not replace anything. If you just need to read the options, it is recommended to use the [`buildStart`](guide/en/#buildstart) hook as that hook has access to the options after the transformations from all `options` hooks have been taken into account.

Reads and replaces or manipulates the options object passed to `rollup.rollup`. Returning `null` does not replace anything. This is the only hook that does not have access to most [plugin context](guide/en/#plugin-context) utility functions as it is run before rollup is fully configured.
This is the only hook that does not have access to most [plugin context](guide/en/#plugin-context) utility functions as it is run before rollup is fully configured.

#### `outputOptions`
Type: `(outputOptions: OutputOptions) => OutputOptions | null`<br>
Kind: `sync, sequential`
Kind: `sync, sequential`<br>
Phase: `generate`

Reads and replaces or manipulates the output options object passed to `bundle.generate`. Returning `null` does not replace anything.
Replaces or manipulates the output options object passed to `bundle.generate()` or `bundle.write()`. Returning `null` does not replace anything. If you just need to read the output options, it is recommended to use the [`renderStart`](guide/en/#renderstart) hook as this hook has access to the output options after the transformations from all `outputOptions` hooks have been taken into account.

#### `outro`
Type: `string | (() => string)`<br>
Kind: `async, parallel`
Kind: `async, parallel`<br>
Phase: `generate`

Cf. [`output.intro/output.outro`](guide/en/#outputintrooutputoutro).

#### `renderChunk`
Type: `(code: string, chunk: ChunkInfo, options: OutputOptions) => string | { code: string, map: SourceMap } | null`<br>
Kind: `async, sequential`
Kind: `async, sequential`<br>
Phase: `generate`

Can be used to transform individual chunks. Called for each Rollup output chunk file. Returning `null` will apply no transformations.

#### `renderError`
Type: `(error: Error) => void`<br>
Kind: `async, parallel`
Kind: `async, parallel`<br>
Phase: `generate`

Called when rollup encounters an error during `bundle.generate()` or `bundle.write()`. The error is passed to this hook. To get notified when generation completes successfully, use the `generateBundle` hook.

#### `renderStart`
Type: `() => void`<br>
Kind: `async, parallel`
Type: `(outputOptions: OutputOptions, inputOptions: InputOptions) => void`<br>
Kind: `async, parallel`<br>
Phase: `generate`

Called initially each time `bundle.generate()` or `bundle.write()` is called. To get notified when generation has completed, use the `generateBundle` and `renderError` hooks.
Called initially each time `bundle.generate()` or `bundle.write()` is called. To get notified when generation has completed, use the `generateBundle` and `renderError` hooks. This is the recommended hook to use when you need access to the output options passed to `bundle.generate()` or `bundle.write()` as it will take the transformations by all [`outputOptions`](guide/en/#outputoptions) hooks into account. It also receives the input options passed to `rollup.rollup()` so that plugins that can be used as output plugins, i.e. plugins that only use `generate` phase hooks, can get access to them.

#### `resolveDynamicImport`
Type: `(specifier: string | ESTree.Node, importer: string) => string | false | null | {id: string, external?: boolean}`<br>
Kind: `async, first`
Kind: `async, first`<br>
Phase: `generate`

Defines a custom resolver for dynamic imports. Returning `false` signals that the import should be kept as it is and not be passed to other resolvers thus making it external. Similar to the [`resolveId`](guide/en/#resolveid) hook, you can also return an object to resolve the import to a different id while marking it as external at the same time.

Expand All @@ -222,7 +241,8 @@ Note that the return value of this hook will not be passed to `resolveId` afterw

#### `resolveFileUrl`
Type: `({chunkId: string, fileName: string, format: string, moduleId: string, referenceId: string, relativePath: string}) => string | null`<br>
Kind: `sync, first`
Kind: `sync, first`<br>
Phase: `generate`

Allows to customize how Rollup resolves URLs of files that were emitted by plugins via `this.emitAsset` or `this.emitChunk`. By default, Rollup will generate code for `import.meta.ROLLUP_ASSET_URL_assetReferenceId` and `import.meta.ROLLUP_CHUNK_URL_chunkReferenceId` that should correctly generate absolute URLs of emitted files independent of the output format and the host system where the code is deployed.

Expand All @@ -249,7 +269,8 @@ resolveFileUrl({fileName}) {

#### `resolveId`
Type: `(source: string, importer: string) => string | false | null | {id: string, external?: boolean, moduleSideEffects?: boolean | null}`<br>
Kind: `async, first`
Kind: `async, first`<br>
Phase: `build`

Defines a custom resolver. A resolver can be useful for e.g. locating third-party dependencies. Returning `null` defers to other `resolveId` functions and eventually the default resolution behavior; returning `false` signals that `source` should be treated as an external module and not included in the bundle. If this happens for a relative import, the id will be renormalized the same way as when the `external` option is used.

Expand All @@ -270,7 +291,8 @@ If `false` is returned for `moduleSideEffects` in the first hook that resolves a

#### `resolveImportMeta`
Type: `(property: string | null, {chunkId: string, moduleId: string, format: string}) => string | null`<br>
Kind: `sync, first`
Kind: `sync, first`<br>
Phase: `generate`

Allows to customize how Rollup handles `import.meta` and `import.meta.someProperty`, in particular `import.meta.url`. In ES modules, `import.meta` is an object and `import.meta.url` contains the URL of the current module, e.g. `http://server.net/bundle.js` for browsers or `file:///path/to/bundle.js` in Node.

Expand All @@ -292,7 +314,8 @@ Note that since this hook has access to the filename of the current chunk, its r

#### `transform`
Type: `(code: string, id: string) => string | null | { code: string, map?: string | SourceMap, ast? : ESTree.Program, moduleSideEffects?: boolean | null }`<br>
Kind: `async, sequential`
Kind: `async, sequential`<br>
Phase: `build`

Can be used to transform individual modules. To prevent additional parsing overhead in case e.g. this hook already used `this.parse` to generate an AST for some reason, this hook can optionally return a `{ code, ast }` object. The `ast` must be a standard ESTree AST with `start` and `end` properties for each node.

Expand All @@ -304,13 +327,15 @@ You can use [`this.getModuleInfo`](guide/en/#thisgetmoduleinfomoduleid-string--m

#### `watchChange`
Type: `(id: string) => void`<br>
Kind: `sync, sequential`
Kind: `sync, sequential`<br>
Phase: `build` (can also be triggered during `generate` but cannot be used by output plugins)

Notifies a plugin whenever rollup has detected a change to a monitored file in `--watch` mode.

#### `writeBundle`
Type: `( bundle: { [fileName: string]: AssetInfo | ChunkInfo }) => void`<br>
Kind: `async, parallel`
Kind: `async, parallel`<br>
Phase: `generate`

Called only at the end of `bundle.write()` once all files have been written. Similar to the [`generateBundle`](guide/en/#generatebundle) hook, `bundle` provides the full list of files being written along with their details.

Expand Down
37 changes: 35 additions & 2 deletions docs/999-big-list-of-options.md
Expand Up @@ -226,6 +226,35 @@ this.a.b.c = ...
*/
```

#### output.plugins
Type: `OutputPlugin | (OutputPlugin | void)[]`

Adds a plugin just to this output. See [Using output plugins](guide/en/#using-output-plugins) for more information on how to use output-specific plugins and [Plugins](guide/en/#plugin-development) on how to write your own. For plugins imported from packages, remember to call the imported plugin function (i.e. `commonjs()`, not just `commonjs`). Falsy plugins will be ignored, which can be used to easily activate or deactivate plugins.

Not every plugin can be used here. `output.plugins` is limited to plugins that only use hooks that run during `bundle.generate()` or `bundle.write()`, i.e. after Rollup's main analysis is complete. If you are a plugin author, see [Plugin hooks](guide/en/#hooks) to find out which hooks can be used.

The following will add minifaction to one of the outputs:

```js
// rollup.config.js
import {terser} from 'rollup-plugin-terser';

export default {
input: 'main.js',
output: [
{
file: 'bundle.js',
format: 'esm'
},
{
file: 'bundle.min.js',
format: 'esm',
plugins: [terser()]
}
]
};
```

#### plugins
Type: `Plugin | (Plugin | void)[]`

Expand All @@ -239,12 +268,16 @@ import commonjs from 'rollup-plugin-commonjs';
const isProduction = process.env.NODE_ENV === 'production';

export default (async () => ({
entry: 'main.js',
input: 'main.js',
plugins: [
resolve(),
commonjs(),
isProduction && (await import('rollup-plugin-terser')).terser()
]
],
output: {
file: 'bundle.js',
format: 'cjs'
}
}))();
```

Expand Down