From 25f43c2ad25cc8d1eae5fee8f25791def08cb9c7 Mon Sep 17 00:00:00 2001 From: Zack Jackson Date: Sun, 10 Jun 2018 15:44:30 -0400 Subject: [PATCH 1/7] feat(src/flushChunks.js): Support Webpack 4 Aggressive Chunking Supports complex code splitting done by webpack, allows for better code sharing between universal components. BREAKING CHANGE: none #55 --- src/flushChunks.js | 45 +++++++++++++++++++++++++++++++++++++-------- yarn.lock | 14 +++++++++++--- 2 files changed, 48 insertions(+), 11 deletions(-) diff --git a/src/flushChunks.js b/src/flushChunks.js index ebb0c61..50706ac 100644 --- a/src/flushChunks.js +++ b/src/flushChunks.js @@ -23,6 +23,7 @@ type Module = { export type Stats = { assetsByChunkName: FilesMap, + namedChunkGroups: FilesMap, chunks: Array, modules: Array, publicPath: string @@ -61,14 +62,27 @@ export default (stats: Stats, opts: Options): Api => const flushChunks = (stats: Stats, isWebpack: boolean, opts: Options = {}) => { const beforeEntries = opts.before || defaults.before - const jsBefore = filesFromChunks(beforeEntries, stats.assetsByChunkName) + const jsBefore = filesFromChunks( + beforeEntries, + stats.assetsByChunkName, + stats.namedChunkGroups + ) const files = opts.chunkNames - ? filesFromChunks(opts.chunkNames, stats.assetsByChunkName, true) + ? filesFromChunks( + opts.chunkNames, + stats.assetsByChunkName, + stats.namedChunkGroups, + true + ) : flush(opts.moduleIds || [], stats, opts.rootDir, isWebpack) const afterEntries = opts.after || defaults.after - const jsAfter = filesFromChunks(afterEntries, stats.assetsByChunkName) + const jsAfter = filesFromChunks( + afterEntries, + stats.assetsByChunkName, + stats.namedChunkGroups + ) return createApiWithCss( [...jsBefore, ...files, ...jsAfter], @@ -87,7 +101,11 @@ const flushFiles = (stats: Stats, opts: Options2) => const flushFilesPure = (stats: Stats, isWebpack: boolean, opts: Options2) => { const files = opts.chunkNames - ? filesFromChunks(opts.chunkNames, stats.assetsByChunkName) + ? filesFromChunks( + opts.chunkNames, + stats.assetsByChunkName, + stats.namedChunkGroups + ) : flush(opts.moduleIds || [], stats, opts.rootDir, isWebpack) const filter = opts.filter @@ -192,20 +210,31 @@ const concatFilesAtKeys = ( const filesFromChunks = ( chunkNames: Files, assets: FilesMap, + assetsByChunkName: FilesMap, checkChunkNames?: boolean ): Files => { const hasChunk = entry => { - const result = !!(assets[entry] || assets[entry + '-']) + const result = !!(assets[entry] || assets[`${entry}-`]) if (!result && checkChunkNames) { - console.warn(`[FLUSH CHUNKS]: Unable to find ${entry} in Webpack chunks. Please check usage of Babel plugin.`) + console.warn( + `[FLUSH CHUNKS]: Unable to find ${entry} in Webpack chunks. Please check usage of Babel plugin.` + ) } return result } - const entryToFiles = entry => assets[entry] || assets[entry + '-'] + const filesByChunkName = name => { + if (!assetsByChunkName || !assetsByChunkName[name]) { + return name + } + return assetsByChunkName[name].chunks + } - return [].concat(...chunkNames.filter(hasChunk).map(entryToFiles)) + const entryToFiles = entry => assets[entry] || assets[`${entry}-`] + const chunksToResolve = chunkNames.filter(hasChunk).map(filesByChunkName) + const chunksWithAssets = [].concat(...chunksToResolve) + return [].concat(...chunksWithAssets.filter(isUnique).map(entryToFiles)) } /** EXPORTS FOR TESTS */ diff --git a/yarn.lock b/yarn.lock index 047f527..a314f3d 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3660,6 +3660,13 @@ node-fetch@^1.0.1: encoding "^0.1.11" is-stream "^1.0.1" +node-fetch@^1.7.1: + version "1.7.3" + resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-1.7.3.tgz#980f6f72d85211a5347c6b2bc18c5b84c3eb47ef" + dependencies: + encoding "^0.1.11" + is-stream "^1.0.1" + node-int64@^0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/node-int64/-/node-int64-0.4.0.tgz#87a9065cdb355d3182d8f94ce11188b825c68a3b" @@ -5044,13 +5051,14 @@ travis-deploy-once@1.0.0-node-0.10-support: request-promise "^4.1.1" travis-ci "^2.1.1" -travis-github-status@^1.4.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/travis-github-status/-/travis-github-status-1.4.0.tgz#4282e9edfc3eec81eee6c285568f30e23b89e12e" +travis-github-status@^1.6.3: + version "1.6.3" + resolved "https://registry.yarnpkg.com/travis-github-status/-/travis-github-status-1.6.3.tgz#85436c999feca06182855ab9bbacdd25ae5326a2" dependencies: codeclimate-test-reporter "^0.4.1" colors "^1.1.2" github "^9.2.0" + node-fetch "^1.7.1" snyk "^1.29.0" trim-newlines@^1.0.0: From 033d97c7070b5e2ca265d51225989b63db50bf0a Mon Sep 17 00:00:00 2001 From: Zack Jackson Date: Sun, 10 Jun 2018 18:01:51 -0400 Subject: [PATCH 2/7] test: Fixing FlowTypes for new Webpack 4 chunks Adding object flowType for the new chunkAssets object from webpack 4 stats --- src/flushChunks.js | 73 +++++++++++++++++++++++++++++++--------------- 1 file changed, 50 insertions(+), 23 deletions(-) diff --git a/src/flushChunks.js b/src/flushChunks.js index 50706ac..d4d6e14 100644 --- a/src/flushChunks.js +++ b/src/flushChunks.js @@ -22,7 +22,7 @@ type Module = { } export type Stats = { - assetsByChunkName: FilesMap, + assetsByChunkName: Object, namedChunkGroups: FilesMap, chunks: Array, modules: Array, @@ -207,34 +207,61 @@ const concatFilesAtKeys = ( [] ) +const filesByChunkName = (name, assetsByChunkName) => { + if (!assetsByChunkName || !assetsByChunkName[name]) { + return [name] + } + return assetsByChunkName[name].chunks +} + +const hasChunk = (entry, assets, checkChunkNames) => { + const result = !!(assets[entry] || assets[`${entry}-`]) + if (!result && checkChunkNames) { + console.warn( + `[FLUSH CHUNKS]: Unable to find ${entry} in Webpack chunks. Please check usage of Babel plugin.` + ) + } + + return result +} + +const chunksToResolve = ({ + chunkNames, + assetsByChunkName, + assets, + checkChunkNames +}: { + chunkNames: Files, + assets: FilesMap, + assetsByChunkName: Object, + checkChunkNames?: boolean +}): Array => + chunkNames + .reduce((names, name) => { + if (!hasChunk(name, assets, checkChunkNames)) { + return names + } + const files = filesByChunkName(name, assetsByChunkName) + names.push(...files) + return names + }, []) + .filter(isUnique) + const filesFromChunks = ( chunkNames: Files, assets: FilesMap, - assetsByChunkName: FilesMap, + assetsByChunkName: Object, checkChunkNames?: boolean ): Files => { - const hasChunk = entry => { - const result = !!(assets[entry] || assets[`${entry}-`]) - if (!result && checkChunkNames) { - console.warn( - `[FLUSH CHUNKS]: Unable to find ${entry} in Webpack chunks. Please check usage of Babel plugin.` - ) - } - - return result - } - - const filesByChunkName = name => { - if (!assetsByChunkName || !assetsByChunkName[name]) { - return name - } - return assetsByChunkName[name].chunks - } - const entryToFiles = entry => assets[entry] || assets[`${entry}-`] - const chunksToResolve = chunkNames.filter(hasChunk).map(filesByChunkName) - const chunksWithAssets = [].concat(...chunksToResolve) - return [].concat(...chunksWithAssets.filter(isUnique).map(entryToFiles)) + const chunksWithAssets = chunksToResolve({ + chunkNames, + assetsByChunkName, + assets, + checkChunkNames + }) + + return [].concat(...chunksWithAssets.map(entryToFiles)) } /** EXPORTS FOR TESTS */ From 39a5f0efe375c18e586fe3c3db3a352fb1df9ad0 Mon Sep 17 00:00:00 2001 From: Zack Jackson Date: Sun, 10 Jun 2018 20:24:15 -0400 Subject: [PATCH 3/7] refactor(src/flushChunks): Reducing cognitive complexity Reducing cognitive complexity of code, fixing multiple code climate issues --- src/flushChunks.js | 23 +++++++---------------- 1 file changed, 7 insertions(+), 16 deletions(-) diff --git a/src/flushChunks.js b/src/flushChunks.js index d4d6e14..a81ad0a 100644 --- a/src/flushChunks.js +++ b/src/flushChunks.js @@ -62,27 +62,18 @@ export default (stats: Stats, opts: Options): Api => const flushChunks = (stats: Stats, isWebpack: boolean, opts: Options = {}) => { const beforeEntries = opts.before || defaults.before - const jsBefore = filesFromChunks( - beforeEntries, - stats.assetsByChunkName, - stats.namedChunkGroups - ) + const { assetsByChunkName, namedChunkGroups } = stats + const ffc = (assets, isWebpack = false) => + filesFromChunks(assets, assetsByChunkName, namedChunkGroups, isWebpack) + + const jsBefore = ffc(beforeEntries) const files = opts.chunkNames - ? filesFromChunks( - opts.chunkNames, - stats.assetsByChunkName, - stats.namedChunkGroups, - true - ) + ? ffc(opts.chunkNames, true) : flush(opts.moduleIds || [], stats, opts.rootDir, isWebpack) const afterEntries = opts.after || defaults.after - const jsAfter = filesFromChunks( - afterEntries, - stats.assetsByChunkName, - stats.namedChunkGroups - ) + const jsAfter = ffc(afterEntries) return createApiWithCss( [...jsBefore, ...files, ...jsAfter], From 88dbc9795da21f2f031887c9fe3b41f7d5ed7b11 Mon Sep 17 00:00:00 2001 From: Zack Jackson Date: Sun, 10 Jun 2018 21:56:59 -0400 Subject: [PATCH 4/7] Update README.md Adding additional notes about the update to the README --- README.md | 56 ++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 55 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 62fcfa4..74758cf 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,6 @@ # Webpack Flush Chunks -

