diff --git a/.lintstagedrc b/.lintstagedrc
index a7b8a40dd73..c2078e45c9a 100644
--- a/.lintstagedrc
+++ b/.lintstagedrc
@@ -3,7 +3,7 @@
"prettier --write",
"tslint --project . --fix"
],
- "test/**/*.ts": [
+ "test/typescript/**/*.ts": [
"prettier --write",
"tslint --project test/typescript --fix"
],
diff --git a/docs/01-command-line-reference.md b/docs/01-command-line-reference.md
index 2a5a6819746..057b6e8cdc0 100755
--- a/docs/01-command-line-reference.md
+++ b/docs/01-command-line-reference.md
@@ -35,11 +35,8 @@ export default { // can be an array (for multiple inputs)
// advanced input options
cache,
- inlineDynamicImports,
- manualChunks,
onwarn,
preserveEntrySignatures,
- preserveModules,
strictDeprecations,
// danger zone
@@ -73,11 +70,14 @@ export default { // can be an array (for multiple inputs)
extend,
footer,
hoistTransitiveImports,
+ inlineDynamicImports,
interop,
intro,
+ manualChunks,
minifyInternalExports,
outro,
paths,
+ preserveModules,
sourcemap,
sourcemapExcludeSources,
sourcemapFile,
diff --git a/docs/02-javascript-api.md b/docs/02-javascript-api.md
index cadcae07379..ed03f0a12aa 100755
--- a/docs/02-javascript-api.md
+++ b/docs/02-javascript-api.md
@@ -83,11 +83,8 @@ const inputOptions = {
// advanced input options
cache,
- inlineDynamicImports,
- manualChunks,
onwarn,
preserveEntrySignatures,
- preserveModules,
strictDeprecations,
// danger zone
@@ -129,11 +126,14 @@ const outputOptions = {
externalLiveBindings,
footer,
hoistTransitiveImports,
+ inlineDynamicImports,
interop,
intro,
+ manualChunks,
minifyInternalExports,
outro,
paths,
+ preserveModules,
sourcemap,
sourcemapExcludeSources,
sourcemapFile,
diff --git a/docs/04-tutorial.md b/docs/04-tutorial.md
index 9be6fbed265..7829cf3315e 100755
--- a/docs/04-tutorial.md
+++ b/docs/04-tutorial.md
@@ -282,7 +282,7 @@ var version=function(){"use strict";var n="1.0.0";return function(){console.log(
### Code Splitting
-For code splitting, there are cases where Rollup splits code into chunks automatically, like dynamic loading or multiple entry points, and there is a way to explicitly tell Rollup which modules to split into separate chunks via the [`manualChunks`](guide/en/#manualchunks) option.
+For code splitting, there are cases where Rollup splits code into chunks automatically, like dynamic loading or multiple entry points, and there is a way to explicitly tell Rollup which modules to split into separate chunks via the [`output.manualChunks`](guide/en/#outputmanualchunks) option.
To use the code splitting feature to achieve the lazy dynamic loading (where some imported module(s) is only loaded after executing a function), we go back to the original example and modify `src/main.js` to load `src/foo.js` dynamically instead of statically:
diff --git a/docs/06-faqs.md b/docs/06-faqs.md
index 3fcb532f70a..fa902b4afa0 100755
--- a/docs/06-faqs.md
+++ b/docs/06-faqs.md
@@ -61,7 +61,7 @@ With this optimization, a JavaScript engine will discover all transitive depende
2. Load and parse `other-entry.js` and `external`. The import of `other-entry.js` is already loaded and parsed.
3. Execute `main.js`.
-There may be situations where this optimization is not desired, in which case you can turn it off via the [`output.hoistTransitiveImports`](guide/en/#outputhoisttransitiveimports) option. This optimization is also never applied when using the [`preserveModules`](guide/en/#preservemodules) option.
+There may be situations where this optimization is not desired, in which case you can turn it off via the [`output.hoistTransitiveImports`](guide/en/#outputhoisttransitiveimports) option. This optimization is also never applied when using the [`output.preserveModules`](guide/en/#outputpreservemodules) option.
#### How do I add polyfills to a Rollup bundle?
@@ -94,7 +94,7 @@ For most code this is not a problem, because Rollup can guarantee:
This is however a problem for polyfills, as those usually need to be executed first but it is usually not desired to place an import of the polyfill in every single module. Luckily, this is not needed:
1. If there are no external dependencies that depend on the polyfill, it is enough to add an import of the polyfill as first statement to each static entry point.
-2. Otherwise, additionally making the polyfill a separate entry or [manual chunk](guide/en/#manualchunks) will always make sure it is executed first.
+2. Otherwise, additionally making the polyfill a separate entry or [manual chunk](guide/en/#outputmanualchunks) will always make sure it is executed first.
#### Is Rollup meant for building libraries or applications?
diff --git a/docs/999-big-list-of-options.md b/docs/999-big-list-of-options.md
index 58270b8758f..52870464e0d 100755
--- a/docs/999-big-list-of-options.md
+++ b/docs/999-big-list-of-options.md
@@ -316,92 +316,6 @@ buildWithCache()
})
```
-#### inlineDynamicImports
-Type: `boolean`
-CLI: `--inlineDynamicImports`/`--no-inlineDynamicImports`
-Default: `false`
-
-This will inline dynamic imports instead of creating new chunks to create a single bundle. Only possible if a single input is provided.
-
-#### manualChunks
-Type: `{ [chunkAlias: string]: string[] } | ((id: string, {getModuleInfo, getModuleIds}) => string | void)`
-
-Allows the creation of custom shared common chunks. When using the object form, each property represents a chunk that contains the listed modules and all their dependencies if they are part of the module graph unless they are already in another manual chunk. The name of the chunk will be determined by the property key.
-
-Note that it is not necessary for the listed modules themselves to be be part of the module graph, which is useful if you are working with `@rollup/plugin-node-resolve` and use deep imports from packages. For instance
-
-```
-manualChunks: {
- lodash: ['lodash']
-}
-```
-
-will put all lodash modules into a manual chunk even if you are only using imports of the form `import get from 'lodash/get'`.
-
-When using the function form, each resolved module id will be passed to the function. If a string is returned, the module and all its dependency will be added to the manual chunk with the given name. For instance this will create a `vendor` chunk containing all dependencies inside `node_modules`:
-
-```javascript
-manualChunks(id) {
- if (id.includes('node_modules')) {
- return 'vendor';
- }
-}
-```
-
-Be aware that manual chunks can change the behaviour of the application if side-effects are triggered before the corresponding modules are actually used.
-
-When using the function form, `manualChunks` will be passed an object as second parameter containing the functions `getModuleInfo` and `getModuleIds` that work the same way as [`this.getModuleInfo`](guide/en/#thisgetmoduleinfomoduleid-string--moduleinfo) and [`this.getModuleIds`](guide/en/#thisgetmoduleids--iterableiteratorstring) on the plugin context.
-
-This can be used to dynamically determine into which manual chunk a module should be placed depending on its position in the module graph. For instance consider a scenario where you have a set of components, each of which dynamically imports a set of translated strings, i.e.
-
-```js
-// Inside the "foo" component
-
-function getTranslatedStrings(currentLanguage) {
- switch (currentLanguage) {
- case 'en': return import('./foo.strings.en.js');
- case 'de': return import('./foo.strings.de.js');
- // ...
- }
-}
-```
-
-If a lot of such components are used together, this will result in a lot of dynamic imports of very small chunks: Even though we known that all language files of the same language that are imported by the same chunk will always be used together, Rollup does not have this information.
-
-The following code will merge all files of the same language that are only used by a single entry point:
-
-```js
-manualChunks(id, { getModuleInfo }) {
- const match = /.*\.strings\.(\w+)\.js/.exec(id);
- if (match) {
- const language = match[1]; // e.g. "en"
- const dependentEntryPoints = [];
-
- // we use a Set here so we handle each module at most once. This
- // prevents infinite loops in case of circular dependencies
- const idsToHandle = new Set(getModuleInfo(id).dynamicImporters);
-
- for (const moduleId of idsToHandle) {
- const { isEntry, dynamicImporters, importers } = getModuleInfo(moduleId);
- if (isEntry || dynamicImporters.length > 0) dependentEntryPoints.push(moduleId);
-
- // The Set iterator is intelligent enough to iterate over elements that
- // are added during iteration
- for (const importerId of importers) idsToHandle.add(importerId);
- }
-
- // If there is a unique entry, we put it into into a chunk based on the entry name
- if (dependentEntryPoints.length === 1) {
- return `${dependentEntryPoints[0].split('/').slice(-1)[0].split('.')[0]}.strings.${language}`;
- }
- // For multiple entries, we put it into a "shared" chunk
- if (dependentEntryPoints.length > 1) {
- return `shared.strings.${language}`;
- }
- }
-}
-```
-
#### onwarn
Type: `(warning: RollupWarning, defaultHandler: (warning: string | RollupWarning) => void) => void;`
@@ -485,7 +399,7 @@ Default: `"[name]-[hash].js"`
The pattern to use for naming shared chunks created when code-splitting. Pattern supports the following placeholders:
* `[format]`: The rendering format defined in the output options, e.g. `es` or `cjs`.
* `[hash]`: A hash based on the content of the chunk and the content of all its dependencies.
- * `[name]`: The name of the chunk. This can be explicitly set via the [`manualChunks`](guide/en/#manualchunks) option or when the chunk is created by a plugin via [`this.emitFile`](guide/en/#thisemitfileemittedfile-emittedchunk--emittedasset--string). Otherwise it will be derived from the chunk contents.
+ * `[name]`: The name of the chunk. This can be explicitly set via the [`output.manualChunks`](guide/en/#outputmanualchunks) option or when the chunk is created by a plugin via [`this.emitFile`](guide/en/#thisemitfileemittedfile-emittedchunk--emittedasset--string). Otherwise it will be derived from the chunk contents.
Forward slashes `/` can be used to place files in sub-directories. See also [`output.assetFileNames`](guide/en/#outputassetfilenames), [`output.entryFileNames`](guide/en/#outputentryfilenames).
@@ -508,7 +422,7 @@ The pattern to use for chunks created from entry points. Pattern supports the fo
Forward slashes `/` can be used to place files in sub-directories. See also [`output.assetFileNames`](guide/en/#outputassetfilenames), [`output.chunkFileNames`](guide/en/#outputchunkfilenames).
-This pattern will also be used when using the [`preserveModules`](guide/en/#preservemodules) option. Here there is a different set of placeholders available, though:
+This pattern will also be used when using the [`output.preserveModules`](guide/en/#outputpreservemodules) option. Here there is a different set of placeholders available, though:
* `[format]`: The rendering format defined in the output options.
* `[name]`: The file name (without extension) of the file.
* `[ext]`: The extension of the file.
@@ -526,7 +440,14 @@ Type: `boolean`
CLI: `--hoistTransitiveImports`/`--no-hoistTransitiveImports`
Default: `true`
-By default when creating multiple chunks, transitive imports of entry chunks will be added as empty imports to the entry chunks. See ["Why do additional imports turn up in my entry chunks when code-splitting?"](guide/en/#why-do-additional-imports-turn-up-in-my-entry-chunks-when-code-splitting) for details and background. Setting this option to `false` will disable this behaviour. This option is ignored when using the [`preserveModules`](guide/en/#preservemodules) option as here, imports will never be hoisted.
+By default when creating multiple chunks, transitive imports of entry chunks will be added as empty imports to the entry chunks. See ["Why do additional imports turn up in my entry chunks when code-splitting?"](guide/en/#why-do-additional-imports-turn-up-in-my-entry-chunks-when-code-splitting) for details and background. Setting this option to `false` will disable this behaviour. This option is ignored when using the [`output.preserveModules`](guide/en/#outputpreservemodules) option as here, imports will never be hoisted.
+
+#### output.inlineDynamicImports
+Type: `boolean`
+CLI: `--inlineDynamicImports`/`--no-inlineDynamicImports`
+Default: `false`
+
+This will inline dynamic imports instead of creating new chunks to create a single bundle. Only possible if a single input is provided. Note that this will change the execution order: A module that is only imported dynamically will be executed immediately if the dynamic import is inlined.
#### output.interop
Type: `boolean`
@@ -551,6 +472,85 @@ export default {
};
```
+#### output.manualChunks
+Type: `{ [chunkAlias: string]: string[] } | ((id: string, {getModuleInfo, getModuleIds}) => string | void)`
+
+Allows the creation of custom shared common chunks. When using the object form, each property represents a chunk that contains the listed modules and all their dependencies if they are part of the module graph unless they are already in another manual chunk. The name of the chunk will be determined by the property key.
+
+Note that it is not necessary for the listed modules themselves to be be part of the module graph, which is useful if you are working with `@rollup/plugin-node-resolve` and use deep imports from packages. For instance
+
+```
+manualChunks: {
+ lodash: ['lodash']
+}
+```
+
+will put all lodash modules into a manual chunk even if you are only using imports of the form `import get from 'lodash/get'`.
+
+When using the function form, each resolved module id will be passed to the function. If a string is returned, the module and all its dependency will be added to the manual chunk with the given name. For instance this will create a `vendor` chunk containing all dependencies inside `node_modules`:
+
+```javascript
+manualChunks(id) {
+ if (id.includes('node_modules')) {
+ return 'vendor';
+ }
+}
+```
+
+Be aware that manual chunks can change the behaviour of the application if side-effects are triggered before the corresponding modules are actually used.
+
+When using the function form, `manualChunks` will be passed an object as second parameter containing the functions `getModuleInfo` and `getModuleIds` that work the same way as [`this.getModuleInfo`](guide/en/#thisgetmoduleinfomoduleid-string--moduleinfo) and [`this.getModuleIds`](guide/en/#thisgetmoduleids--iterableiteratorstring) on the plugin context.
+
+This can be used to dynamically determine into which manual chunk a module should be placed depending on its position in the module graph. For instance consider a scenario where you have a set of components, each of which dynamically imports a set of translated strings, i.e.
+
+```js
+// Inside the "foo" component
+
+function getTranslatedStrings(currentLanguage) {
+ switch (currentLanguage) {
+ case 'en': return import('./foo.strings.en.js');
+ case 'de': return import('./foo.strings.de.js');
+ // ...
+ }
+}
+```
+
+If a lot of such components are used together, this will result in a lot of dynamic imports of very small chunks: Even though we known that all language files of the same language that are imported by the same chunk will always be used together, Rollup does not have this information.
+
+The following code will merge all files of the same language that are only used by a single entry point:
+
+```js
+manualChunks(id, { getModuleInfo }) {
+ const match = /.*\.strings\.(\w+)\.js/.exec(id);
+ if (match) {
+ const language = match[1]; // e.g. "en"
+ const dependentEntryPoints = [];
+
+ // we use a Set here so we handle each module at most once. This
+ // prevents infinite loops in case of circular dependencies
+ const idsToHandle = new Set(getModuleInfo(id).dynamicImporters);
+
+ for (const moduleId of idsToHandle) {
+ const { isEntry, dynamicImporters, importers } = getModuleInfo(moduleId);
+ if (isEntry || dynamicImporters.length > 0) dependentEntryPoints.push(moduleId);
+
+ // The Set iterator is intelligent enough to iterate over elements that
+ // are added during iteration
+ for (const importerId of importers) idsToHandle.add(importerId);
+ }
+
+ // If there is a unique entry, we put it into into a chunk based on the entry name
+ if (dependentEntryPoints.length === 1) {
+ return `${dependentEntryPoints[0].split('/').slice(-1)[0].split('.')[0]}.strings.${language}`;
+ }
+ // For multiple entries, we put it into a "shared" chunk
+ if (dependentEntryPoints.length > 1) {
+ return `shared.strings.${language}`;
+ }
+ }
+}
+```
+
#### output.minifyInternalExports
Type: `boolean`
CLI: `--minifyInternalExports`/`--no-minifyInternalExports`
@@ -647,6 +647,54 @@ define(['https://d3js.org/d3.v4.min'], function (d3) {
});
```
+#### output.preserveModules
+Type: `boolean`
+CLI: `--preserveModules`/`--no-preserveModules`
+Default: `false`
+
+Instead of creating as few chunks as possible, this mode will create separate chunks for all modules using the original module names as file names. Requires the [`output.dir`](guide/en/#outputdir) option. Tree-shaking will still be applied, suppressing files that are not used by the provided entry points or do not have side-effects when executed. This mode can be used to transform a file structure to a different module format.
+
+Note that when transforming to `cjs` or `amd` format, each file will by default be treated as an entry point with [`output.exports`](guide/en/#outputexports) set to `auto`. This means that e.g. for `cjs`, a file that only contains a default export will be rendered as
+
+```js
+// input main.js
+export default 42;
+
+// output main.js
+'use strict';
+
+var main = 42;
+
+module.exports = main;
+```
+
+assigning the value directly to `module.exports`. If someone imports this file, they will get access to the default export via
+
+```js
+const main = require('./main.js');
+console.log(main); // 42
+```
+
+As with regular entry points, files that mix default and named exports will produce warnings. You can avoid the warnings by forcing all files to use named export mode via `output.exports: "named"`. In that case, the default export needs to be accessed via the `.default` property of the export:
+
+```js
+// input main.js
+export default 42;
+
+// output main.js
+'use strict';
+
+Object.defineProperty(exports, '__esModule', { value: true });
+
+var main = 42;
+
+exports.default = main;
+
+// consuming file
+const main = require('./main.js');
+console.log(main.default); // 42
+```
+
#### output.sourcemap
Type: `boolean | 'inline' | 'hidden'`
CLI: `-m`/`--sourcemap`/`--no-sourcemap`
@@ -769,55 +817,6 @@ console.log(shared);
At the moment, the only way to override this setting for individual entry chunks is to use the plugin API and emit those chunks via [`this.emitFile`](guide/en/#thisemitfileemittedfile-emittedchunk--emittedasset--string) instead of using the [`input`](guide/en/#input) option.
-#### preserveModules
-Type: `boolean`
-CLI: `--preserveModules`/`--no-preserveModules`
-Default: `false`
-
-Instead of creating as few chunks as possible, this mode will create separate chunks for all modules using the original module names as file names. Requires the [`output.dir`](guide/en/#outputdir) option. Tree-shaking will still be applied, suppressing files that are not used by the provided entry points or do not have side-effects when executed. This mode can be used to transform a file structure to a different module format.
-
-Note that when transforming to `cjs` or `amd` format, each file will by default be treated as an entry point with [`output.exports`](guide/en/#outputexports) set to `auto`. This means that e.g. for `cjs`, a file that only contains a default export will be rendered as
-
-```js
-// input main.js
-export default 42;
-
-// output main.js
-'use strict';
-
-var main = 42;
-
-module.exports = main;
-```
-
-assigning the value directly to `module.exports`. If someone imports this file, they will get access to the default export via
-
-```js
-const main = require('./main.js');
-console.log(main); // 42
-```
-
-As with regular entry points, files that mix default and named exports will produce warnings. You can avoid the warnings by forcing all files to use named export mode via `output.exports: "named"`. In that case, the default export needs to be accessed via the `.default` property of the export:
-
-```js
-// input main.js
-export default 42;
-
-// output main.js
-'use strict';
-
-Object.defineProperty(exports, '__esModule', { value: true });
-
-var main = 42;
-
-exports.default = main;
-
-// consuming file
-const main = require('./main.js');
-console.log(main.default); // 42
-```
-
-
#### strictDeprecations
Type: `boolean`
CLI: `--strictDeprecations`/`--no-strictDeprecations`
@@ -1363,6 +1362,23 @@ Whether to skip the `bundle.write()` step when a rebuild is triggered.
☢️ These options have been deprecated and may be removed in a future Rollup version.
+#### inlineDynamicImports
+_Use the [`output.inlineDynamicImports`](guide/en/#outputinlinedynamicimports) output option instead, which has the same signature._
+
+#### manualChunks
+_Use the [`output.manualChunks`](guide/en/#outputmanualchunks) output option instead, which has the same signature._
+
+#### preserveModules
+_Use the [`output.preserveModules`](guide/en/#outputpreservemodules) output option instead, which has the same signature._
+
+#### output.dynamicImportFunction
+_Use the [`renderDynamicImport`](guide/en/#renderdynamicimport) plugin hook instead._
+Type: `string`
+CLI: `--dynamicImportFunction `
+Default: `import`
+
+This will rename the dynamic import function to the chosen name when outputting ES bundles. This is useful for generating code that uses a dynamic import polyfill such as [this one](https://github.com/uupaa/dynamic-import-polyfill).
+
#### treeshake.pureExternalModules
_Use [`treeshake.moduleSideEffects: 'no-external'`](guide/en/#treeshake) instead._
Type: `boolean | string[] | (id: string) => boolean | null`
@@ -1391,11 +1407,3 @@ console.log(42);
```
You can also supply a list of external ids to be considered pure or a function that is called whenever an external import could be removed.
-
-#### output.dynamicImportFunction
-_Use the [`renderDynamicImport`](guide/en/#renderdynamicimport) plugin hook instead._
-Type: `string`
-CLI: `--dynamicImportFunction `
-Default: `import`
-
-This will rename the dynamic import function to the chosen name when outputting ES bundles. This is useful for generating code that uses a dynamic import polyfill such as [this one](https://github.com/uupaa/dynamic-import-polyfill).
diff --git a/rollup.config.js b/rollup.config.js
index 28445f9c021..3ea255a09c2 100644
--- a/rollup.config.js
+++ b/rollup.config.js
@@ -99,7 +99,8 @@ export default command => {
],
treeshake,
manualChunks: { rollup: ['src/node-entry.ts'] },
- strictDeprecations: true,
+ // TODO set this to `true` again once manualChunks has been moved to the output
+ strictDeprecations: false,
output: {
banner,
chunkFileNames: 'shared/[name].js',
diff --git a/src/Bundle.ts b/src/Bundle.ts
index 162601cb6cf..d66eace0925 100644
--- a/src/Bundle.ts
+++ b/src/Bundle.ts
@@ -1,5 +1,9 @@
import Chunk from './Chunk';
+import ExternalModule from './ExternalModule';
+import Graph from './Graph';
+import Module from './Module';
import {
+ GetManualChunk,
NormalizedInputOptions,
NormalizedOutputOptions,
OutputBundle,
@@ -7,54 +11,54 @@ import {
OutputChunk
} from './rollup/types';
import { Addons, createAddons } from './utils/addons';
+import { getChunkAssignments } from './utils/chunkAssignment';
import commondir from './utils/commondir';
-import { error, warnDeprecation } from './utils/error';
+import { errCannotAssignModuleToChunk, error, warnDeprecation } from './utils/error';
+import { sortByExecutionOrder } from './utils/executionOrder';
import { FILE_PLACEHOLDER } from './utils/FileEmitter';
import { basename, isAbsolute } from './utils/path';
import { PluginDriver } from './utils/PluginDriver';
import { timeEnd, timeStart } from './utils/timers';
export default class Bundle {
+ private facadeChunkByModule = new Map();
+
constructor(
private readonly outputOptions: NormalizedOutputOptions,
private readonly unsetOptions: Set,
private readonly inputOptions: NormalizedInputOptions,
private readonly pluginDriver: PluginDriver,
- private readonly chunks: Chunk[]
+ private readonly graph: Graph
) {}
async generate(isWrite: boolean): Promise {
timeStart('GENERATE', 1);
- const inputBase = commondir(getAbsoluteEntryModulePaths(this.chunks));
const outputBundle: OutputBundleWithPlaceholders = Object.create(null);
- this.pluginDriver.setOutputBundle(outputBundle, this.outputOptions.assetFileNames);
+ this.pluginDriver.setOutputBundle(
+ outputBundle,
+ this.outputOptions.assetFileNames,
+ this.facadeChunkByModule
+ );
try {
await this.pluginDriver.hookParallel('renderStart', [this.outputOptions, this.inputOptions]);
- if (this.chunks.length > 1) {
+
+ timeStart('generate chunks', 2);
+ const chunks = await this.generateChunks();
+ if (chunks.length > 1) {
validateOptionsForMultiChunkOutput(this.outputOptions);
}
+ const inputBase = commondir(getAbsoluteEntryModulePaths(chunks));
+ timeEnd('generate chunks', 2);
+ timeStart('render modules', 2);
+
+ // We need to create addons before prerender because at the moment, there
+ // can be no async code between prerender and render due to internal state
const addons = await createAddons(this.outputOptions, this.pluginDriver);
- for (const chunk of this.chunks) {
- chunk.generateExports(this.outputOptions);
- }
- for (const chunk of this.chunks) {
- chunk.preRender(this.outputOptions, inputBase, this.pluginDriver);
- }
- this.assignChunkIds(inputBase, addons, outputBundle);
- assignChunksToBundle(this.chunks, outputBundle);
-
- await Promise.all(
- this.chunks.map(chunk => {
- const outputChunk = outputBundle[chunk.id!] as OutputChunk;
- return chunk
- .render(this.outputOptions, addons, outputChunk, this.pluginDriver)
- .then(rendered => {
- outputChunk.code = rendered.code;
- outputChunk.map = rendered.map;
- });
- })
- );
+ this.prerenderChunks(chunks, inputBase);
+ timeEnd('render modules', 2);
+
+ await this.addFinalizedChunksToBundle(chunks, inputBase, addons, outputBundle);
} catch (error) {
await this.pluginDriver.hookParallel('renderError', [error]);
throw error;
@@ -64,27 +68,65 @@ export default class Bundle {
outputBundle as OutputBundle,
isWrite
]);
- for (const key of Object.keys(outputBundle)) {
- const file = outputBundle[key] as any;
- if (!file.type) {
- warnDeprecation(
- 'A plugin is directly adding properties to the bundle object in the "generateBundle" hook. This is deprecated and will be removed in a future Rollup version, please use "this.emitFile" instead.',
- true,
- this.inputOptions
- );
- file.type = 'asset';
- }
- }
- this.pluginDriver.finaliseAssets();
+ this.finaliseAssets(outputBundle);
timeEnd('GENERATE', 1);
return outputBundle as OutputBundle;
}
- private assignChunkIds(inputBase: string, addons: Addons, bundle: OutputBundleWithPlaceholders) {
+ private async addFinalizedChunksToBundle(
+ chunks: Chunk[],
+ inputBase: string,
+ addons: Addons,
+ outputBundle: OutputBundleWithPlaceholders
+ ): Promise {
+ this.assignChunkIds(chunks, inputBase, addons, outputBundle);
+ for (const chunk of chunks) {
+ const chunkDescription = (outputBundle[
+ chunk.id!
+ ] = chunk.getPrerenderedChunk() as OutputChunk);
+ chunkDescription.fileName = chunk.id!;
+ }
+ await Promise.all(
+ chunks.map(chunk => {
+ const outputChunk = outputBundle[chunk.id!] as OutputChunk;
+ return chunk
+ .render(this.outputOptions, addons, outputChunk, this.pluginDriver)
+ .then(rendered => {
+ outputChunk.code = rendered.code;
+ outputChunk.map = rendered.map;
+ });
+ })
+ );
+ }
+
+ private async addManualChunks(
+ manualChunks: Record
+ ): Promise