diff --git a/src/content/api/cli.md b/src/content/api/cli.md index fcc6699a707a..dfcdb6317f08 100644 --- a/src/content/api/cli.md +++ b/src/content/api/cli.md @@ -8,6 +8,7 @@ contributors: - chenxsan - rencire - madhavarshney + - EugeneHlushko related: - title: Analyzing Build Statistics url: https://survivejs.com/webpack/optimizing-build/analyzing-build-statistics/ @@ -23,11 +24,6 @@ related: For proper usage and easy distribution of this configuration, webpack can be configured with `webpack.config.js`. Any parameters sent to the CLI will map to a corresponding parameter in the config file. -Users have a choice between two CLI packages: - -* [webpack-cli](https://github.com/webpack/webpack-cli): the original webpack full-featured CLI. -* [webpack-command](https://github.com/webpack-contrib/webpack-command): the lightweight, opinionated and modern CLI. - Read the [installation guide](/guides/installation) if you don't already have webpack and CLI installed. @@ -221,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/api/plugins.md b/src/content/api/plugins.md index 415cd948bb4c..a348957cdee9 100644 --- a/src/content/api/plugins.md +++ b/src/content/api/plugins.md @@ -99,6 +99,38 @@ compiler.hooks.myCustomHook.call(a, b, c); Again, see the [documentation](https://github.com/webpack/tapable) for `tapable` to learn more about the different hook classes and how they work. +## Reporting Progress + +Plugins can report progress via [`ProgressPlugin`](/plugins/progress-plugin/), which prints progress messages to stderr by default. In order to enable progress reporting, pass a `--progress` argument when running the [webpack CLI](/api/cli/). + +It is possible to customize the printed output by passing different arguments to the `reportProgress` function of [`ProgressPlugin`](/plugins/progress-plugin/). + +To report progress, a plugin must `tap` into a hook using the `context: true` option: + +```js +compiler.hooks.emit.tapAsync({ + name: 'MyPlugin', + context: true +}, (context, compiler, callback) => { + const reportProgress = context && context.reportProgress; + if (reportProgress) reportProgress(0.95, 'Starting work'); + setTimeout(() => { + if (reportProgress) reportProgress(0.95, 'Done work'); + callback(); + }, 1000); +}); +``` + +The `reportProgress` function may be called with these arguments: + +```js +reportProgress(percentage, ...args); +``` + +* `percentage`: This argument is unused; instead, [`ProgressPlugin`](/plugins/progress-plugin/) will calculate a percentage based on the current hook. +* `...args`: Any number of strings, which will be passed to the `ProgressPlugin` handler to be reported to the user. + +Note that only a subset of compiler and compilation hooks support the `reportProgress` function. See [`ProgressPlugin`](/plugins/progress-plugin/#supported-hooks) for a full list. ## Next Steps 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/hot-module-replacement.md b/src/content/concepts/hot-module-replacement.md index 354142daa16e..c046f67d4927 100644 --- a/src/content/concepts/hot-module-replacement.md +++ b/src/content/concepts/hot-module-replacement.md @@ -2,6 +2,7 @@ title: Hot Module Replacement sort: 11 contributors: + - kryptokinght - SpaceK33z - sokra - GRardB @@ -13,7 +14,7 @@ Hot Module Replacement (HMR) exchanges, adds, or removes [modules](/concepts/mod - Retain application state which is lost during a full reload. - Save valuable development time by only updating what's changed. -- Tweak styling faster -- almost comparable to changing styles in the browser's debugger. +- Modifications made to CSS/JS in the source code results in an instant browser update which is almost comparable to changing styles directly in the browser's dev tools. ## How It Works diff --git a/src/content/concepts/index.md b/src/content/concepts/index.md index d3cf10af141a..df773a0dcb87 100644 --- a/src/content/concepts/index.md +++ b/src/content/concepts/index.md @@ -14,22 +14,25 @@ contributors: - arjunsajeev - byzyk - yairhaimo + - EugeneHlushko + - farskid --- -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 +43,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 +60,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 +85,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 and JSON 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 +113,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 +128,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/loaders.md b/src/content/concepts/loaders.md index 1fc1e556e511..d1d4523e9667 100644 --- a/src/content/concepts/loaders.md +++ b/src/content/concepts/loaders.md @@ -10,6 +10,7 @@ contributors: - simon04 - jhnns - byzyk + - debs-obrien --- Loaders are transformations that are applied on the source code of a module. They allow you to pre-process files as you `import` or “load” them. Thus, loaders are kind of like “tasks” in other build tools and provide a powerful way to handle front-end build steps. Loaders can transform files from a different language (like TypeScript) to JavaScript or inline images as data URLs. Loaders even allow you to do things like `import` CSS files directly from your JavaScript modules! @@ -121,6 +122,6 @@ functions (loaders). Users now have more flexibility to include fine-grained log ## Resolving Loaders -Loaders follow the standard [module resolution](/concepts/module-resolution/). In most cases it will be loaders from the [module path](/concepts/module-resolution/#module-paths) (think `npm install`, `node_modules`). +Loaders follow the standard [module resolution](/concepts/module-resolution/). In most cases it will be loaded from the [module path](/concepts/module-resolution/#module-paths) (think `npm install`, `node_modules`). A loader module is expected to export a function and be written in Node.js compatible JavaScript. They are most commonly managed with npm, but you can also have custom loaders as files within your application. By convention, loaders are usually named `xxx-loader` (e.g. `json-loader`). See ["How to Write a Loader?"](/development/how-to-write-a-loader) for more information. 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/concepts/targets.md b/src/content/concepts/targets.md index cea4b6aaf659..1ae5cb6a8d43 100644 --- a/src/content/concepts/targets.md +++ b/src/content/concepts/targets.md @@ -11,7 +11,7 @@ contributors: Because JavaScript can be written for both server and browser, webpack offers multiple deployment _targets_ that you can set in your webpack [configuration](/configuration). -W> The webpack `target` property is not to be confused with the `output.libraryTarget` property. For more information see [our guide](/concepts/output) on the `output` property. +W> The webpack `target` property is not to be confused with the `output.libraryTarget` property. For more information see [our guide](/concepts/output/) on the `output` property. ## Usage @@ -27,7 +27,7 @@ module.exports = { In the example above, using `node` webpack will compile for usage in a Node.js-like environment (uses Node.js `require` to load chunks and not touch any built in modules like `fs` or `path`). -Each _target_ has a variety of deployment/environment specific additions, support to fit its needs. See what [targets are available](/configuration/target). +Each _target_ has a variety of deployment/environment specific additions, support to fit its needs. See what [targets are available](/configuration/target/). ?>Further expansion for other popular target values diff --git a/src/content/concepts/why-webpack.md b/src/content/concepts/why-webpack.md new file mode 100644 index 000000000000..19866fae3779 --- /dev/null +++ b/src/content/concepts/why-webpack.md @@ -0,0 +1,54 @@ +--- +title: Why webpack +sort: 7 +contributors: +- debs-obrien +- montogeek +- jeremenichelli +- EugeneHlushko +--- + +To understand why you should use webpack lets do a recap of how we use JavaScript on the web before bundlers were a thing. + +There are two ways to run JavaScript in a browser. First, include a script for each functionality you want to implement, the issue is that the solution is hard to scale as loading too many scripts causes a network bottleneck. The other alternative is to load a big .js file containing all your project code, but this results in an unmaintainable scripts that causes problems in scope, size, readability, fragility and monolith files. + + +## IIFE's - Immediately invoked function expressions + +IIFEs solve scoping issues for large projects. When script files are wrapped by an IIFE, you can safely concatenate or safely combine files without concern of scope collision. + +This lead to tools like Make, Gulp, Grunt, Broccoli or Brunch. These tools are known as task runners and they are used, among with other purposes, to concatenate all your project files together in order to solve some of the issues mentioned before. + +However, anytime you want to change one file you have to rebuild the whole thing. Concatenating makes it trivial to reuse scripts across files and makes build optimizations more difficult to implement. How do you even know what code is being used and which is not? + +If you are only using one function from lodash or one date utility from moment.js you are actually adding the entire library and just squishing it together. How do you treeshake the dependencies on your code? Also, lazy loading chunks of code can be hard to achieve at scale and requires a lot of manual work from the developer. + + +## Birth of JavaScript Modules happened thanks to Node.js + +webpack runs on Node.js, a JavaScript runtime that can be used in computers and servers outside a browser environment. + +When Node.js was released a new era started, and it came with new challenges. Now that JavaScript is not running in a browser, how are Node applications supposed to load new chunks of code? There is no html files and scripts tags that can be added to it. + +CommonJS came out and introduced `require`, which allows you to load and use a module in the current file. This solves scope issues out of the box and which code is used becomes clear since we need to import each module that we are going to need. + + +## npm + Node.js + modules -- mass distribution + +JavaScript is taking over the world as a language, as a platform and as a way to rapidly develop and create fast running applications. + +But there is no browser support for CommonJS. There are no [live bindings](https://medium.com/webpack/the-state-of-javascript-modules-4636d1774358). There are problems with circular references. Sync module resolution loader is slow. While CommonJS was a great solution for Node.js projects, browsers didn't support modules. That's when bundlers and tools like Browserify, RequireJS and SystemJS were created to solve this limitation making it possible to write CommonJS modules that run in a browser. + + +## ESM - ECMAScript Modules + +The good news for web projects is that modules are becoming an official feature in ECMAScript standard, though browser support is still short and early implementations show that bundling is still faster and recommended today. + + +## Wouldn't it be nice… + +...to have something that will not only let us write modules but also support any module format (at least until we get to ESM) and that can handle resources and assets at the same time. + +This is why webpack exists. It's a tool that not only let's you bundle your JavaScript applications, supporting both ESM and CommonJS, but can be extended to support all different kind of assets like images, fonts and stylesheets. + +webpack cares a lot about performance and it's always adding and improving features like async chunk loading and prefetching to help you deliver the best possible version of your project to the user, always caring about loading times and performance. diff --git a/src/content/configuration/dev-server.md b/src/content/configuration/dev-server.md index d0740a33ba6d..d61215b56aca 100644 --- a/src/content/configuration/dev-server.md +++ b/src/content/configuration/dev-server.md @@ -24,6 +24,8 @@ T> Options that are compatible with [webpack-dev-middleware](https://github.com/ This set of options is picked up by [webpack-dev-server](https://github.com/webpack/webpack-dev-server) and can be used to change its behavior in various ways. Here's a simple example that gzips and serves everything from our `dist/` directory: ```js +var path = require('path'); + module.exports = { //... devServer: { @@ -730,7 +732,7 @@ webpack-dev-server --port 8080 Proxying some URLs can be useful when you have a separate API backend development server and you want to send API requests on the same domain. -The dev-server makes use of the powerful [http-proxy-middleware](https://github.com/chimurai/http-proxy-middleware) package. Checkout its [documentation](https://github.com/chimurai/http-proxy-middleware#options) for more advanced usages. +The dev-server makes use of the powerful [http-proxy-middleware](https://github.com/chimurai/http-proxy-middleware) package. Check out its [documentation](https://github.com/chimurai/http-proxy-middleware#options) for more advanced usages. Note that some of `http-proxy-middleware`'s features do not require a `target` key, e.g. its `router` feature, but you will still need to include a `target` key in your config here, otherwise `webpack-dev-server` won't pass it along to `http-proxy-middleware`). With a backend on `localhost:3000`, you can use this to enable proxying: 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/index.md b/src/content/configuration/index.md index f79628a03a4b..bc46a81322fc 100644 --- a/src/content/configuration/index.md +++ b/src/content/configuration/index.md @@ -401,3 +401,4 @@ T> Want to rapidly generate webpack configuration file for your project requirem [Generate Custom Webpack Configuration](https://generatewebpackconfig.netlify.com/) is an interactive portal you can play around by selecting custom webpack configuration options tailored for your frontend project. It automatically generates a minimal webpack configuration based on your selection of loaders/plugins, etc. +[Visual tool for creating webpack configs](https://webpack.jakoblind.no/) is an online configuration tool for creating webpack config where you can select any combination of features you need. It also generates a full example project based on your webpack configs. diff --git a/src/content/configuration/module.md b/src/content/configuration/module.md index e7a4890fbd9b..6deeef7d4ef4 100644 --- a/src/content/configuration/module.md +++ b/src/content/configuration/module.md @@ -9,6 +9,8 @@ contributors: - dylanonelson - byzyk - pnevares + - fadysamirsadek + - nerdkid93 --- These options determine how the [different types of modules](/concepts/modules) within a project will be treated. @@ -253,7 +255,7 @@ An array of [`Rules`](#rule) that is also used when the Rule matches. ## `Rule.sideEffects` -Possible values: `false | an array of paths` +Possible values: `true | false` Indicate what parts of the module contain side effects. See [Tree Shaking](/guides/tree-shaking/#mark-the-file-as-side-effect-free) for details. @@ -263,6 +265,29 @@ Indicate what parts of the module contain side effects. See [Tree Shaking](/guid `Rule.test` is a shortcut to `Rule.resource.test`. If you supply a `Rule.test` option, you cannot also supply a `Rule.resource`. See [`Rule.resource`](#ruleresource) and [`Condition.test`](#condition) for details. +## `Rule.type` + +Possible values: `"javascript/auto" | "javascript/dynamic" | "javascript/esm" | "json" | "webassembly/experimental"` + +`Rule.type` sets the type for a matching module. This prevents defaultRules and their default importing behaviors from occurring. For example, if you want to load a `.json` file through a custom loader, you'd need to set the `type` to `javascript/auto` to bypass webpack's built-in json importing. (See [v4.0 changelog](https://github.com/webpack/webpack/releases/tag/v4.0.0) for more details) + +```javascript +module.exports = { + //... + module: { + rules: [ + //... + { + test: /\.json$/, + type: 'javascript/auto', + loader: 'custom-json-loader' + } + ] + } +}; +``` + + ## `Rule.use` A list of [UseEntries](#useentry) which are applied to modules. Each entry specifies a loader to be used. diff --git a/src/content/configuration/optimization.md b/src/content/configuration/optimization.md index fc6710f7e876..a372e68c63a9 100644 --- a/src/content/configuration/optimization.md +++ b/src/content/configuration/optimization.md @@ -172,6 +172,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` @@ -382,3 +409,22 @@ module.exports = { } }; ``` + +## `optimization.portableRecords` + +`bool` + +`optimization.portableRecords` tells webpack to generate records with relative paths to be able to move the context folder. + +By default `optimization.portableRecords` is disabled. Automatically enabled if at least one of the records options provided to webpack config: [`recordsPath`](/configuration/other-options/#recordspath), [`recordsInputPath`](/configuration/other-options/#recordsinputpath), [`recordsOutputPath`](/configuration/other-options/#recordsoutputpath). + +__webpack.config.js__ + +```js +module.exports = { + //... + optimization: { + portableRecords: true + } +}; +``` \ No newline at end of file diff --git a/src/content/configuration/output.md b/src/content/configuration/output.md index a4801c64dbe5..1e5cf1d8db9b 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/configuration/plugins.md b/src/content/configuration/plugins.md index 8f05b7a72b6b..41c0ef1cfee8 100644 --- a/src/content/configuration/plugins.md +++ b/src/content/configuration/plugins.md @@ -8,7 +8,7 @@ contributors: - byzyk --- -The `plugins` option is used to customize the webpack build process in a variety of ways. webpack comes with a variety built-in plugins available under `webpack.[plugin-name]`. See [this page](/plugins) for a list of plugins and documentation but note that there are a lot more out in the community. +The `plugins` option is used to customize the webpack build process in a variety of ways. webpack comes with a variety built-in plugins available under `webpack.[plugin-name]`. See [Plugins page](/plugins) for a list of plugins and documentation but note that there are a lot more out in the community. T> Note: This page only discusses using plugins, however if you are interested in writing your own please visit [Writing a Plugin](/development/how-to-write-a-plugin/). @@ -17,14 +17,14 @@ T> Note: This page only discusses using plugins, however if you are interested i `array` -A list of webpack plugins. For example, when multiple bundles share some of the same dependencies, the `CommonsChunkPlugin` could be useful to extract those dependencies into a shared bundle to avoid duplication. This could be added like so: +A list of webpack plugins. For example, [`DefinePlugin`](/plugins/define-plugin/) allows you to create global constants which can be configured at compile time. This can be useful for allowing different behavior between development builds and release builds. ```js module.exports = { //... plugins: [ - new webpack.optimize.CommonsChunkPlugin({ - //... + new webpack.DefinePlugin({ + // Definitions... }) ] }; @@ -42,17 +42,6 @@ var DashboardPlugin = require('webpack-dashboard/plugin'); module.exports = { //... plugins: [ - // build optimization plugins - new webpack.optimize.CommonsChunkPlugin({ - name: 'vendor', - filename: 'vendor-[hash].min.js', - }), - new webpack.optimize.UglifyJsPlugin({ - compress: { - warnings: false, - drop_console: false, - } - }), new ExtractTextPlugin({ filename: 'build.min.css', allChunks: true, 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/asset-management.md b/src/content/guides/asset-management.md index d26fab97ecfa..04cd1744d59d 100644 --- a/src/content/guides/asset-management.md +++ b/src/content/guides/asset-management.md @@ -121,20 +121,19 @@ Now run your build command: ``` bash npm run build -Hash: 9a3abfc96300ef87880f -Version: webpack 2.6.1 -Time: 834ms - Asset Size Chunks Chunk Names -bundle.js 560 kB 0 [emitted] [big] main - [0] ./~/lodash/lodash.js 540 kB {0} [built] - [1] ./src/style.css 1 kB {0} [built] - [2] ./~/css-loader!./src/style.css 191 bytes {0} [built] - [3] ./~/css-loader/lib/css-base.js 2.26 kB {0} [built] - [4] ./~/style-loader/lib/addStyles.js 8.7 kB {0} [built] - [5] ./~/style-loader/lib/urls.js 3.01 kB {0} [built] - [6] (webpack)/buildin/global.js 509 bytes {0} [built] - [7] (webpack)/buildin/module.js 517 bytes {0} [built] - [8] ./src/index.js 351 bytes {0} [built] +Hash: 43e22662004ea1cc5709 +Version: webpack 4.19.0 +Time: 6051ms +Built at: 2018-09-15 11:12:13 + Asset Size Chunks Chunk Names +bundle.js 76.4 KiB 0 [emitted] main +Entrypoint main = bundle.js +[1] ./src/index.js 368 bytes {0} [built] +[2] (webpack)/buildin/global.js 509 bytes {0} [built] +[3] (webpack)/buildin/module.js 519 bytes {0} [built] +[4] ./src/style.css 1.05 KiB {0} [built] +[5] ./node_modules/css-loader!./src/style.css 190 bytes {0} [built] + + 4 hidden modules ``` Open up `index.html` in your browser again and you should see that `Hello webpack` is now styled in red. To see what webpack did, inspect the page (don't view the page source, as it won't show you the result) and look at the page's head tags. It should contain our style block that we imported in `index.js`. @@ -241,22 +240,21 @@ Let's create a new build and open up the index.html file again: ``` bash npm run build -Hash: 854865050ea3c1c7f237 -Version: webpack 2.6.1 -Time: 895ms - Asset Size Chunks Chunk Names -5c999da72346a995e7e2718865d019c8.png 11.3 kB [emitted] - bundle.js 561 kB 0 [emitted] [big] main - [0] ./src/icon.png 82 bytes {0} [built] - [1] ./~/lodash/lodash.js 540 kB {0} [built] - [2] ./src/style.css 1 kB {0} [built] - [3] ./~/css-loader!./src/style.css 242 bytes {0} [built] - [4] ./~/css-loader/lib/css-base.js 2.26 kB {0} [built] - [5] ./~/style-loader/lib/addStyles.js 8.7 kB {0} [built] - [6] ./~/style-loader/lib/urls.js 3.01 kB {0} [built] - [7] (webpack)/buildin/global.js 509 bytes {0} [built] - [8] (webpack)/buildin/module.js 517 bytes {0} [built] - [9] ./src/index.js 503 bytes {0} [built] +Hash: 0993aeea2fd6ea0a7b22 +Version: webpack 4.19.0 +Time: 836ms +Built at: 2018-09-15 12:58:57 + Asset Size Chunks Chunk Names +da4574bb234ddc4bb47cbe1ca4b20303.png 3.01 MiB [emitted] [big] + bundle.js 76.7 KiB 0 [emitted] main +Entrypoint main = bundle.js +[1] ./src/index.js 368 bytes {0} [built] +[2] (webpack)/buildin/global.js 509 bytes {0} [built] +[3] (webpack)/buildin/module.js 519 bytes {0} [built] +[4] ./src/style.css 1.05 KiB {0} [built] +[5] ./node_modules/css-loader!./src/style.css 337 bytes {0} [built] +[8] ./src/icon.png 82 bytes {0} [built] + + 5 hidden modules ``` If all went well, you should now see your icon as a repeating background, as well as an `img` element beside our `Hello webpack` text. If you inspect this element, you'll see that the actual filename has changed to something like `5c999da72346a995e7e2718865d019c8.png`. This means webpack found our file in the `src` folder and processed it! @@ -351,24 +349,26 @@ Now run a new build and let's see if webpack handled our fonts: ``` bash npm run build -Hash: b4aef94169088c79ed1c -Version: webpack 2.6.1 -Time: 775ms - Asset Size Chunks Chunk Names - 5c999da72346a995e7e2718865d019c8.png 11.3 kB [emitted] -11aebbbd407bcc3ab1e914ca0238d24d.woff 221 kB [emitted] - bundle.js 561 kB 0 [emitted] [big] main - [0] ./src/icon.png 82 bytes {0} [built] - [1] ./~/lodash/lodash.js 540 kB {0} [built] - [2] ./src/style.css 1 kB {0} [built] - [3] ./~/css-loader!./src/style.css 420 bytes {0} [built] - [4] ./~/css-loader/lib/css-base.js 2.26 kB {0} [built] - [5] ./src/MyFont.woff 83 bytes {0} [built] - [6] ./~/style-loader/lib/addStyles.js 8.7 kB {0} [built] - [7] ./~/style-loader/lib/urls.js 3.01 kB {0} [built] - [8] (webpack)/buildin/global.js 509 bytes {0} [built] - [9] (webpack)/buildin/module.js 517 bytes {0} [built] - [10] ./src/index.js 503 bytes {0} [built] +Hash: e4c67b7eebe94142a38e +Version: webpack 4.19.0 +Time: 879ms +Built at: 2018-09-15 13:14:08 + Asset Size Chunks Chunk Names +5439466351d432b73fdb518c6ae9654a.woff2 19.5 KiB [emitted] + 387c65cc923ad19790469cfb5b7cb583.woff 23.4 KiB [emitted] + da4574bb234ddc4bb47cbe1ca4b20303.png 3.01 MiB [emitted] [big] + bundle.js 77 KiB 0 [emitted] main +Entrypoint main = bundle.js + [1] ./src/index.js 368 bytes {0} [built] + [2] (webpack)/buildin/global.js 509 bytes {0} [built] + [3] (webpack)/buildin/module.js 519 bytes {0} [built] + [4] ./src/style.css 1.05 KiB {0} [built] + [5] ./node_modules/css-loader!./src/style.css 611 bytes {0} [built] + [8] ./src/my-font.woff2 84 bytes {0} [built] + [9] ./src/my-font.woff 83 bytes {0} [built] +[10] ./src/icon.png 82 bytes {0} [built] + + 5 hidden modules + ``` Open up `index.html` again and see if our `Hello webpack` text has changed to the new font. If all is well, you should see the changes. 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/code-splitting.md b/src/content/guides/code-splitting.md index 63e183e63a3a..dacbbfb9645b 100644 --- a/src/content/guides/code-splitting.md +++ b/src/content/guides/code-splitting.md @@ -24,6 +24,7 @@ contributors: - kcolton - efreitasn - EugeneHlushko + - Tiendo1011 - byzyk related: - title: in webpack @@ -41,7 +42,7 @@ Code splitting is one of the most compelling features of webpack. This feature a There are three general approaches to code splitting available: - Entry Points: Manually split code using [`entry`](/configuration/entry-context) configuration. -- Prevent Duplication: Use the [`SplitChunks`](/plugins/split-chunks-plugin/) to dedupe and split chunks. +- Prevent Duplication: Use the [`SplitChunksPlugin`](/plugins/split-chunks-plugin/) to dedupe and split chunks. - Dynamic Imports: Split code via inline function calls within modules. @@ -113,14 +114,14 @@ As mentioned there are some pitfalls to this approach: - If there are any duplicated modules between entry chunks they will be included in both bundles. - It isn't as flexible and can't be used to dynamically split code with the core application logic. -The first of these two points is definitely an issue for our example, as `lodash` is also imported within `./src/index.js` and will thus be duplicated in both bundles. Let's remove this duplication by using the `SplitChunks` plugin. +The first of these two points is definitely an issue for our example, as `lodash` is also imported within `./src/index.js` and will thus be duplicated in both bundles. Let's remove this duplication by using the [`SplitChunksPlugin`](/plugins/split-chunks-plugin/). ## Prevent Duplication -W> The CommonsChunkPlugin has been removed in webpack v4 legato. To learn how chunks are treated in the latest version, check out the [SplitChunksPlugin](/plugins/split-chunks-plugin/). +The [`SplitChunksPlugin`](/plugins/split-chunks-plugin/) allows us to extract common dependencies into an existing entry chunk or an entirely new chunk. Let's use this to de-duplicate the `lodash` dependency from the previous example: -The [`SplitChunks`](/plugins/split-chunks-plugin/) allows us to extract common dependencies into an existing entry chunk or an entirely new chunk. Let's use this to de-duplicate the `lodash` dependency from the previous example: +W> The `CommonsChunkPlugin` has been removed in webpack v4 legato. To learn how chunks are treated in the latest version, check out the [`SplitChunksPlugin`](/plugins/split-chunks-plugin/). __webpack.config.js__ @@ -145,7 +146,7 @@ __webpack.config.js__ }; ``` -With the [`SplitChunks`](/plugins/split-chunks-plugin/) in place, we should now see the duplicate dependency removed from our `index.bundle.js` and `another.bundle.js`. The plugin should notice that we've separated `lodash` out to a separate chunk and remove the dead weight from our main bundle. Let's do an `npm run build` to see if it worked: +With the [`optimization.splitChunks`](/plugins/split-chunks-plugin/#optimization-splitchunks) configuration option in place, we should now see the duplicate dependency removed from our `index.bundle.js` and `another.bundle.js`. The plugin should notice that we've separated `lodash` out to a separate chunk and remove the dead weight from our main bundle. Let's do an `npm run build` to see if it worked: ``` bash Hash: ac2ac6042ebb4f20ee54 @@ -170,8 +171,6 @@ Here are some other useful plugins and loaders provided by the community for spl - [`bundle-loader`](/loaders/bundle-loader): Used to split code and lazy load the resulting bundles. - [`promise-loader`](https://github.com/gaearon/promise-loader): Similar to the `bundle-loader` but uses promises. -T> The [`CommonsChunkPlugin`](/plugins/commons-chunk-plugin) is also used to split vendor modules from core application code using [explicit vendor chunks](/plugins/commons-chunk-plugin/#explicit-vendor-chunk). - ## Dynamic Imports @@ -234,9 +233,8 @@ __src/index.js__ - - // Lodash, now imported by this script - element.innerHTML = _.join(['Hello', 'webpack'], ' '); -+ return import(/* webpackChunkName: "lodash" */ 'lodash').then(_ => { ++ return import(/* webpackChunkName: "lodash" */ 'lodash').then(({ default: _ }) => { + var element = document.createElement('div'); -+ var _ = _.default; + + element.innerHTML = _.join(['Hello', 'webpack'], ' '); + @@ -251,6 +249,8 @@ __src/index.js__ + }) ``` +The reason we need `default` is since webpack 4, when importing a CommonJS module, the import will no longer resolve to the value of `module.exports`, it will instead create an artificial namespace object for the CommonJS module, for more information on the reason behind this, read [webpack 4: import() and CommonJs](https://medium.com/webpack/webpack-4-import-and-commonjs-d619d626b655) + Note the use of `webpackChunkName` in the comment. This will cause our separate bundle to be named `lodash.bundle.js` instead of just `[id].bundle.js`. For more information on `webpackChunkName` and the other available options, see the [`import()` documentation](/api/module-methods#import-). Let's run webpack to see `lodash` separated out to a separate bundle: ``` bash @@ -274,7 +274,7 @@ __src/index.js__ ``` diff - function getComponent() { + async function getComponent() { -- return import(/* webpackChunkName: "lodash" */ 'lodash').then(_ => { +- return import(/* webpackChunkName: "lodash" */ 'lodash').then({ default: _ } => { - var element = document.createElement('div'); - - element.innerHTML = _.join(['Hello', 'webpack'], ' '); @@ -283,7 +283,7 @@ __src/index.js__ - - }).catch(error => 'An error occurred while loading the component'); + var element = document.createElement('div'); -+ const _ = await import(/* webpackChunkName: "lodash" */ 'lodash'); ++ const { default: _ } = await import(/* webpackChunkName: "lodash" */ 'lodash'); + + element.innerHTML = _.join(['Hello', 'webpack'], ' '); + @@ -320,8 +320,8 @@ T> webpack will add the prefetch hint once the parent chunk has been loaded. Preload directive has a bunch of differences compared to prefetch: -- A preloaded chunk starts loading in parallel to the parent chunk. A prefetched chunk starts after the parent chunk finish. -- A preloaded chunk has medium priority and instantly downloaded. A prefetched chunk is downloaded in browser idle time. +- A preloaded chunk starts loading in parallel to the parent chunk. A prefetched chunk starts after the parent chunk finishes loading. +- A preloaded chunk has medium priority and is instantly downloaded. A prefetched chunk is downloaded while browser is idle. - A preloaded chunk should be instantly requested by the parent chunk. A prefetched chunk can be used anytime in the future. - Browser support is different. diff --git a/src/content/guides/development.md b/src/content/guides/development.md index 70358163446f..57312fa52029 100644 --- a/src/content/guides/development.md +++ b/src/content/guides/development.md @@ -8,6 +8,7 @@ contributors: - TheDutchCoder - WojciechKo - Calinou + - GAumala --- T> This guide extends on code examples found in the [Output Management](/guides/output-management) guide. @@ -205,6 +206,8 @@ __webpack.config.js__ This tells `webpack-dev-server` to serve the files from the `dist` directory on `localhost:8080`. +W> webpack-dev-server doesn't write any output files after compiling. Instead, it keeps bundle files in memory and serves them as if they were real files mounted at the server's root path. If your page expects to find the bundle files in different path, you can change this with the [`publicPath`](/configuration/dev-server/#devserver-publicpath-) option in the dev server's configuration. + Let's add a script to easily run the dev server as well: __package.json__ diff --git a/src/content/guides/installation.md b/src/content/guides/installation.md index f8a9537b70c4..e65466b676ce 100644 --- a/src/content/guides/installation.md +++ b/src/content/guides/installation.md @@ -5,12 +5,14 @@ contributors: - pksjce - 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. @@ -28,19 +30,12 @@ npm install --save-dev webpack npm install --save-dev webpack@ ``` -If you're using webpack v4 or later, you'll need to install a [CLI](/api/cli/). +If you're using webpack v4 or later, you'll need to install the [CLI](/api/cli/). ``` bash npm install --save-dev webpack-cli ``` -or - -``` bash -npm install --save-dev webpack-command -``` - - Installing locally is what we recommend for most projects. This makes it easier to upgrade projects individually when breaking changes are introduced. Typically webpack is run via one or more [npm scripts](https://docs.npmjs.com/misc/scripts) which will look for a webpack installation in your local `node_modules` directory: ```json diff --git a/src/content/guides/production.md b/src/content/guides/production.md index fc9b0e6cfbb2..544f1c664136 100644 --- a/src/content/guides/production.md +++ b/src/content/guides/production.md @@ -118,7 +118,7 @@ __package.json__ "name": "development", "version": "1.0.0", "description": "", - "main": "webpack.config.js", + "main": "src/index.js", "scripts": { - "start": "webpack-dev-server --open", + "start": "webpack-dev-server --open --config webpack.dev.js", @@ -160,7 +160,6 @@ __webpack.prod.js__ module.exports = merge(common, { mode: 'production', - devtool: 'source-map' }); ``` diff --git a/src/content/guides/tree-shaking.md b/src/content/guides/tree-shaking.md index 17011dcd2c72..3582c8b48bbf 100644 --- a/src/content/guides/tree-shaking.md +++ b/src/content/guides/tree-shaking.md @@ -13,6 +13,7 @@ contributors: - lumo10 - byzyk - pnevares + - EugeneHlushko related: - title: "webpack 4 beta — try it today!" url: https://medium.com/webpack/webpack-4-beta-try-it-today-6b1d27d7d7e2#9a67 @@ -60,7 +61,7 @@ export function cube(x) { } ``` -Set the `mode` configuration option to [development](https://webpack.js.org/concepts/mode/#mode-development) to make sure that the bundle is not minified: +Set the `mode` configuration option to [development](/concepts/mode/#mode-development) to make sure that the bundle is not minified: __webpack.config.js__ @@ -74,7 +75,7 @@ module.exports = { path: path.resolve(__dirname, 'dist') - } + }, -+ mode: "development" ++ mode: 'development' }; ``` @@ -172,9 +173,7 @@ Finally, `"sideEffects"` can also be set from the [`module.rules` configuration ## Minify the Output -So we've cued up our "dead code" to be dropped by using the `import` and `export` syntax, but we still need to drop it from the bundle. To do that, we'll use the `-p` (production) webpack compilation flag to enable `UglifyJSPlugin`. - -As of webpack 4, this is also easily toggled via the `"mode"` configuration option, set to `"production"`. +So we've cued up our "dead code" to be dropped by using the `import` and `export` syntax, but we still need to drop it from the bundle. To do that set the `mode` configuration option to [`production`](/concepts/mode/#mode-production) configuration option. __webpack.config.js__ @@ -187,8 +186,8 @@ module.exports = { filename: 'bundle.js', path: path.resolve(__dirname, 'dist') }, -- mode: "development" -+ mode: "production" +- mode: 'development' ++ mode: 'production' }; ``` @@ -205,8 +204,8 @@ T> [ModuleConcatenationPlugin](/plugins/module-concatenation-plugin) is needed f So, what we've learned is that in order to take advantage of _tree shaking_, you must... - Use ES2015 module syntax (i.e. `import` and `export`). -- Add a "sideEffects" property to your project's `package.json` file. -- Include a minifier that supports dead code removal (e.g. the `UglifyJSPlugin`). +- Add a `"sideEffects"` property to your project's `package.json` file. +- Use [`production`](/concepts/mode/#mode-production) `mode` configuration option to enable [various optimizations](/concepts/mode/#usage) including minification and tree shaking. You can imagine your application as a tree. The source code and libraries you actually use represent the green, living leaves of the tree. Dead code represents the brown, dead leaves of the tree that are consumed by autumn. In order to get rid of the dead leaves, you have to shake the tree, causing them to fall. diff --git a/src/content/guides/typescript.md b/src/content/guides/typescript.md index b86c2965eb4c..df167ec213a9 100644 --- a/src/content/guides/typescript.md +++ b/src/content/guides/typescript.md @@ -119,7 +119,7 @@ __tsconfig.json__ } ``` -Now we need to tell webpack to extract these source maps and into our final bundle: +Now we need to tell webpack to extract these source maps and include in our final bundle: __webpack.config.js__ 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/index.md b/src/content/plugins/index.md index c107d1b7c6d1..3199c4a537b0 100644 --- a/src/content/plugins/index.md +++ b/src/content/plugins/index.md @@ -34,6 +34,7 @@ Name | Description [`NoEmitOnErrorsPlugin`](/configuration/optimization/#optimization-noemitonerrors) | Skip the emitting phase when there are compilation errors [`NormalModuleReplacementPlugin`](/plugins/normal-module-replacement-plugin) | Replace resource(s) that matches a regexp [`NpmInstallWebpackPlugin`](/plugins/npm-install-webpack-plugin) | Auto-install missing dependencies during development +[`ProgressPlugin`](/plugins/progress-plugin) | Report compilation progress [`ProvidePlugin`](/plugins/provide-plugin) | Use modules without having to use import/require [`SourceMapDevToolPlugin`](/plugins/source-map-dev-tool-plugin) | Enables a more fine grained control of source maps [`EvalSourceMapDevToolPlugin`](/plugins/eval-source-map-dev-tool-plugin) | Enables a more fine grained control of eval source maps diff --git a/src/content/plugins/progress-plugin.md b/src/content/plugins/progress-plugin.md new file mode 100644 index 000000000000..878f89bc5afe --- /dev/null +++ b/src/content/plugins/progress-plugin.md @@ -0,0 +1,96 @@ +--- +title: ProgressPlugin +contributors: + - elliottsj +--- + +The `ProgressPlugin` provides a way to customize how progress is reported during a compilation. + +## Usage + +Create an instance of `ProgressPlugin` with a handler function which will be called when hooks report progress: + +```js +const handler = (percentage, message, ...args) => { + // e.g. Output each progress message directly to the console: + console.info(percentage, message, ...args); +}; + +new webpack.ProgressPlugin(handler); +``` + +* `handler` is a function which takes these arguments: + * `percentage`: a number between 0 and 1 indicating the completion percentage of the compilation. + * `message`: a short description of the currently-executing hook. + * `...args`: zero or more additional strings describing the current progress. + +## Supported Hooks + +The following hooks report progress information to `ProgressPlugin`. + +T> _Hooks marked with * allow plugins to report progress information using `reportProgress`. For more, see [Plugin API: Reporting Progress](/api/plugins/#reporting-progress)_ + +**Compiler** + +* compilation +* emit* +* afterEmit* +* done + +**Compilation** + +* buildModule +* failedModule +* succeedModule +* finishModules* +* seal* +* optimizeDependenciesBasic* +* optimizeDependencies* +* optimizeDependenciesAdvanced* +* afterOptimizeDependencies* +* optimize* +* optimizeModulesBasic* +* optimizeModules* +* optimizeModulesAdvanced* +* afterOptimizeModules* +* optimizeChunksBasic* +* optimizeChunks* +* optimizeChunksAdvanced* +* afterOptimizeChunks* +* optimizeTree* +* afterOptimizeTree* +* optimizeChunkModulesBasic* +* optimizeChunkModules* +* optimizeChunkModulesAdvanced* +* afterOptimizeChunkModules* +* reviveModules* +* optimizeModuleOrder* +* advancedOptimizeModuleOrder* +* beforeModuleIds* +* moduleIds* +* optimizeModuleIds* +* afterOptimizeModuleIds* +* reviveChunks* +* optimizeChunkOrder* +* beforeChunkIds* +* optimizeChunkIds* +* afterOptimizeChunkIds* +* recordModules* +* recordChunks* +* beforeHash* +* afterHash* +* recordHash* +* beforeModuleAssets* +* beforeChunkAssets* +* additionalChunkAssets* +* record* +* additionalAssets* +* optimizeChunkAssets* +* afterOptimizeChunkAssets* +* optimizeAssets* +* afterOptimizeAssets* +* afterSeal* + +## Source + +* [`ProgressPlugin` source](https://github.com/webpack/webpack/blob/master/lib/ProgressPlugin.js) diff --git a/src/content/plugins/source-map-dev-tool-plugin.md b/src/content/plugins/source-map-dev-tool-plugin.md index e27bf021de9d..62c394e76a40 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 5e5a224b4d4b..038644d1cab6 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` @@ -216,9 +233,13 @@ module.exports = { //... optimization: { splitChunks: { - test (chunks) { - //... - return true; + cacheGroups: { + vendors: { + test (chunks) { + //... + return true; + } + } } } } @@ -340,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. diff --git a/src/utilities/process-readme.js b/src/utilities/process-readme.js index 8d467253c3fe..5e4aefa0a86e 100644 --- a/src/utilities/process-readme.js +++ b/src/utilities/process-readme.js @@ -24,7 +24,13 @@ module.exports = function processREADME(body, options = {}) { // Only resolve non-absolute urls from their source if they are not a document fragment link if (!href.startsWith('#')) { - href = url.resolve(options.source, href); + + // Convert Github raw links to rendered links + let rendered_url = options.source + .replace(/raw.githubusercontent.com/, 'github.com') + .replace(/master/, 'blob/master'); + + href = url.resolve(rendered_url, href); } // Modify absolute documenation links to be root relative