From de835985fb770320705809244daaf404a8e9b5e2 Mon Sep 17 00:00:00 2001 From: Guy Bedford Date: Wed, 30 May 2018 13:52:58 +0200 Subject: [PATCH] remove processChunks hook for generateBundle, include tree-shaking info in generateBundle modules --- src/Chunk.ts | 19 +++++++--- src/Graph.ts | 4 ++- src/Module.ts | 9 ++--- src/ast/nodes/MetaProperty.ts | 1 - src/rollup/index.ts | 67 +++++++++++++++-------------------- src/rollup/types.d.ts | 16 +++++---- test/hooks/index.js | 18 ++++++---- 7 files changed, 73 insertions(+), 61 deletions(-) diff --git a/src/Chunk.ts b/src/Chunk.ts index 2209c680487..bc7704904e8 100644 --- a/src/Chunk.ts +++ b/src/Chunk.ts @@ -19,7 +19,7 @@ import { RenderOptions } from './utils/renderHelpers'; import { Addons } from './utils/addons'; import sha256 from 'hash.js/lib/hash/sha/256'; import ExternalVariable from './ast/variables/ExternalVariable'; -import { GlobalsOption, OutputOptions, RawSourceMap } from './rollup/types'; +import { GlobalsOption, OutputOptions, RawSourceMap, RenderedModule } from './rollup/types'; import { toBase64 } from './utils/base64'; import { renderNamePattern, makeUnique } from './utils/renderNamePattern'; @@ -91,6 +91,10 @@ export default class Chunk { orderedModules: Module[]; linked = false; + renderedModules: { + [moduleId: string]: RenderedModule; + }; + // this represents the chunk module wrappings // which form the output dependency graph private imports = new Map(); @@ -152,10 +156,6 @@ export default class Chunk { return Object.keys(this.exportNames); } - getModuleIds(): string[] { - return this.orderedModules.map(module => module.id); - } - private inlineChunkDependencies(chunk: Chunk, deep: boolean) { for (let dep of chunk.dependencies) { if (dep instanceof ExternalModule) { @@ -785,6 +785,7 @@ export default class Chunk { let hoistedSource = ''; + this.renderedModules = Object.create(null); this.renderedModuleSources = []; for (let i = 0; i < this.orderedModules.length; i++) { @@ -794,6 +795,14 @@ export default class Chunk { if (options.compact && source.lastLine().indexOf('//') !== -1) source.append('\n'); this.renderedModuleSources.push(source); + const { renderedExports, removedExports } = module.getRenderedExports(); + this.renderedModules[module.id] = { + renderedExports, + removedExports, + renderedLength: source.toString().length, + originalLength: module.originalCode.length + }; + const namespace = module.getOrCreateNamespace(); if (namespace.needsNamespaceBlock || !source.isEmpty()) { magicString.addSource(source); diff --git a/src/Graph.ts b/src/Graph.ts index b8d178bad4f..a0a8659da61 100644 --- a/src/Graph.ts +++ b/src/Graph.ts @@ -238,7 +238,9 @@ export default class Graph { finaliseAssets(assetFileNames: string) { const outputBundle: OutputBundle = Object.create(null); - this.assetsById.forEach(asset => finaliseAsset(asset, outputBundle, assetFileNames)); + this.assetsById.forEach(asset => { + if (asset.source !== undefined) finaliseAsset(asset, outputBundle, assetFileNames); + }); return outputBundle; } diff --git a/src/Module.ts b/src/Module.ts index 44fd42d4c92..371c43d1eb6 100644 --- a/src/Module.ts +++ b/src/Module.ts @@ -680,14 +680,15 @@ export default class Module { return null; } - getIncludedExports(): string[] { + getRenderedExports() { // only direct exports are counted here, not reexports at all - const includedExports = []; + const renderedExports: string[] = []; + const removedExports: string[] = []; for (let exportName in this.exports) { const expt = this.exports[exportName]; - if (expt.node.included) includedExports.push(exportName); + (expt.node.included ? renderedExports : removedExports).push(exportName); } - return includedExports; + return { renderedExports, removedExports }; } traceExport(name: string): Variable { diff --git a/src/ast/nodes/MetaProperty.ts b/src/ast/nodes/MetaProperty.ts index 0c3b684dab8..d635574df64 100644 --- a/src/ast/nodes/MetaProperty.ts +++ b/src/ast/nodes/MetaProperty.ts @@ -88,7 +88,6 @@ export default class MetaProperty extends NodeBase { // support import.meta.ROLLUP_ASSET_URL_[ID] if (importMetaProperty.startsWith('ROLLUP_ASSET_URL_')) { - console.log('mechanism'); const assetFileName = this.context.getAssetFileName(importMetaProperty.substr(17)); const relPath = normalize(relative(dirname(chunkId), assetFileName)); code.overwrite(parent.start, parent.end, relUrlMechanisms[format](relPath, compact)); diff --git a/src/rollup/index.ts b/src/rollup/index.ts index b7971557de7..b418b1e6c6c 100644 --- a/src/rollup/index.ts +++ b/src/rollup/index.ts @@ -20,8 +20,7 @@ import { OutputBundle, OutputFile, RollupSingleFileBuild, - RollupBuild, - ChunkDefinition + RollupBuild } from './types'; import getExportMode from '../utils/getExportMode'; import Chunk from '../Chunk'; @@ -79,10 +78,16 @@ function applyOptionHook(inputOptions: InputOptions, plugin: Plugin) { return inputOptions; } +function applyBuildStartHook(graph: Graph) { + return Promise.all( + graph.plugins.map(plugin => plugin.buildStart && plugin.buildStart.call(graph.pluginContext)) + ).then(() => {}); +} + function applyBuildEndHook(graph: Graph, err?: any) { - for (let plugin of graph.plugins) { - if (plugin.buildEnd) plugin.buildEnd.call(graph.pluginContext, err); - } + return Promise.all( + graph.plugins.map(plugin => plugin.buildEnd && plugin.buildEnd.call(graph.pluginContext, err)) + ).then(() => {}); } function getInputOptions(rawInputOptions: GenericConfigObject): any { @@ -110,43 +115,28 @@ export default function rollup( initialiseTimers(inputOptions); const graph = new Graph(inputOptions); - for (let plugin of graph.plugins) { - if (plugin.buildStart) plugin.buildStart.call(graph.pluginContext, inputOptions); - } - timeStart('BUILD', 1); - return graph - .build( - inputOptions.input, - inputOptions.manualChunks, - inputOptions.inlineDynamicImports, - inputOptions.experimentalPreserveModules - ) - .then(chunks => { - // run generateBundle hook - const processChunksPlugins = graph.plugins.filter(plugin => plugin.processChunks); - if (processChunksPlugins.length === 0) return chunks; - const processChunksChunks: ChunkDefinition[] = chunks.map(chunk => { - const chunkModules: ChunkDefinition = Object.create(null); - for (let module of chunk.orderedModules) - chunkModules[module.id] = module.getIncludedExports(); - return chunkModules; + return applyBuildStartHook(graph) + .then(() => { + return graph.build( + inputOptions.input, + inputOptions.manualChunks, + inputOptions.inlineDynamicImports, + inputOptions.experimentalPreserveModules + ); + }) + .catch(err => { + return applyBuildEndHook(graph, err).then(() => { + throw err; }); - return Promise.all( - processChunksPlugins.map(plugin => - plugin.processChunks.call(graph.pluginContext, processChunksChunks) - ) - ).then(() => { + }) + .then(chunks => { + return applyBuildEndHook(graph).then(() => { return chunks; }); }) - .catch(err => { - applyBuildEndHook(graph, err); - throw err; - }) .then(chunks => { - applyBuildEndHook(graph); timeEnd('BUILD', 1); // TODO: deprecate legacy single chunk return @@ -229,10 +219,11 @@ export default function rollup( } // then name all chunks - for (let chunk of chunks) { + for (let i = 0; i < chunks.length; i++) { + const chunk = chunks[i]; const imports = chunk.getImportIds(); const exports = chunk.getExportNames(); - const modules = chunk.getModuleIds(); + const modules = chunk.renderedModules; if (chunk === singleInputChunk) { singleInputChunk.id = basename( @@ -244,7 +235,7 @@ export default function rollup( const outputChunk: OutputChunk = { imports, exports, - modules: singleInputChunk.getModuleIds(), + modules, code: undefined, map: undefined }; diff --git a/src/rollup/types.d.ts b/src/rollup/types.d.ts index c8402b25146..4055a6c3551 100644 --- a/src/rollup/types.d.ts +++ b/src/rollup/types.d.ts @@ -140,12 +140,11 @@ export interface Plugin { resolveId?: ResolveIdHook; missingExport?: MissingExportHook; transform?: TransformHook; - processChunks?: (this: PluginContext, chunks: ChunkDefinition[]) => void | Promise; // TODO: deprecate transformBundle?: TransformChunkHook; transformChunk?: TransformChunkHook; - buildStart?: (this: PluginContext, options: InputOptions) => void; - buildEnd?: (this: PluginContext, err?: any) => void; + buildStart?: (this: PluginContext, options: InputOptions) => Promise | void; + buildEnd?: (this: PluginContext, err?: any) => Promise | void; // TODO: deprecate ongenerate?: ( this: PluginContext, @@ -306,14 +305,19 @@ export type SerializedTimings = { [label: string]: number }; export type OutputFile = string | Buffer | OutputChunk; -export interface ChunkDefinition { - [moduleId: string]: string[]; +export interface RenderedModule { + renderedExports: string[]; + removedExports: string[]; + renderedLength: number; + originalLength: number; } export interface OutputChunk { imports: string[]; exports: string[]; - modules: string[]; + modules: { + [id: string]: RenderedModule; + }; code: string; map?: SourceMap; } diff --git a/test/hooks/index.js b/test/hooks/index.js index 75c87cd6d27..716d2ad54a3 100644 --- a/test/hooks/index.js +++ b/test/hooks/index.js @@ -340,7 +340,7 @@ module.exports = input; assetId = this.emitAsset('test.ext'); return ''; }, - processChunks () { + generateBundle () { this.setAssetSource(assetId, 'hello world'); } } @@ -539,7 +539,7 @@ module.exports = input; }); - it('supports processBundle hook including reporting tree-shaken exports', () => { + it('supports processBundle hook including reporting rendered exports and source length', () => { return rollup .rollup({ input: 'input', @@ -550,12 +550,18 @@ module.exports = input; dep: `export var a = 1; export var b = 2;` }), { - processChunks (chunks) { - assert.equal(chunks.length, 1); + generateBundle (options, outputBundle, isWrite) { + const chunk = outputBundle['input.js']; // can detect that b has been tree-shaken this way - assert.equal(chunks[0]['dep'][0], 'a'); - assert.equal(chunks[0]['dep'].length, 1); + assert.equal(chunk.modules['dep'].renderedExports[0], 'a'); + assert.equal(chunk.modules['dep'].renderedExports.length, 1); + + assert.equal(chunk.modules['dep'].removedExports[0], 'b'); + assert.equal(chunk.modules['dep'].removedExports.length, 1); + + assert.equal(chunk.modules['dep'].renderedLength, 10); + assert.equal(chunk.modules['dep'].originalLength, 35); } } ]