diff --git a/src/index.js b/src/index.js index c0d05da..33caa5c 100644 --- a/src/index.js +++ b/src/index.js @@ -38,6 +38,7 @@ class PreloadPlugin { const extractedChunks = extractChunks({ compilation, + rel: options.rel, optionsInclude: options.include, }); diff --git a/src/lib/extract-chunks.js b/src/lib/extract-chunks.js index 1bbe62e..526439f 100644 --- a/src/lib/extract-chunks.js +++ b/src/lib/extract-chunks.js @@ -15,7 +15,35 @@ * limitations under the License. */ -function extractChunks({compilation, optionsInclude}) { +function getInitialChunks(compilation) { + return compilation.chunks.filter(chunk => { + if ('canBeInitial' in chunk) { + return !chunk.canBeInitial(); + } else { + return !chunk.isInitial(); + } + }); +} + +// This is an expensive operation as it uses getStats, but currently it is the only place we can get this data from. +function extractChildAssets(compilation, rel) { + const stats = compilation.getStats().toJson({all: false, entrypoints: true, chunks: true}); + + const assets = Object.keys(stats.entrypoints).reduce((childAssets, entrypointKey) => { + const entrypoint = stats.entrypoints[entrypointKey]; + childAssets = childAssets.concat(entrypoint.chunks.map(chunkId => stats.chunks.find(chunk => chunk.id === chunkId))); + + if (entrypoint.childAssets && entrypoint.childAssets[rel]) { + childAssets.push({files: entrypoint.childAssets[rel]}); + } + + return childAssets; + }, []); + + return assets; +} + +function extractChunks({compilation, optionsInclude, rel}) { try { // 'asyncChunks' are chunks intended for lazy/async loading usually generated as // part of code-splitting with import() or require.ensure(). By default, asyncChunks @@ -32,13 +60,11 @@ function extractChunks({compilation, optionsInclude}) { } if (optionsInclude === 'initial') { - return compilation.chunks.filter(chunk => { - if ('canBeInitial' in chunk) { - return chunk.canBeInitial(); - } else { - return chunk.isInitial(); - } - }); + return getInitialChunks(compilation); + } + + if (optionsInclude === 'entryAndChildren') { + return extractChildAssets(compilation, rel); } if (optionsInclude === 'allChunks') { diff --git a/test/unit/extract-chunk.js b/test/unit/extract-chunk.js new file mode 100644 index 0000000..b6598d9 --- /dev/null +++ b/test/unit/extract-chunk.js @@ -0,0 +1,90 @@ +/** + * @license + * Copyright 2018 Google Inc. + * + * Licensed under the Apache License, Version 2.0 (the 'License'); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an 'AS IS' BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +const extractChunk = require('../../src/lib/extract-chunks'); + +const stubEntrypoints = { + entry1: { + chunks: ['chunk1', 'chunk2'], + childAssets: {} + } +}; + +const stubEntrypointsWithPreloadedChildren = { + entry1: { + chunks: ['chunk1', 'chunk2'], + childAssets: {} + }, + entry2: { + chunks: ['chunk3'], + childAssets: {preload: ['file4.js']} + } +}; + +const stubChunks = [ + {id: 'chunk1', files: ['file1.js']}, + {id: 'chunk2', files: ['file2.js']}, + {id: 'chunk3', files: ['file3.js']}, +]; + +class StubCompilation { + constructor(entrypoints, chunks) { + this.entrypoints = entrypoints; + this.chunks = chunks; + } + + getStats() { + return { + toJson: () => ({ + entrypoints: this.entrypoints, + chunks: this.chunks + }) + }; + } +} + +describe(`Entry and Children:`, function() { + it(`Includes entrypoints`, function() { + const compilation = new StubCompilation(stubEntrypoints, stubChunks); + const chunks = extractChunk({ + compilation, + optionsInclude: 'entryAndChildren', + rel: 'preload' + }); + expect(chunks).toEqual(stubChunks.slice(0, 2)); + }); + + it(`Includes entrypoints and children`, function() { + const compilation = new StubCompilation(stubEntrypointsWithPreloadedChildren, stubChunks); + const chunks = extractChunk({ + compilation, + optionsInclude: 'entryAndChildren', + rel: 'preload' + }); + expect(chunks).toEqual(stubChunks.concat({files: ['file4.js']})); + }); + + it(`Only includes entrypoints matching the rel option`, function() { + const compilation = new StubCompilation(stubEntrypointsWithPreloadedChildren, stubChunks); + const chunks = extractChunk({ + compilation, + optionsInclude: 'entryAndChildren', + rel: 'prefetch' + }); + expect(chunks).toEqual(stubChunks); + }); +});