From ba274dfa52df92dbff689cf060f6051033497bf7 Mon Sep 17 00:00:00 2001 From: Eugene Hlushko Date: Thu, 27 Sep 2018 12:39:48 +0300 Subject: [PATCH] Update next branch with recent master updates (#2551) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix(contribute) Use consistent plugin name in code snippet (#2496) * fix(configuration) Fix small typo (#2511) * docs(manifest) Corrections and small update to concept manifest page (#2504) Small updates and corrections for manifest concepts page * docs(concepts) Update dependency graph concepts page (#2495) * docs(concepts) Update dependency graph concepts page * docs(concepts) Dependency graph minor tweak * docs(concepts) Use common formatting, provide more links, mention mod… (#2472) * docs(concepts) use common formatting, provide more links, mention mode in core of the concepts * docs(concepts) duplicate links on the list for better ux * docs(concepts) forgot to add EugeneHlushko to contributors * docs(configuration) Add externals examples (#2515) Update the external docs with an example on how to combine the different syntaxes. I felt it was not clear how to achieve this from the existing docs. * docs(plugins) Update Writing plugin and Plugin pattern page (#2200) * Update Writing plugin and Plugin pattern page * Fixed formatting issues * Fix markdown lint issues * Update plugin-patterns.md * Update plugin-patterns.md * docs(concepts) Using vendors as entry is not recommended (#2525) * Using vendors as entry is not recommended fixes webpack/webpack#6647 * add note about vendor entrypoints * fix(guides) Correct misspelling and punctuation errors (#2513) * Correct misspelling and punctuation errors * Update build-performance.md * docs(plugins): Add custom vendor chunks using RegEx example (#2518) * docs(config): Example 3 - custom vendor chunk using RegEx * docs(config): Example 3 SplitChunks Fenced blank added * docs(config): (typo) Example 3 - custom vendor chunk using RegEx * sakhisheikh docs(config): (reworded) Example 3 - custom vendor chunk using RegEx * docs(config): (Reword) Example 3 - custom vendor chunk using RegEx * docs(config): (Reword) Example 3 - custom vendor chunk using RegEx * chore(plugins) Remove space (#2527) * docs(config): Example 3 - custom vendor chunk using RegEx * squashed everything after c81e77e * docs(plugins) Add .mjs to the defaults (#2493) This should be updated once https://github.com/webpack/webpack/pull/7947 is released. * chore(plugins) Minor SplitChunks Documentation Clean Up (#2252) * Minor Documentation Clean Up Originally, i was just trying to change defer => differ, but I ended up doing a bit more editing. * Lower the case * fix(api) Clarify module section (#2529) Change wording from "bind an extension" to "bind a file extension" in order to distinguish from a webpack extension. _describe your changes..._ - [ ] Read and sign the [CLA][1]. PRs that haven't signed it won't be accepted. - [ ] Make sure your PR complies with the [writer's guide][2]. - [ ] Review the diff carefully as sometimes this can reveal issues. - __Remove these instructions from your PR as they are for your eyes only.__ [1]: https://cla.js.foundation/webpack/webpack.js.org [2]: https://webpack.js.org/writers-guide/ * docs(plugins): Update links in htmlwebpackplugin (#2530) * docs(plugins) Fix reuseExistingChunk title nesting (#2526) * docs(plugins) scp reuseExistingChunk title nesting fix * docs(plugins) scp reuseExistingChunk title notation * docs(guides) Fix typo (#2537) * chore(guides) Import needs to be highlighted with '+' mark (#2536) import webpack needs to be highlighted since we are adding webpack.HashedModuleIdsPlugin() * docs(config) Optimization moduleIds option (#2543) --- src/content/api/cli.md | 10 +- src/content/concepts/dependency-graph.md | 10 +- src/content/concepts/entry-points.md | 24 +-- src/content/concepts/index.md | 32 +-- src/content/concepts/manifest.md | 11 +- src/content/configuration/externals.md | 33 +++ src/content/configuration/optimization.md | 27 +++ src/content/configuration/output.md | 2 +- src/content/contribute/plugin-patterns.md | 118 ++++++----- src/content/contribute/writing-a-plugin.md | 198 +++++++++++------- src/content/guides/build-performance.md | 40 ++-- src/content/guides/caching.md | 2 +- src/content/guides/installation.md | 3 +- src/content/plugins/html-webpack-plugin.md | 3 +- .../plugins/source-map-dev-tool-plugin.md | 2 +- src/content/plugins/split-chunks-plugin.md | 56 ++++- 16 files changed, 362 insertions(+), 209 deletions(-) diff --git a/src/content/api/cli.md b/src/content/api/cli.md index 032829ad0f96..7fd99d471b5f 100644 --- a/src/content/api/cli.md +++ b/src/content/api/cli.md @@ -217,11 +217,11 @@ Parameter | Explanation | Input type | D These options allow you to bind [modules](/configuration/module/) as allowed by webpack -Parameter | Explanation | Usage --------------------- | ---------------------------------- | ---------------- -`--module-bind` | Bind an extension to a loader | `--module-bind js=babel-loader` -`--module-bind-post` | Bind an extension to a post loader | -`--module-bind-pre` | Bind an extension to a pre loader | +Parameter | Explanation | Usage +-------------------- | -------------------------------------- | ---------------- +`--module-bind` | Bind a file extension to a loader | `--module-bind js=babel-loader` +`--module-bind-post` | Bind a file extension to a post loader | +`--module-bind-pre` | Bind a file extension to a pre loader | ### Watch Options diff --git a/src/content/concepts/dependency-graph.md b/src/content/concepts/dependency-graph.md index bebc98236083..acc65b2c0517 100644 --- a/src/content/concepts/dependency-graph.md +++ b/src/content/concepts/dependency-graph.md @@ -3,11 +3,17 @@ title: Dependency Graph sort: 9 contributors: - TheLarkInn + - EugeneHlushko +related: + - title: HTTP2 Aggresive Splitting Example + url: https://github.com/webpack/webpack/tree/master/examples/http2-aggressive-splitting + - title: webpack & HTTP/2 + url: https://medium.com/webpack/webpack-http-2-7083ec3f3ce6 --- Any time one file depends on another, webpack treats this as a _dependency_. This allows webpack to take non-code assets, such as images or web fonts, and also provide them as _dependencies_ for your application. When webpack processes your application, it starts from a list of modules defined on the command line or in its config file. -Starting from these _entry points_, webpack recursively builds a _dependency graph_ that includes every module your application needs, then packages all of those modules into a small number of _bundles_ - often, just one - to be loaded by the browser. +Starting from these [_entry points_](/concepts/entry-points/), webpack recursively builds a _dependency graph_ that includes every module your application needs, then bundles all of those modules into a small number of _bundles_ - often, just one - to be loaded by the browser. -T> Bundling your application is especially powerful for *HTTP/1.1* clients, as it minimizes the number of times your app has to wait while the browser starts a new request. For *HTTP/2*, you can also use Code Splitting and bundling through webpack for the [best optimization](https://medium.com/webpack/webpack-http-2-7083ec3f3ce6#.7y5d3hz59). +T> Bundling your application is especially powerful for _HTTP/1.1_ clients, as it minimizes the number of times your app has to wait while the browser starts a new request. For _HTTP/2_, you can also use [Code Splitting](/guides/code-splitting/) to achieve best results. diff --git a/src/content/concepts/entry-points.md b/src/content/concepts/entry-points.md index 0a6bbf0695ff..8aacddf83fa0 100644 --- a/src/content/concepts/entry-points.md +++ b/src/content/concepts/entry-points.md @@ -5,6 +5,7 @@ contributors: - TheLarkInn - chrisVillanueva - byzyk + - sokra --- As mentioned in [Getting Started](/guides/getting-started/#using-a-configuration), there are multiple ways to define the `entry` property in your webpack configuration. We will show you the ways you **can** configure the `entry` property, in addition to explaining why it may be useful to you. @@ -47,7 +48,7 @@ Usage: `entry: {[entryChunkName: string]: string|Array}` module.exports = { entry: { app: './src/app.js', - vendors: './src/vendors.js' + adminApp: './src/adminApp.js' } }; ``` @@ -61,26 +62,9 @@ T> **"Scalable webpack configurations"** are ones that can be reused and combine Below is a list of entry configurations and their real-world use cases: - ### Separate App and Vendor Entries -**webpack.config.js** - -```javascript -module.exports = { - entry: { - app: './src/app.js', - vendors: './src/vendors.js' - } -}; -``` - -**What does this do?** At face value, this tells webpack to create dependency graphs starting at both `app.js` and `vendors.js`. These graphs are completely separate and independent of each other (there will be a webpack bootstrap in each bundle). This is commonly seen with single page applications which have only one entry point (excluding vendors). - -**Why?** This setup allows you to leverage `CommonsChunkPlugin` and extract any vendor references from your app bundle into your vendor bundle, replacing them with `__webpack_require__()` calls. If there is no vendor code in your application bundle, then you can achieve a common pattern in webpack known as [long-term vendor-caching](/guides/caching). - -?> Consider removing this scenario in favor of the DllPlugin, which provides a better vendor-splitting. - +T> In webpack version < 4 it was common to add vendors as separate entrypoint to compile it as separate file (in combination with the `CommonsChunkPlugin`). This is discouraged in webpack 4. Instead the `optimization.splitChunks` option takes care of separating vendors and app modules and creating a separate file. **Do not** create a entry for vendors or other stuff which is not the starting point of execution. ### Multi Page Application @@ -100,6 +84,6 @@ module.exports = { **Why?** In a multi-page application, the server is going to fetch a new HTML document for you. The page reloads this new document and assets are redownloaded. However, this gives us the unique opportunity to do multiple things: -- Use `CommonsChunkPlugin` to create bundles of shared application code between each page. Multi-page applications that reuse a lot of code/modules between entry points can greatly benefit from these techniques, as the amount of entry points increase. +- Use `optimization.splitChunks` to create bundles of shared application code between each page. Multi-page applications that reuse a lot of code/modules between entry points can greatly benefit from these techniques, as the amount of entry points increase. T> As a rule of thumb: for each HTML document use exactly one entry point. diff --git a/src/content/concepts/index.md b/src/content/concepts/index.md index 493899e11fa9..6fa7a2a40560 100644 --- a/src/content/concepts/index.md +++ b/src/content/concepts/index.md @@ -14,22 +14,24 @@ contributors: - arjunsajeev - byzyk - yairhaimo + - EugeneHlushko --- -At its core, **webpack** is a _static module bundler_ for modern JavaScript applications. When webpack processes your application, it internally builds a _dependency graph_ which maps every module your project needs and generates one or more _bundles_. +At its core, __webpack__ is a _static module bundler_ for modern JavaScript applications. When webpack processes your application, it internally builds a [dependency graph](/concepts/dependency-graph/) which maps every module your project needs and generates one or more _bundles_. T> Learn more about JavaScript modules and webpack modules [here](/concepts/modules). -Since version 4.0.0, **webpack does not require a configuration file** to bundle your project, nevertheless it is [incredibly configurable](/configuration) to better fit your needs. +Since version 4.0.0, __webpack does not require a configuration file__ to bundle your project, nevertheless it is [incredibly configurable](/configuration) to better fit your needs. -To get started you only need to understand its **Core Concepts**: +To get started you only need to understand its __Core Concepts__: -- Entry -- Output -- Loaders -- Plugins +- [Entry](#entry) +- [Output](#output) +- [Loaders](#loaders) +- [Plugins](#plugins) +- [Mode](#mode) -This document is intended to give a **high-level** overview of these concepts, while providing links to detailed concept specific use cases. +This document is intended to give a __high-level__ overview of these concepts, while providing links to detailed concept specific use cases. For a better understanding of the ideas behind module bundlers and how they work under the hood consult these resources: @@ -40,9 +42,9 @@ For a better understanding of the ideas behind module bundlers and how they work ## Entry -An **entry point** indicates which module webpack should use to begin building out its internal *dependency graph*. webpack will figure out which other modules and libraries that entry point depends on (directly and indirectly). +An __entry point__ indicates which module webpack should use to begin building out its internal [dependency graph](/concepts/dependency-graph/). webpack will figure out which other modules and libraries that entry point depends on (directly and indirectly). -By default its value is `./src/index.js`, but you can specify a different (or multiple entry points) by configuring the **entry** property in the [webpack configuration](/configuration). For example: +By default its value is `./src/index.js`, but you can specify a different (or multiple entry points) by configuring the __entry__ property in the [webpack configuration](/configuration). For example: __webpack.config.js__ @@ -57,7 +59,7 @@ T> Learn more in the [entry points](/concepts/entry-points) section. ## Output -The **output** property tells webpack where to emit the *bundles* it creates and how to name these files. It defaults to `./dist/main.js` for the main output file and to the `./dist` folder for any other generated file. +The __output__ property tells webpack where to emit the *bundles* it creates and how to name these files. It defaults to `./dist/main.js` for the main output file and to the `./dist` folder for any other generated file. You can configure this part of the process by specifying an `output` field in your configuration: @@ -82,11 +84,11 @@ T> The `output` property has [many more configurable features](/configuration/ou ## Loaders -Out of the box, webpack only understands JavaScript files. **Loaders** allow webpack to process other types of files and convert them into valid [modules](/concepts/modules) that can be consumed by your application and added to the dependency graph. +Out of the box, webpack only understands JavaScript files. __Loaders__ allow webpack to process other types of files and convert them into valid [modules](/concepts/modules) that can be consumed by your application and added to the dependency graph. W> Note that the ability to `import` any type of module, e.g. `.css` files, is a feature specific to webpack and may not be supported by other bundlers or task runners. We feel this extension of the language is warranted as it allows developers to build a more accurate dependency graph. -At a high level, **loaders** have two properties in your webpack configuration: +At a high level, __loaders__ have two properties in your webpack configuration: 1. The `test` property identifies which file or files should be transformed. 2. The `use` property indicates which loader should be used to do the transforming. @@ -110,7 +112,7 @@ module.exports = { The configuration above has defined a `rules` property for a single module with two required properties: `test` and `use`. This tells webpack's compiler the following: -> "Hey webpack compiler, when you come across a path that resolves to a '.txt' file inside of a `require()`/`import` statement, **use** the `raw-loader` to transform it before you add it to the bundle." +> "Hey webpack compiler, when you come across a path that resolves to a '.txt' file inside of a `require()`/`import` statement, __use__ the `raw-loader` to transform it before you add it to the bundle." W> It is important to remember that when defining rules in your webpack config, you are defining them under `module.rules` and not `rules`. For your benefit, webpack will warn you if this is done incorrectly. @@ -125,7 +127,7 @@ T> Check out the [plugin interface](/api/plugins) and how to use it to extend we In order to use a plugin, you need to `require()` it and add it to the `plugins` array. Most plugins are customizable through options. Since you can use a plugin multiple times in a config for different purposes, you need to create an instance of it by calling it with the `new` operator. -**webpack.config.js** +__webpack.config.js__ ```javascript const HtmlWebpackPlugin = require('html-webpack-plugin'); //installed via npm diff --git a/src/content/concepts/manifest.md b/src/content/concepts/manifest.md index b675033b769f..9398f81f39b4 100644 --- a/src/content/concepts/manifest.md +++ b/src/content/concepts/manifest.md @@ -3,32 +3,33 @@ title: The Manifest sort: 10 contributors: - skipjack + - EugeneHlushko related: - title: Separating a Manifest url: https://survivejs.com/webpack/optimizing/separating-manifest/ - title: Predictable Long Term Caching with Webpack url: https://medium.com/webpack/predictable-long-term-caching-with-webpack-d3eee1d3fa31 - title: Caching - url: /guides/caching + url: /guides/caching/ --- In a typical application or site built with webpack, there are three main types of code: 1. The source code you, and maybe your team, have written. 2. Any third-party library or "vendor" code your source is dependent on. -3. A webpack runtime and _manifest_ that conducts the interaction of all modules. +3. A webpack runtime and __manifest__ that conducts the interaction of all modules. This article will focus on the last of these three parts, the runtime and in particular the manifest. ## Runtime -As mentioned above, we'll only briefly touch on this. The runtime, along with the manifest data, is basically all the code webpack needs to connect your modularized application while it's running in the browser. It contains the loading and resolving logic needed to connect your modules as they interact. This includes connecting modules that have already been loaded into the browser as well as logic to lazy-load the ones that haven't. +The runtime, along with the manifest data, is basically all the code webpack needs to connect your modularized application while it's running in the browser. It contains the loading and resolving logic needed to connect your modules as they interact. This includes connecting modules that have already been loaded into the browser as well as logic to lazy-load the ones that haven't. ## Manifest -So, once your application hits the browser in the form of an `index.html` file, some bundles, and a variety of other assets, what does it look like? That `/src` directory you meticulously laid out is now gone, so how does webpack manage the interaction between all of your modules? This is where the manifest data comes in... +Once your application hits the browser in the form of `index.html` file, some bundles and a variety of other assets required by your application must be loaded and linked somehow. That `/src` directory you meticulously laid out is now bundled, minified and maybe even splitted into smaller chunks for lazy-loading by webpack's [`optimization`](/configuration/optimization/). So how does webpack manage the interaction between all of your required modules? This is where the manifest data comes in... As the compiler enters, resolves, and maps out your application, it keeps detailed notes on all your modules. This collection of data is called the "Manifest" and it's what the runtime will use to resolve and load modules once they've been bundled and shipped to the browser. No matter which [module syntax](/api/module-methods) you have chosen, those `import` or `require` statements have now become `__webpack_require__` methods that point to module identifiers. Using the data in the manifest, the runtime will be able to find out where to retrieve the modules behind the identifiers. @@ -39,4 +40,4 @@ So now you have a little bit of insight about how webpack works behind the scene By using content hashes within your bundle file names, you can indicate to the browser when the contents of a file has changed thus invalidating the cache. Once you start doing this though, you'll immediately notice some funny behavior. Certain hashes change even when their contents apparently do not. This is caused by the injection of the runtime and manifest which changes every build. -See [the manifest section](/guides/output-management#the-manifest) of our _Managing Built Files_ guide to learn how to extract the manifest, and read the guides below to learn more about the intricacies of long term caching. +See [the manifest section](/guides/output-management/#the-manifest) of our _Output management_ guide to learn how to extract the manifest, and read the guides below to learn more about the intricacies of long term caching. diff --git a/src/content/configuration/externals.md b/src/content/configuration/externals.md index 856ad56a3d58..93523d7a6c53 100644 --- a/src/content/configuration/externals.md +++ b/src/content/configuration/externals.md @@ -7,6 +7,7 @@ contributors: - pksjce - fadysamirsadek - byzyk + - zefman --- The `externals` configuration option provides a way of excluding dependencies from the output bundles. Instead, the created bundle relies on that dependency to be present in the consumer's environment. This feature is typically most useful to __library developers__, however there are a variety of applications for it. @@ -148,5 +149,37 @@ module.exports = { In this case any dependency named `jQuery`, capitalized or not, or `$` would be externalized. +### Combining syntaxes + +Sometimes you may want to use a combination of the above syntaxes. This can be done in the following manner: + +```js +module.exports = { + //... + externals: [ + { + // String + react: 'react', + // Object + lodash : { + commonjs: 'lodash', + amd: 'lodash', + root: '_' // indicates global variable + }, + // Array + subtract: ['./math', 'subtract'] + }, + // Function + function(context, request, callback) { + if (/^yourregex$/.test(request)){ + return callback(null, 'commonjs ' + request); + } + callback(); + }, + // Regex + /^(jquery|\$)$/i + ] +}; +``` For more information on how to use this configuration, please refer to the article on [how to author a library](/guides/author-libraries). diff --git a/src/content/configuration/optimization.md b/src/content/configuration/optimization.md index f27abe3abf65..f8d1fa2da407 100644 --- a/src/content/configuration/optimization.md +++ b/src/content/configuration/optimization.md @@ -177,6 +177,33 @@ module.exports = { }; ``` +## `optimization.moduleIds` + +`bool: false` `string: natural, named, hashed, size, total-size` + +Tells webpack which algorithm to use when choosing module ids. Setting `optimization.moduleIds` to `false` tells webpack that none of built-in algorithms should be used, as custom one can be provided via plugin. By default `optimization.moduleIds` is set to `false`. + +The following string values are supported: + +Option | Description +--------------------- | ----------------------- +`natural` | Numeric ids in order of usage. +`named` | Readable ids for better debugging. +`hashed` | Short hashes as ids for better long term caching. +`size` | Numeric ids focused on minimal initial download size. +`total-size` | numeric ids focused on minimal total download size. + +__webpack.config.js__ + +```js +module.exports = { + //... + optimization: { + moduleIds: 'hashed' + } +}; +``` + ## `optimization.nodeEnv` `string` `bool: false` diff --git a/src/content/configuration/output.md b/src/content/configuration/output.md index da17b1065f85..2a667ff70e90 100644 --- a/src/content/configuration/output.md +++ b/src/content/configuration/output.md @@ -429,7 +429,7 @@ module.exports = { The variable `MyLibrary` will be bound with the return value of your entry file, if the resulting output is included as a script tag in an HTML page. -W> Note that if an `array` is provided as an `entry` point, only the last module in the array will be exposed. If an `object` is provided, it can exposed using an `array` syntax (see [this example](https://github.com/webpack/webpack/tree/master/examples/multi-part-library) for details). +W> Note that if an `array` is provided as an `entry` point, only the last module in the array will be exposed. If an `object` is provided, it can be exposed using an `array` syntax (see [this example](https://github.com/webpack/webpack/tree/master/examples/multi-part-library) for details). T> Read the [authoring libraries guide](/guides/author-libraries) guide for more information on `output.library` as well as `output.libraryTarget`. diff --git a/src/content/contribute/plugin-patterns.md b/src/content/contribute/plugin-patterns.md index 043f0e7d2954..e59013d4cc03 100644 --- a/src/content/contribute/plugin-patterns.md +++ b/src/content/contribute/plugin-patterns.md @@ -1,6 +1,8 @@ --- title: Plugin Patterns sort: 5 +contributors: + - nveenjain --- Plugins grant unlimited opportunity to perform customizations within the webpack build system. This allows you to create custom asset types, perform unique build modifications, or even enhance the webpack runtime while using middleware. The following are some features of webpack that become useful while writing plugins. @@ -10,63 +12,66 @@ Plugins grant unlimited opportunity to perform customizations within the webpack After a compilation is sealed, all structures within the compilation may be traversed. ```javascript -function MyPlugin() {} - -MyPlugin.prototype.apply = function(compiler) { - compiler.plugin('emit', function(compilation, callback) { - - // Explore each chunk (build output): - compilation.chunks.forEach(function(chunk) { - // Explore each module within the chunk (built inputs): - chunk.modules.forEach(function(module) { - // Explore each source file path that was included into the module: - module.fileDependencies.forEach(function(filepath) { - // we've learned a lot about the source structure now... +class MyPlugin { + apply(compiler) { + compiler.hooks.emit.tapAsync('MyPlugin', (compilation, callback) => { + // Explore each chunk (build output): + compilation.chunks.forEach(chunk => { + // Explore each module within the chunk (built inputs): + chunk.modules.forEach(module => { + // Explore each source file path that was included into the module: + module.fileDependencies.forEach(filepath => { + // we've learned a lot about the source structure now... + }); }); - }); - // Explore each asset filename generated by the chunk: - chunk.files.forEach(function(filename) { - // Get the asset source for each file generated by the chunk: - var source = compilation.assets[filename].source(); + // Explore each asset filename generated by the chunk: + chunk.files.forEach(filename => { + // Get the asset source for each file generated by the chunk: + var source = compilation.assets[filename].source(); + }); }); - }); - - callback(); - }); -}; + callback(); + }); + } +} module.exports = MyPlugin; ``` -- `compilation.modules`: An array of modules (built inputs) in the compilation. Each module manages the build of a raw file from your source library. -- `module.fileDependencies`: An array of source file paths included into a module. This includes the source JavaScript file itself (ex: `index.js`), and all dependency asset files (stylesheets, images, etc) that it has required. Reviewing dependencies is useful for seeing what source files belong to a module. -- `compilation.chunks`: An array of chunks (build outputs) in the compilation. Each chunk manages the composition of a final rendered assets. -- `chunk.modules`: An array of modules that are included into a chunk. By extension, you may look through each module's dependencies to see what raw source files fed into a chunk. -- `chunk.files`: An array of output filenames generated by the chunk. You may access these asset sources from the `compilation.assets` table. +* `compilation.modules`: An array of modules (built inputs) in the compilation. Each module manages the build of a raw file from your source library. +* `module.fileDependencies`: An array of source file paths included into a module. This includes the source JavaScript file itself (ex: `index.js`), and all dependency asset files (stylesheets, images, etc) that it has required. Reviewing dependencies is useful for seeing what source files belong to a module. +* `compilation.chunks`: An array of chunks (build outputs) in the compilation. Each chunk manages the composition of a final rendered assets. +* `chunk.modules`: An array of modules that are included into a chunk. By extension, you may look through each module's dependencies to see what raw source files fed into a chunk. +* `chunk.files`: An array of output filenames generated by the chunk. You may access these asset sources from the `compilation.assets` table. ### Monitoring the watch graph While running webpack middleware, each compilation includes a `fileDependencies` array (what files are being watched) and a `fileTimestamps` hash that maps watched file paths to a timestamp. These are extremely useful for detecting what files have changed within the compilation: ```javascript -function MyPlugin() { - this.startTime = Date.now(); - this.prevTimestamps = {}; +class MyPlugin { + constructor() { + this.startTime = Date.now(); + this.prevTimestamps = {}; + } + apply(compiler) { + compiler.hooks.emit.tapAsync('MyPlugin', (compilation, callback) => { + var changedFiles = Object.keys(compilation.fileTimestamps).filter( + watchfile => { + return ( + (this.prevTimestamps[watchfile] || this.startTime) < + (compilation.fileTimestamps[watchfile] || Infinity) + ); + } + ); + + this.prevTimestamps = compilation.fileTimestamps; + callback(); + }); + } } -MyPlugin.prototype.apply = function(compiler) { - compiler.plugin('emit', function(compilation, callback) { - - var changedFiles = Object.keys(compilation.fileTimestamps).filter(function(watchfile) { - return (this.prevTimestamps[watchfile] || this.startTime) < (compilation.fileTimestamps[watchfile] || Infinity); - }.bind(this)); - - this.prevTimestamps = compilation.fileTimestamps; - callback(); - }.bind(this)); -}; - module.exports = MyPlugin; ``` @@ -77,22 +82,21 @@ You may also feed new file paths into the watch graph to receive compilation tri Similar to the watch graph, it's fairly simple to monitor changed chunks (or modules, for that matter) within a compilation by tracking their hashes. ```javascript -function MyPlugin() { - this.chunkVersions = {}; +class MyPlugin { + constructor() { + this.chunkVersions = {}; + } + apply(compiler) { + compiler.hooks.emit.tapAsync('MyPlugin', (compilation, callback) => { + var changedChunks = compilation.chunks.filter(chunk => { + var oldVersion = this.chunkVersions[chunk.name]; + this.chunkVersions[chunk.name] = chunk.hash; + return chunk.hash !== oldVersion; + }); + callback(); + }); + } } -MyPlugin.prototype.apply = function(compiler) { - compiler.plugin('emit', function(compilation, callback) { - - var changedChunks = compilation.chunks.filter(function(chunk) { - var oldVersion = this.chunkVersions[chunk.name]; - this.chunkVersions[chunk.name] = chunk.hash; - return chunk.hash !== oldVersion; - }.bind(this)); - - callback(); - }.bind(this)); -}; - module.exports = MyPlugin; ``` diff --git a/src/content/contribute/writing-a-plugin.md b/src/content/contribute/writing-a-plugin.md index a3d6a22fa8dc..b71d8091d9ae 100644 --- a/src/content/contribute/writing-a-plugin.md +++ b/src/content/contribute/writing-a-plugin.md @@ -3,27 +3,32 @@ title: Writing a Plugin sort: 4 contributors: - tbroadley + - nveenjain - iamakulov - byzyk + - franjohn21 --- Plugins expose the full potential of the webpack engine to third-party developers. Using staged build callbacks, developers can introduce their own behaviors into the webpack build process. Building plugins is a bit more advanced than building loaders, because you'll need to understand some of the webpack low-level internals to hook into them. Be prepared to read some source code! ## Creating a Plugin -A plugin for `webpack` consists of a named JavaScript class that: +A plugin for webpack consists of -- Defines the `apply` method. -- Specifies an [event hook](/api/compiler-hooks/) on which to bind itself. -- Manipulates the build using the plugin API provided by webpack. +- A named JavaScript function. +- Defines `apply` method in its prototype. +- Specifies an [event hook](/api/compiler-hooks/) to tap into. +- Manipulates webpack internal instance specific data. +- Invokes webpack provided callback after functionality is complete. ```javascript +// A JavaScript class. class MyExampleWebpackPlugin { - // Define the `apply` method + // Define `apply` as it's prototype method which is supplied with compiler as it's argument apply(compiler) { // Specify the event hook to attach to compiler.hooks.compile.tapAsync( - 'afterCompile', + 'MyExampleWebpackPlugin', (compilation, callback) => { console.log('This is an example plugin!'); console.log('Here’s the `compilation` object which represents a single build of assets:', compilation); @@ -44,14 +49,11 @@ Plugins are instantiated objects with an `apply` method on their prototype. This ```javascript class HelloWorldPlugin { - constructor(options) { - this.options = options; - } - apply(compiler) { - compiler.hooks.done.tap('HelloWorldPlugin', () => { + compiler.hooks.done.tap('Hello World Plugin', ( + stats /* stats is passed as argument when done hook is tapped. */ + ) => { console.log('Hello World!'); - console.log(this.options); }); } } @@ -67,9 +69,7 @@ var HelloWorldPlugin = require('hello-world'); module.exports = { // ... config settings here ... - plugins: [ - new HelloWorldPlugin({setting: true}) - ] + plugins: [new HelloWorldPlugin({ options: true })] }; ``` @@ -77,27 +77,14 @@ module.exports = { Among the two most important resources while developing plugins are the `compiler` and `compilation` objects. Understanding their roles is an important first step in extending the webpack engine. -- The `compiler` object represents the fully configured webpack environment. This object is built once upon starting webpack, and is configured with all operational settings including options, loaders, and plugins. When applying a plugin to the webpack environment, the plugin will receive a reference to this compiler. Use the compiler to access the main webpack environment. - -- A `compilation` object represents a single build of versioned assets. While running webpack development middleware, a new compilation will be created each time a file change is detected, thus generating a new set of compiled assets. A compilation surfaces information about the present state of module resources, compiled assets, changed files, and watched dependencies. The compilation also provides many hooks at which a plugin can perform custom actions. - -These two components are an integral part of any webpack plugin (especially a `compilation`), so developers will benefit by familiarizing themselves with these source files: - -- [Compiler Source](https://github.com/webpack/webpack/blob/master/lib/Compiler.js) -- [Compilation Source](https://github.com/webpack/webpack/blob/master/lib/Compilation.js) - -## Accessing Compilation - -Compiler exposes a bunch of hooks that provide a reference to each new compilation. Compilations, in their turn, provide additional event hooks for tapping into steps within the build process. - ```javascript class HelloCompilationPlugin { apply(compiler) { - // Setup callback for accessing a compilation: - compiler.hooks.compilation.tap('HelloCompilationPlugin', (compilation) => { - // Now setup callbacks for accessing compilation steps: + // Tap into compilation hook which gives compilation as argument to the callback function + compiler.hooks.compilation.tap('HelloCompilationPlugin', compilation => { + // Now we can tap into various hooks available through compilation compilation.hooks.optimize.tap('HelloCompilationPlugin', () => { - console.log('Hello compilation!'); + console.log('Assets are being optimized.'); }); }); } @@ -110,31 +97,43 @@ The list of hooks available on the `compiler`, `compilation`, and other importan ## Async event hooks -Some event hooks are asynchronous. Apart from `tap`, they also have `tapAsync` and `tapPromise` methods. By tapping using these methods, you can do asynchronous actions inside hooks: +Some plugin hooks are asynchronous. To tap into them, we can use `tap` method which will behave in synchronous manner or use one of `tapAsync` method or `tapPromise` method which are asyncronous methods. + +### tapAsync + +When we use `tapAsync` method to tap into plugins, we need to call the callback function which is supplied as the last argument to our function. ```javascript class HelloAsyncPlugin { apply(compiler) { - // tapAsync() is callback-based - compiler.hooks.emit.tapAsync('HelloAsyncPlugin', function(compilation, callback) { + compiler.hooks.emit.tapAsync('HelloAsyncPlugin', (compilation, callback) => { + // Do something async... setTimeout(function() { console.log('Done with async work...'); callback(); }, 1000); }); + } +} - // tapPromise() is promise-based - compiler.hooks.emit.tapPromise('HelloAsyncPlugin', (compilation) => { - return doSomethingAsync() - .then(() => { - console.log('Done with async work...'); - }); - }); +module.exports = HelloAsyncPlugin; +``` + +#### tapPromise + +When we use `tapPromise` method to tap into plugins, we need to return a promise which resolves when our asynchronous task is completed. - // Plain old tap() is still here: - compiler.hooks.emit.tap('HelloAsyncPlugin', () => { - // No async work here - console.log('Done with sync work...'); +```javascript +class HelloAsyncPlugin { + apply(compiler) { + compiler.hooks.emit.tapPromise('HelloAsyncPlugin', compilation => { + // return a Promise that resolves when we are done... + return new Promise((resolve, reject) => { + setTimeout(function() { + console.log('Done with async work...'); + resolve(); + }, 1000); + }); }); } } @@ -151,22 +150,23 @@ Let's write a simple example plugin that generates a new build file called `file ```javascript class FileListPlugin { apply(compiler) { - compiler.hooks.emit.tapAsync('FileListPlugin', (compilation, callback) => { + // emit is asynchronous hook, tapping into it using tapAsync, you can use tapPromise/tap(synchronous) as well + compiler.hooks.emit.tapAsync('FileListPlugin', (compiler, callback) => { // Create a header string for the generated file: var filelist = 'In this build:\n\n'; // Loop through all compiled assets, // adding a new line item for each filename. for (var filename in compilation.assets) { - filelist += ('- '+ filename +'\n'); + filelist += '- ' + filename + '\n'; } // Insert this list into the webpack build as a new file asset: compilation.assets['filelist.md'] = { - source() { + source: function() { return filelist; }, - size() { + size: function() { return filelist.length; } }; @@ -179,33 +179,85 @@ class FileListPlugin { module.exports = FileListPlugin; ``` -## Under the hood +## Different Plugin Shapes + +A plugin can be classified into types based on the event hooks it taps into. Every event hook is pre-defined as synchronous or asynchronous or waterfall or parallel hook and hook is called internally using call/callAsync method. The list of hooks that are supported or can be tapped into are generally specified in this.hooks property. -Under the hood, webpack uses [Tapable](https://github.com/webpack/tapable) to create and run hooks. This is how it looks: +For example:- ```javascript -import { SyncHook, AsyncSeriesHook } from 'tapable'; - -class SomeWebpackInternalClass { - constructor() { - this.hooks = { - // Create hooks: - compilation: new SyncHook(), - run: new AsyncSeriesHook(), - }; - } +this.hooks = { + shouldEmit: new SyncBailHook(['compilation']) +}; +``` + +It represents that the only hook supported is `shouldEmit` which is a hook of `SyncBailHook` type and the only parameter which will be passed to any plugin that taps into `shouldEmit` hook is `compilation`. + +Various types of hooks supported are :- + +### Synchronous Hooks + +- **SyncHook** + + - Defined as `new SyncHook([params])` + - Tapped into using `tap` method. + - Called using `call(...params)` method. + +- **Bail Hooks** + + - Defined using `SyncBailHook[params]` + - Tapped into using `tap` method. + - Called using `call(...params)` method. + + In these type of hooks, each of the plugin callbacks will be invoked one after the other with the specific `args`. If any value is returned except undefined by any plugin, then that value is returned by hook and no further plugin callback is invoked. Many useful events like `optimizeChunks`, `optimizeChunkModules` are SyncBailHooks. + +- **Waterfall Hooks** + + - Defined using `SyncWaterfallHook[params]` + - Tapped into using `tap` method. + - Called using `call( ... params)` method + + Here each of the plugins are called one after the other with the arguments from the return value of the previous plugin. The plugin must take the order of its execution into account. + It must accept arguments from the previous plugin that was executed. The value for the first plugin is `init`. Hence atleast 1 param must be supplied for waterfall hooks. This pattern is used in the Tapable instances which are related to the webpack templates like `ModuleTemplate`, `ChunkTemplate` etc. + +### Asynchronous Hooks + +- **Async Series Hook** + + - Defined using `AsyncSeriesHook[params]` + - Tapped into using `tap`/`tapAsync`/`tapPromise` method. + - Called using `callAsync( ... params)` method + + The plugin handler functions are called with all arguments and a callback function with the signature `(err?: Error) -> void`. The handler functions are called in order of registration. `callback` is called after all the handlers are called. + This is also a commonly used pattern for events like `emit`, `run`. + +- **Async waterfall** The plugins will be applied asynchronously in the waterfall manner. + + - Defined using `AsyncWaterfallHook[params]` + - Tapped into using `tap`/`tapAsync`/`tapPromise` method. + - Called using `callAsync( ... params)` method + + The plugin handler functions are called with the current value and a callback function with the signature `(err: Error, nextValue: any) -> void.` When called `nextValue` is the current value for the next handler. The current value for the first handler is `init`. After all handlers are applied, callback is called with the last value. If any handler passes a value for `err`, the callback is called with this error and no more handlers are called. + This plugin pattern is expected for events like `before-resolve` and `after-resolve`. + +- **Async Series Bail** + + - Defined using `AsyncSeriesBailHook[params]` + - Tapped into using `tap`/`tapAsync`/`tapPromise` method. + - Called using `callAsync( ... params)` method someMethod() { - // Call a hook: - this.hooks.compilation.call(); + // Call a hook: + this.hooks.compilation.call(); - // Call another hook: - // (This is an async one, so webpack passes a callback into it) - this.hooks.run.callAsync(() => { - // The callback is called when all tapped functions finish executing - }); - } -} -``` +- **Async Parallel** + + - Defined using `AsyncParallelHook[params]` + - Tapped into using `tap`/`tapAsync`/`tapPromise` method. + - Called using `callAsync( ... params)` method + +- **Async Series Bail** -There’re multiple types of hooks which run tapped functions a bit differently. They are described [in the Tapable docs](https://github.com/webpack/tapable#hook-types). + - Defined using `AsyncSeriesBailHook[params]` + - Tapped into using `tap`/`tapAsync`/`tapPromise` method. + - Called using `callAsync( ... params)` method diff --git a/src/content/guides/build-performance.md b/src/content/guides/build-performance.md index 1ee98d336018..6d8d8499ede5 100644 --- a/src/content/guides/build-performance.md +++ b/src/content/guides/build-performance.md @@ -14,7 +14,7 @@ This guide contains some useful tips for improving build/compilation performance ## General -The following best practices should help whether or not you are in [development](/guides/development) or building for [production](/guides/production). +The following best practices should help, whether you're running build scripts in [development](/guides/development) or [production](/guides/production). ### Stay Up to Date @@ -23,7 +23,7 @@ Use the latest webpack version. We are always making performance improvements. T [![latest webpack version](https://img.shields.io/npm/v/webpack.svg?label=webpack&style=flat-square&maxAge=3600)](https://github.com/webpack/webpack/releases) -Staying up to date with __Node.js__ can also help with performance. On top of this, keeping your package manager (e.g. `npm` or `yarn`) up to date can also help. Newer versions create more efficient module trees and increase resolving speed. +Staying up-to-date with __Node.js__ can also help with performance. On top of this, keeping your package manager (e.g. `npm` or `yarn`) up-to-date can also help. Newer versions create more efficient module trees and increase resolving speed. ### Loaders @@ -64,14 +64,14 @@ module.exports = { ### Bootstrap -Each additional loader/plugin has a bootup time. Try to use as few different tools as possible. +Each additional loader/plugin has a bootup time. Try to use as few tools as possible. ### Resolving -The following steps can increase the speed of resolving: +The following steps can increase resolving speed: -- Minimize the number of items in `resolve.modules`, `resolve.extensions`, `resolve.mainFiles`, `resolve.descriptionFiles` as they increase the number of filesystem calls. +- Minimize the number of items in `resolve.modules`, `resolve.extensions`, `resolve.mainFiles`, `resolve.descriptionFiles`, as they increase the number of filesystem calls. - Set `resolve.symlinks: false` if you don't use symlinks (e.g. `npm link` or `yarn link`). - Set `resolve.cacheWithContext: false` if you use custom resolving plugins, that are not context specific. @@ -96,7 +96,7 @@ Decrease the total size of the compilation to increase build performance. Try to The `thread-loader` can be used to offload expensive loaders to a worker pool. -W> Don't use too many workers as there is a boot overhead for the Node.js runtime and the loader. Minimize the module transfers between worker and main process. IPC is expensive. +W> Don't use too many workers, as there is a boot overhead for the Node.js runtime and the loader. Minimize the module transfers between worker and main process. IPC is expensive. ### Persistent cache @@ -118,9 +118,9 @@ The following steps are especially useful in _development_. ### Incremental Builds -Use webpack's watch mode. Don't use other tools to watch your files and invoke webpack. The built in watch mode will keep track of timestamps and passes this information to the compilation for cache invalidation. +Use webpack's watch mode. Don't use other tools to watch your files and invoke webpack. The built-in watch mode will keep track of timestamps and passes this information to the compilation for cache invalidation. -In some setups watching falls back to polling mode. With many watched files this can cause a lot of CPU load. In these cases you can increase the polling interval with `watchOptions.poll`. +In some setups, watching falls back to polling mode. With many watched files, this can cause a lot of CPU load. In these cases, you can increase the polling interval with `watchOptions.poll`. ### Compile in Memory @@ -143,12 +143,12 @@ Be aware of the performance differences of the different `devtool` settings. - The `cheap-source-map` variants are more performant, if you can live with the slightly worse mapping quality. - Use a `eval-source-map` variant for incremental builds. -=> In most cases `cheap-module-eval-source-map` is the best option. +=> In most cases, `cheap-module-eval-source-map` is the best option. ### Avoid Production Specific Tooling -Certain utilities, plugins and loader only make sense when building for production. For example, it usually doesn't make sense to minify and mangle your code with the `UglifyJsPlugin` while in development. These tools should typically be excluded in development: +Certain utilities, plugins, and loaders only make sense when building for production. For example, it usually doesn't make sense to minify and mangle your code with the `UglifyJsPlugin` while in development. These tools should typically be excluded in development: - `UglifyJsPlugin` - `ExtractTextPlugin` @@ -160,7 +160,7 @@ Certain utilities, plugins and loader only make sense when building for producti ### Minimal Entry Chunk -webpack only emits updated chunks to the filesystem. For some configuration options (HMR, `[name]`/`[chunkhash]` in `output.chunkFilename`, `[hash]`) the entry chunk is invalidated in addition to the changed chunks. +webpack only emits updated chunks to the filesystem. For some configuration options, (HMR, `[name]`/`[chunkhash]` in `output.chunkFilename`, `[hash]`) the entry chunk is invalidated in addition to the changed chunks. Make sure the entry chunk is cheap to emit by keeping it small. The following code block extracts a chunk containing only the runtime with _all other chunks as children_: @@ -201,11 +201,11 @@ module.exports = { ### Node.js Version -There has been a [performance regression](https://github.com/nodejs/node/issues/19769) in the latest stable versions of Node.js and its ES2015 `Map` and `Set` implementations. A fix has been merged in master, but a release has yet to be made. In the meantime, to get the most out of incremental build speeds, try to stick with version 8.9.x (problem exists between 8.9.10 - 9.11.1). webpack has moved to using those ES2015 data structures liberally, and it will improve the initial build times as well. +There has been a [performance regression](https://github.com/nodejs/node/issues/19769) in the latest stable versions of Node.js and its ES2015 `Map` and `Set` implementations. A fix has been merged into master, but a release has yet to be made. In the meantime, to get the most out of incremental build speeds, try to stick with version 8.9.x (the problem exists between 8.9.10 - 9.11.1). webpack has moved to using those ES2015 data structures liberally, and it will improve the initial build times as well. ### TypeScript Loader -Recently, `ts-loader` has started to consume the internal TypeScript watch mode APIs which dramatically decreases the number of modules to be rebuilt on each iteration. This `experimentalWatchApi` shares the same logic as the normal TypeScript watch mode itself and is quite stable for development use. Turn on `transpileOnly` as well for truly fast incremental builds. +Recently, `ts-loader` has started to consume the internal TypeScript watch mode APIs which dramatically decreases the number of modules to be rebuilt on each iteration. This `experimentalWatchApi` shares the same logic as the normal TypeScript watch mode itself and is quite stable for development use. Turn on `transpileOnly`, as well, for even faster incremental builds. ```js module.exports = { @@ -227,7 +227,7 @@ Note: the `ts-loader` documentation suggests the use of `cache-loader`, but this To gain typechecking again, use the [`ForkTsCheckerWebpackPlugin`](https://www.npmjs.com/package/fork-ts-checker-webpack-plugin). -There is a [full example](https://github.com/TypeStrong/ts-loader/tree/master/examples/fast-incremental-builds) on the ts-loader github repository +There is a [full example](https://github.com/TypeStrong/ts-loader/tree/master/examples/fast-incremental-builds) on the ts-loader github repository. --- @@ -236,14 +236,14 @@ There is a [full example](https://github.com/TypeStrong/ts-loader/tree/master/ex The following steps are especially useful in _production_. -W> __Don't sacrifice the quality of your application for small performance gains!__ Keep in mind that optimization quality is in most cases more important than build performance. +W> __Don't sacrifice the quality of your application for small performance gains!__ Keep in mind that optimization quality is, in most cases, more important than build performance. ### Multiple Compilations -When using multiple compilations the following tools can help: +When using multiple compilations, the following tools can help: -- [`parallel-webpack`](https://github.com/trivago/parallel-webpack): It allows to do compilation in a worker pool. +- [`parallel-webpack`](https://github.com/trivago/parallel-webpack): It allows for compilation in a worker pool. - `cache-loader`: The cache can be shared between multiple compilations. @@ -256,7 +256,7 @@ Source maps are really expensive. Do you really need them? ## Specific Tooling Issues -The following tools have certain problems that can degrade build performance. +The following tools have certain problems that can degrade build performance: ### Babel @@ -266,8 +266,8 @@ The following tools have certain problems that can degrade build performance. ### TypeScript -- Use the `fork-ts-checker-webpack-plugin` for type checking in a separate process. -- Configure loaders to skip type checking. +- Use the `fork-ts-checker-webpack-plugin` for typechecking in a separate process. +- Configure loaders to skip typechecking. - Use the `ts-loader` in `happyPackMode: true` / `transpileOnly: true`. diff --git a/src/content/guides/caching.md b/src/content/guides/caching.md index 2568bccae18d..51f72e131348 100644 --- a/src/content/guides/caching.md +++ b/src/content/guides/caching.md @@ -282,7 +282,7 @@ __webpack.config.js__ ``` diff const path = require('path'); - const webpack = require('webpack'); ++ const webpack = require('webpack'); const CleanWebpackPlugin = require('clean-webpack-plugin'); const HtmlWebpackPlugin = require('html-webpack-plugin'); diff --git a/src/content/guides/installation.md b/src/content/guides/installation.md index 663af022c76a..e65466b676ce 100644 --- a/src/content/guides/installation.md +++ b/src/content/guides/installation.md @@ -6,12 +6,13 @@ contributors: - bebraw - simon04 - EugeneHlushko + - sibiraj-s --- This guide goes through the various methods used to install webpack. -## Pre-requisites +## Prerequisites Before we begin, make sure you have a fresh version of [Node.js](https://nodejs.org/en/) installed. The current Long Term Support (LTS) release is an ideal starting point. You may run into a variety of issues with the older versions as they may be missing functionality webpack and/or its related packages require. diff --git a/src/content/plugins/html-webpack-plugin.md b/src/content/plugins/html-webpack-plugin.md index c61d32d062c8..0d4f01884b20 100644 --- a/src/content/plugins/html-webpack-plugin.md +++ b/src/content/plugins/html-webpack-plugin.md @@ -3,6 +3,7 @@ title: HtmlWebpackPlugin contributors: - ampedandwired - simon04 + - Sibiraj-S --- The [`HtmlWebpackPlugin`](https://github.com/jantimon/html-webpack-plugin) simplifies creation of HTML files to serve your webpack bundles. This is especially useful for webpack bundles that include a hash in the filename which changes every compilation. You can either let the plugin generate an HTML file for you, supply your own template using [lodash templates](https://lodash.com/docs#template), or use your own [loader](/loaders). @@ -65,4 +66,4 @@ For all configuration options, please see the [plugin documentation](https://git ## Third party addons -The plugin supports addons. For a list see the [documentation](https://github.com/jantimon/html-webpack-plugin#third-party-addons). +The plugin supports addons. For a list see the [documentation](https://github.com/jantimon/html-webpack-plugin#plugins). diff --git a/src/content/plugins/source-map-dev-tool-plugin.md b/src/content/plugins/source-map-dev-tool-plugin.md index e9141318bb9f..5ff23f8e1f3f 100644 --- a/src/content/plugins/source-map-dev-tool-plugin.md +++ b/src/content/plugins/source-map-dev-tool-plugin.md @@ -21,7 +21,7 @@ new webpack.SourceMapDevToolPlugin(options); The following options are supported: -- `test` (`string|regex|array`): Include source maps for modules based on their extension (defaults to `.js` and `.css`). +- `test` (`string|regex|array`): Include source maps for modules based on their extension (defaults to `.js`, `.mjs`, and `.css`). - `include` (`string|regex|array`): Include source maps for module paths that match the given value. - `exclude` (`string|regex|array`): Exclude modules that match the given value from source map generation. - `filename` (`string`): Defines the output filename of the SourceMap (will be inlined if no value is provided). diff --git a/src/content/plugins/split-chunks-plugin.md b/src/content/plugins/split-chunks-plugin.md index 50f667543c80..9b679969205a 100644 --- a/src/content/plugins/split-chunks-plugin.md +++ b/src/content/plugins/split-chunks-plugin.md @@ -7,7 +7,9 @@ contributors: - chrisdothtml - EugeneHlushko - byzyk + - jacobangel - madhavarshney + - sakhisheikh related: - title: webpack's automatic deduplication algorithm example url: https://github.com/webpack/webpack/blob/master/examples/many-pages/README.md @@ -22,9 +24,9 @@ Since webpack v4, the `CommonsChunkPlugin` was removed in favor of `optimization ## Defaults -Out of the box `SplitChunksPlugin` should work great for most users. +Out of the box `SplitChunksPlugin` should work well for most users. -By default it only affects on-demand chunks because changing initial chunks would affect the script tags the HTML file should include to run the project. +By default it only affects on-demand chunks, because changing initial chunks would affect the script tags the HTML file should include to run the project. webpack will automatically split chunks based on these conditions: @@ -37,9 +39,9 @@ When trying to fulfill the last two conditions, bigger chunks are preferred. ## Configuration -For developers that want to have more control over this functionality, webpack provides a set of options to better fit your needs. If you're changing the configuration, it's a good idea to measure the impact of your changes to ensure there's a real benefit. +webpack provides a set of options for developers that want more control over this functionality. -W> Default configuration was chosen to fit web performance best practices but the optimum strategy for your project might defer depending on the nature of it. +W> The default configuration was chosen to fit web performance best practices, but the optimal strategy for your project might differ. If you're changing the configuration, you should measure the impact of your changes to ensure there's a real benefit. ## `optimization.splitChunks` @@ -85,7 +87,7 @@ By default webpack will generate names using origin and name of the chunk (e.g. `function` `string` -This indicates which chunks will be selected for optimization. If a string is provided, possible values are `all`, `async`, and `initial`. Providing `all` can be particularly powerful because it means that chunks can be shared even between async and non-async chunks. +This indicates which chunks will be selected for optimization. When a string is provided, valid values are `all`, `async`, and `initial`. Providing `all` can be particularly powerful, because it means that chunks can be shared even between async and non-async chunks. ```js module.exports = { @@ -99,7 +101,7 @@ module.exports = { }; ``` -Alternatively, you can provide a function for more control. The return value will indicate whether to include each chunk. +Alternatively, you may provide a function for more control. The return value will indicate whether to include each chunk. ```js module.exports = { @@ -199,12 +201,27 @@ module.exports = { A module can belong to multiple cache groups. The optimization will prefer the cache group with a higher `priority`. The default groups have a negative priority to allow custom groups to take higher priority (default value is `0` for custom groups). -#### `splitChunks.cacheGroups.reuseExistingChunk` +#### `splitChunks.cacheGroups.{cacheGroup}.reuseExistingChunk` `boolean` If the current chunk contains modules already split out from the main bundle, it will be reused instead of a new one being generated. This can impact the resulting file name of the chunk. +```js +module.exports = { + //... + optimization: { + splitChunks: { + cacheGroups: { + vendors: { + reuseExistingChunk: true + } + } + } + } +}; +``` + #### `splitChunks.cacheGroups.test` `function` `RegExp` `string` @@ -344,3 +361,28 @@ module.exports = { ``` W> This might result in a large chunk containing all external packages. It is recommended to only include your core frameworks and utilities and dynamically load the rest of the dependencies. + +### Split Chunks: Example 3 + + Create a `custom vendor` chunk, which contains certain `node_modules` packages matched by `RegExp`. + + __webpack.config.js__ + +```js +module.exports = { + //... + optimization: { + splitChunks: { + cacheGroups: { + vendor: { + test: /[\\/]node_modules[\\/](react|react-dom)[\\/]/, + name: 'vendor', + chunks: 'all', + } + } + } + } +}; +``` + +T> This will result in splitting `react` and `react-dom` into a separate chunk. If you're not sure what packages have been included in a chunk you may refer to [Bundle Analysis](/guides/code-splitting/#bundle-analysis) section for details.