Version @@ -41,6 +40,9 @@ 🍾🍾🍾 GIT CLONE LOCAL DEMO πŸš€πŸš€πŸš€

+> **Now supports Webpack 4 aggressive code splitting** +We have updated `webpack-flush-chunks` to now support more complex code splitting! `webpack-flush-chunks` enables developers to leverage smarter and less wasteful chunking methods avaliable to developers inside of Webpack. +

@@ -71,6 +73,58 @@ res.send(` `) ``` +## Webpack 4 Aggressive Code Splitting Support + +This plugin allows for complex code splitting to be leveraged for improved caching and less code duplication! + +#### Before: +Before this update, developers were limited to a single chunk stratagey. What the stratagey did was give developers a similar chunk method to `CommonsChunkPlugin` that was used in Webpack 3. We did not support `AggressiveSplittingPlugin` + +```js + optimization: { + runtimeChunk: { + name: 'bootstrap' + }, + splitChunks: { + chunks: 'initial', + cacheGroups: { + vendors: { + test: /[\\/]node_modules[\\/]/, + name: 'vendor' + } + } + } + }, +``` +#### After: +Now you can use many flexible code splitting methods, like the one below. Webpack encourages aggressive code splitting methods, so we jumped on the bandwagon and did the upgrades. Just like before, we use the chunkNames generated - then we can look within the Webpack 4 chunk graph and resolve any other dependencies or automatically generated chunks that consist as part of the initial chunk. + +We can load the nested chunks in the correct order as required and if many chunks share a common chunk, we ensure they load in the correct order, so that vendor chunks are always available to all chunks depending on them without creating any duplicate requests or chunk calls. + +```js + optimization: { + splitChunks: { + chunks: 'async', + minSize: 30000, + minChunks: 1, + maxAsyncRequests: 5, + maxInitialRequests: 3, + automaticNameDelimiter: '~', + name: true, + cacheGroups: { + vendors: { + test: /[\\/]node_modules[\\/]/, + priority: -10 + }, + default: { + minChunks: 2, + priority: -20, + reuseExistingChunk: true + } + } + } + } +``` The code has been cracked for while now for Server Side Rendering and Code-Splitting *individually*. Accomplishing both *simultaneously* has been an impossibility without jumping through major hoops or using a *framework*, specifically Next.js. Our tools are for "power users" that prefer the *frameworkless* approach. *Webpack Flush Chunks* is essentially the backend to universal rendering components like [React Universal Component](https://github.com/faceyspacey/react-universal-component). It works with any "universal" component/module that buffers a list of `moduleIds` or `chunkNames` evaluated. From 9bd3e37c6a91ec19bc5eae7ca24b0fa175f2b769 Mon Sep 17 00:00:00 2001 From: Zack Jackson Date: Mon, 11 Jun 2018 23:22:35 -0400 Subject: [PATCH 5/7] feat(src): Flush chunks by ID resolving chunk using aggressive code splitting and chunking with IDs and not chunknames BREAKING CHANGE: Significent changes to internal resolution system. --- __tests__/flushChunks.test.js | 2 +- package.json | 3 ++ src/flushChunks.js | 58 +++++++++++++++++++++-------------- 3 files changed, 39 insertions(+), 24 deletions(-) diff --git a/__tests__/flushChunks.test.js b/__tests__/flushChunks.test.js index 2438662..ff0a6f4 100644 --- a/__tests__/flushChunks.test.js +++ b/__tests__/flushChunks.test.js @@ -229,7 +229,7 @@ describe('unit tests', () => { bootstrap: ['bootstrap.js'], main: ['main.js', 'main.css'] } - const outputFiles = filesFromChunks(entryNames, assetsByChunkName) + const outputFiles = filesFromChunks(entryNames, { assetsByChunkName }) expect(outputFiles).toEqual(['bootstrap.js', 'main.js', 'main.css']) }) diff --git a/package.json b/package.json index de3ca85..538f9fe 100644 --- a/package.json +++ b/package.json @@ -5,6 +5,9 @@ "main": "dist/flushChunks.js", "typings": "index.d.ts", "author": "James Gillmore ", + "contributors": [ + "Zack Jackson " + ], "license": "MIT", "scripts": { "build": "babel src -d dist", diff --git a/src/flushChunks.js b/src/flushChunks.js index a81ad0a..f04042d 100644 --- a/src/flushChunks.js +++ b/src/flushChunks.js @@ -62,9 +62,7 @@ export default (stats: Stats, opts: Options): Api => const flushChunks = (stats: Stats, isWebpack: boolean, opts: Options = {}) => { const beforeEntries = opts.before || defaults.before - const { assetsByChunkName, namedChunkGroups } = stats - const ffc = (assets, isWebpack = false) => - filesFromChunks(assets, assetsByChunkName, namedChunkGroups, isWebpack) + const ffc = (assets, isWebpack) => filesFromChunks(assets, stats, isWebpack) const jsBefore = ffc(beforeEntries) @@ -92,11 +90,7 @@ const flushFiles = (stats: Stats, opts: Options2) => const flushFilesPure = (stats: Stats, isWebpack: boolean, opts: Options2) => { const files = opts.chunkNames - ? filesFromChunks( - opts.chunkNames, - stats.assetsByChunkName, - stats.namedChunkGroups - ) + ? filesFromChunks(opts.chunkNames, stats) : flush(opts.moduleIds || [], stats, opts.rootDir, isWebpack) const filter = opts.filter @@ -181,6 +175,17 @@ const createFilesByModuleId = (stats: Stats): FilesMap => { }, {}) } +const findChunkById = ({ chunks }) => { + if (!chunks) { + return {} + } + const filesByChunk = chunks.reduce((chunks, chunk) => { + chunks[chunk.id] = chunk.files + return chunks + }, {}) + return filesByChunk +} + /** HELPERS */ const isUnique = (v: string, i: number, self: Files): boolean => @@ -198,11 +203,12 @@ const concatFilesAtKeys = ( [] ) -const filesByChunkName = (name, assetsByChunkName) => { - if (!assetsByChunkName || !assetsByChunkName[name]) { +const filesByChunkName = (name, namedChunkGroups) => { + if (!namedChunkGroups || !namedChunkGroups[name]) { return [name] } - return assetsByChunkName[name].chunks + + return namedChunkGroups[name].chunks } const hasChunk = (entry, assets, checkChunkNames) => { @@ -218,21 +224,19 @@ const hasChunk = (entry, assets, checkChunkNames) => { const chunksToResolve = ({ chunkNames, - assetsByChunkName, - assets, + stats, checkChunkNames }: { chunkNames: Files, - assets: FilesMap, - assetsByChunkName: Object, + stats: Object, checkChunkNames?: boolean }): Array => chunkNames .reduce((names, name) => { - if (!hasChunk(name, assets, checkChunkNames)) { + if (!hasChunk(name, stats.assetsByChunkName, checkChunkNames)) { return names } - const files = filesByChunkName(name, assetsByChunkName) + const files = filesByChunkName(name, stats.namedChunkGroups) names.push(...files) return names }, []) @@ -240,19 +244,27 @@ const chunksToResolve = ({ const filesFromChunks = ( chunkNames: Files, - assets: FilesMap, - assetsByChunkName: Object, + stats: Object, checkChunkNames?: boolean ): Files => { - const entryToFiles = entry => assets[entry] || assets[`${entry}-`] + const chunksByID = findChunkById(stats) + + const entryToFiles = entry => { + if (typeof entry === 'number') { + return chunksByID[entry] + } + return ( + stats.assetsByChunkName[entry] || stats.assetsByChunkName[`${entry}-`] + ) + } + const chunksWithAssets = chunksToResolve({ chunkNames, - assetsByChunkName, - assets, + stats, checkChunkNames }) - return [].concat(...chunksWithAssets.map(entryToFiles)) + return [].concat(...chunksWithAssets.map(entryToFiles)).filter(chunk => chunk) } /** EXPORTS FOR TESTS */ From 19c606e7a02bbcd6fc616fd3f9d43e7102292f72 Mon Sep 17 00:00:00 2001 From: Zack Jackson Date: Mon, 11 Jun 2018 23:34:02 -0400 Subject: [PATCH 6/7] refactor: DRYing out code --- src/flushChunks.js | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/src/flushChunks.js b/src/flushChunks.js index f04042d..7697caf 100644 --- a/src/flushChunks.js +++ b/src/flushChunks.js @@ -147,16 +147,17 @@ const flushWebpack = (ids: Files, stats: Stats): Files => { } /** CREATE FILES MAP */ - -const createFilesByPath = ({ chunks, modules }: Stats): FilesMap => { - const filesByChunk = chunks.reduce((chunks, chunk) => { +const filesByChunk = chunks => + chunks.reduce((chunks, chunk) => { chunks[chunk.id] = chunk.files return chunks }, {}) +const createFilesByPath = ({ chunks, modules }: Stats): FilesMap => { + const chunkedFiles = filesByChunk(chunks) return modules.reduce((filesByPath, module) => { const filePath = module.name - const files = concatFilesAtKeys(filesByChunk, module.chunks) + const files = concatFilesAtKeys(chunkedFiles, module.chunks) filesByPath[filePath] = files.filter(isUnique) return filesByPath @@ -179,11 +180,7 @@ const findChunkById = ({ chunks }) => { if (!chunks) { return {} } - const filesByChunk = chunks.reduce((chunks, chunk) => { - chunks[chunk.id] = chunk.files - return chunks - }, {}) - return filesByChunk + return filesByChunk(chunks) } /** HELPERS */ From 2ce881c81e967a45fc3b1b7a79c0375648296ea9 Mon Sep 17 00:00:00 2001 From: Zack Jackson Date: Tue, 12 Jun 2018 01:02:00 -0400 Subject: [PATCH 7/7] Update README.md More updates to the README removing old code and all that --- README.md | 62 +++++++++++++++++++++---------------------------------- 1 file changed, 23 insertions(+), 39 deletions(-) diff --git a/README.md b/README.md index 74758cf..79263ea 100644 --- a/README.md +++ b/README.md @@ -38,6 +38,7 @@

🍾🍾🍾 GIT CLONE LOCAL DEMO πŸš€πŸš€πŸš€ +
Webpack 4 demo update in progress

> **Now supports Webpack 4 aggressive code splitting** @@ -54,7 +55,7 @@ import { flushChunkNames } from 'react-universal-component/server' import flushChunks from 'webpack-flush-chunks' const app = ReactDOMServer.renderToString() -const { js, styles, cssHash } = flushChunks(webpackStats, { +const { js, styles } = flushChunks(webpackStats, { chunkNames: flushChunkNames() }) @@ -66,7 +67,6 @@ res.send(`
${app}
- ${cssHash} ${js} @@ -76,6 +76,7 @@ res.send(` ## Webpack 4 Aggressive Code Splitting Support This plugin allows for complex code splitting to be leveraged for improved caching and less code duplication! +Below are two examples of well tested splitting configurations. If you experience any issues with bespoke optimization configurations, we would love to hear about it! #### Before: Before this update, developers were limited to a single chunk stratagey. What the stratagey did was give developers a similar chunk method to `CommonsChunkPlugin` that was used in Webpack 3. We did not support `AggressiveSplittingPlugin` @@ -155,11 +156,12 @@ yarn add --dev babel-plugin-universal-import extract-css-chunks-webpack-plugin ``` - ***[Babel Plugin Universal Import](https://github.com/faceyspacey/babel-plugin-universal-import)*** is used to make `react-universal-component` as frictionless as possible. It removes the need to provide additional options to insure synchronous rendering happens on the server and on the client on initial load. These packages aren't required, but usage as frictionless as possible. -- ***[Extract Css Chunks Webpack Plugin](https://github.com/faceyspacey/extract-css-chunks-webpack-plugin)*** is another companion package made to complete the CSS side of the code-splitting dream. It uses the `cssHash` string to asynchronously request CSS assets as part of a "dual import" when calling `import()`. +- ***[Extract Css Chunks Webpack Plugin](https://github.com/faceyspacey/extract-css-chunks-webpack-plugin)*** is another companion package made to complete the CSS side of the code-splitting dream. Its also a standalone plugin thats great for codesplitting css, with **built-in HMR** -*If you like to move fast, git clone the [universal-demo](https://github.com/faceyspacey/universal-demo)*. + ~~*If you like to move fast, git clone the [universal-demo](https://github.com/faceyspacey/universal-demo)*.~~ We are working on a Webpack 4 demo + ## How It Works @@ -196,14 +198,6 @@ Before we examine how to use `flushChunks/flushFiles`, let's take a look at the - - - ``` @@ -245,7 +239,7 @@ import flushChunks from 'webpack-flush-chunks' const app = ReactDOMServer.renderToString() const chunkNames = flushChunkNames() -const { js, styles, cssHash } = flushChunks(stats, { chunkNames }) +const { js, styles } = flushChunks(stats, { chunkNames }) res.send(` @@ -255,7 +249,6 @@ res.send(`
${app}
- ${cssHash} ${js} @@ -277,22 +270,22 @@ flushChunks(stats, { }) ``` - - **chunkNames** - ***array of chunks flushed from `react-universal-component` -- **before** - ***array of named entries that come BEFORE your dynamic chunks:*** A typical +- **before** - ***array of named entries that come BEFORE your dynamic chunks:*** ~~A typical pattern is to create a `vendor` chunk. A better strategy is to create a `vendor` and a `bootstrap` chunk. The "bootstrap" chunk is a name provided to the `CommonsChunkPlugin` which has no entry point specified for it. The plugin by default removes webpack bootstrap code from the named `vendor` common chunk and puts it in the `bootstrap` chunk. This is a common pattern because the webpack bootstrap code has info about the chunks/modules used in your bundle and is likely to change, which means to cache your `vendor` chunk you need to extract the bootstrap code into its own small chunk file. If this is new to you, don't worry. -[Below](#webpack-configuration) you will find examples for exactly how to specify your Webpack config. Lastly, you do not need to -provide this option if you have a `bootstrap` chunk, or `vendor` chunk or both, as those are the defaults. +[Below](#webpack-configuration) you will find examples for exactly how to specify your Webpack config. Lastly, you do not need to provide this option if you have a `bootstrap` chunk, or `vendor` chunk or both, as those are the defaults.~~ + +Mostly related to Webpack 2 & 3. It is still very useful if you need to load a specific chunk name **first** `webpack-flush-chunks` now can rely on a better chunk graph provided by Webpack 4 - chunks are loaded in the correct order with more autonomy. - **after** - ***array of named entries that come AFTER your dynamic chunks:*** -Similar to `before`, `after` contains an array of chunks you want to come after the dynamic chunks that +~~Similar to `before`, `after` contains an array of chunks you want to come after the dynamic chunks that your universal component flushes. Typically you have just a `main` chunk, and if that's the case, you can ignore this option, -as that's the default. +as that's the default.~~ - **outputPath** - ***absolute path to the directory containing your client build:*** This is only needed if serving css embedded in your served response HTML, rather than links to external stylesheets. I.e. if you are using the `Css` and `css` values in the `return API` described in the next section. It's needed to determine where in the file system to find the CSS that needs to be extract into @@ -357,32 +350,23 @@ module: { }, { test: /\.css$/, - use: ExtractCssChunks.extract({ - use: { - loader: 'css-loader', - options: { - modules: true, - localIdentName: '[name]__[local]--[hash:base64:5]' - } + use: [ + ExtractCssChunks.loader, + { + loader: 'css-loader', + options: { + modules: true, + localIdentName: '[name]__[local]--[hash:base64:5]' } - }) + ] } ] }, plugins: [ - new ExtractCssChunks, - new webpack.optimize.CommonsChunkPlugin({ - names: ['bootstrap'], // notice there is no "bootstrap" named entry - filename: '[name].js', - minChunks: Infinity - }) + new ExtractCssChunks(), ... ``` -- The `CommonsChunkPlugin` with a `"bootstrap"` entry ***which does NOT in fact exist (notice there is no `entry` for it)*** insures that a separate chunk is created just for webpack bootstrap code. -This moves the webpack bootstrap code out of your `main` entry chunk so that it can also run before your dynamic -chunks. - ***server:*** ```js @@ -446,7 +430,7 @@ const chunkNames = flushChunkNames() const scripts = flushFiles(stats, { chunkNames, filter: 'js' }) const styles = flushFiles(stats, { chunkNames, filter: 'css' }) ``` -> i.e. this will get you all files corresponding to flushed "dynamic" chunks, not `main`, `vendor`, etc. +> i.e. this will get you all files corresponding to flushed "dynamic" chunks. The only thing different with the API is that it has a `filter` option, and that it doesn't have `before`, `after` and `outputPath` options. The `filter` can be a file extension as a string, a regex, or a function: `filter: file => file.endsWith('js')`.