One new feature webpack4 supports is zero configuration, which does not require config and can be packaged. This is very tempting for lazy people, but it also means that we don’t know what’s going on with zero configuration, and we don’t know if the packaged files are what we want them to be. However, as the parents of the project, they are still responsible for their children, and every packaging process should be controlled. This article explains what happens with Webpack packaging in different modes.

The MODE parameter has three parameters: production, development, and None. The first two are plugins with presets, and the last one is none. If set to None, webPack is as it started out, with no presets and needs to be configured from scratch.

In the WebPack configuration, all other configurations can be omitted! If you do not add mode, you will receive a warning:

WARNING in configuration The ‘mode’ option has not been set, webpack will fallback to ‘production’ for this value. Set ‘mode’ option to ‘development’ or ‘production’ to enable defaults for each environment. You can also set it to ‘none’ to disable any default behavior. Learn more: Webpack.js.org/concepts/mo…

If mode is not set, the system will give you a default production mode.

The mode configuration is simple, with just three values you can choose from. The none parameter is understandable, so let’s examine the other two production and development states, why they exist, and what they do in webPack packaging.

How do you differentiate in packagingproductionanddevelopmentThe state of the

In production or development mode, webpack creates a global variable, process.env.node_env, Add new webpack.defineplugin ({” process.env.node_env “: JSON. Stringify (” development | production “)}), used to distinguish between different state, at the same time can distinguish program state in your application.

So how do we distinguish between coding? Since process.env.node_env is a global mask, we can refer to values like this, assuming mode:production:

if ("development" === process.env.NODE_ENV){
    ....
}else{... }Copy the code

After compiling:

if ("development"= = ="production") {... }else{... }Copy the code

In the end, process.env.node_env is replaced with a constant. This little feature helps us distinguish the online version from the development version when writing business JS.

noneModule packaging in mode

What does webPack’s default package look like without any optimization? Below is a simple example. We can see that he packages modules into an array, and when he calls a module, he calls one of the sequence numbers in the array directly. There are no optimizations like compressing and obfuscating, and even annotations are fine for us, such as importing /* harmony import /, / harmony default export */.

[/* 0 */ (function(module, __webpack_exports__, __webpack_require__) {
    "use strict";
    __webpack_require__.r(__webpack_exports__);
    /* harmony import */ var _page2_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(1);
    console.log(_page2_js__WEBPACK_IMPORTED_MODULE_0__["default"}), /* 1 */ (function(module, __webpack_exports__, __webpack_require__) {
    "use strict";
    __webpack_require__.r(__webpack_exports__);
    let str="page1"
    /* harmony default export */ __webpack_exports__["default"] = (str); })]Copy the code

However, no matter in the development environment or in the formal environment production, this code is not acceptable. For the development environment, this code is not readable enough, and for the formal environment, this code is not concise enough. Therefore, in order to reduce some repeated operations, Webpack4 provides development | production can greatly help us do off an most, we need to do is on the basis of these things added functionality.

In Development mode, WebPack does that packaging

Development tells the application that I am currently in development state, which means that the packaged content should be development-friendly. In this mode, the following plugins are done and nothing else is done, so they can be omitted.

// webpack.development.config.js
module.exports = {
+ mode: 'development'
- devtool: 'eval',
- plugins: [
-   new webpack.NamedModulesPlugin(),
-   new webpack.NamedChunksPlugin(),
-   new webpack.DefinePlugin({ "process.env.NODE_ENV": JSON.stringify("development")}), -]}Copy the code

Let’s look at the NamedModulesPlugin and NamedChunksPlugin plugins and see what they do. Originally, our WebPack does not name packaged modules, but instead loads modules in sequence, starting from 0. This doesn’t matter for a machine, lookup loads quickly, but it’s a disaster for a human brain, so give each module a name at this point to facilitate lookup during development.

Without NamedModulesPlugin, a module is an array, and the references are referenced in the order in the array. Adding or removing new modules will result in a change in the ordinal number, which is the case under the default webPack package (see the previous section).

With the NamedModulesPlugin, modules have names and unique keys that are fixed no matter how many modules are added or removed.

{

"./src/index.js":   (function(module, __webpack_exports__, __webpack_require__) {
                        "use strict";
                        __webpack_require__.r(__webpack_exports__);
                        var _page2_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__("./src/page2.js");
                        console.log(_page2_js__WEBPACK_IMPORTED_MODULE_0__["default"])}),"./src/page2.js":    (function(module, __webpack_exports__, __webpack_require__) {
                        "use strict";
                        __webpack_require__.r(__webpack_exports__);
                        let str="page1"
                         __webpack_exports__["default"] = (str); })}Copy the code

In addition to NamedModulesPlugin, there is also a NamedChunksPlugin, which is used to name each configured chunk. The original chunks are also arrays without names.

Asset Size Chunks Names index.js 4.04 KiB 0 [emitted] index page2.js 3.75 KiB 1 [emitted] page2Copy the code
Asset Size Chunks Names index.js 4.1 KiB index [emitted] index page1. Js 4.15 KiB page1 [emitted] page1Copy the code

NamedChunksPlugin actually provides a feature where you can customize the name of the chunks. What if I have the same chunk name in different packages? We can use all of the dependent module names plus the module name on this module. Since chunk. modules is deprecated, use another method to replace chunk.mapModules and rename Chunk:

new webpack.NamedChunksPlugin((chunk) => {
    return chunk.mapModules(m => {
        return path.relative(m.context, m.request)
    }).join("_")}),Copy the code

If we look at the effect of doing this one line of code, we can see that the Chunks have been renamed, which largely resolves the problem of re-naming the Chunks:

Asset Size Chunks Names index.js 4.1 KiB index.js_page2.js [emitted] index page2.js 3.78 KiB page2.js [emitted] page2Copy the code

Conclusion: Development has omitted the naming process for us, and we still need to add the rest by ourselves.

production

In the official release, the omitted plug-ins, as shown below, will be analyzed one by one.

// webpack.production.config.js
module.exports = {
+  mode: 'production',
-  plugins: [
-    new UglifyJsPlugin(/* ... */),
-    new webpack.DefinePlugin({ "process.env.NODE_ENV": JSON.stringify("production") }),
-    new webpack.optimize.ModuleConcatenationPlugin(),
-    new webpack.NoEmitOnErrorsPlugin()
-  ]
}
Copy the code

UglifyJsPlugin

Const UglifyJsPlugin = require(‘uglifyjs-webpack-plugin’); UglifyJsPlugin = require(‘uglifyjs-webpack-plugin’); So you can use it.

The new UglifyJsPlugin() plugin can be configured in Optimize, but the effect is the same, so we don’t have to import a new plugin, which will slow down the webPack.

optimization:{
    minimize: true,},Copy the code

Remove the plugins, add obturation compression to Optimization, and webPack takes off quickly. Only the first packing is slow, and then it’s fast.

ModuleConcatenationPlugin

Webpack. Optimize. ModuleConcatenationPlugin () what is the role of this plug-in? The official document describes it this way:

Keep in mind that this plug-in only works with ES6 modules that are handled directly by WebPack. When using transpilers, you need to disable module processing (such as the modules option in Babel).

NoEmitOnErrorsPlugin

. Finally a plugin is webpack NoEmitOnErrorsPlugin (), that is, to prevent an error program, even if there are any errors also continue to compile for me, a very violent way?

others

There are also some default plug-in configurations, which are not referenced in plugins:

flagIncludedChunks

FlagIncludedChunks is configured to see what happens:

Is not enabled

Asset Size Chunks Names index.js 1.02 KiB 0 [emitted] index page1. Js 970 bytes 1 [emitted] page1Copy the code

When enabled, if only two files seem inconspicuous, I add three files, page1 calls page2, index calls page1, and then it is clear that the chunks in this case are the ids of all referenced modules.

Asset Size Chunks Chunk Names index. Js 1.08 KiB 0, 1, 2 [emitted] index page1. Js 1.01 KiB 1, 2 [emitted] page1 page2.js 971 bytes 2 [emitted] page2Copy the code

OccurrenceOrderPlugin

Webpack. Optimize. OccurrenceOrderPlugin this plug-in is according to the chunk citations to arrange in order, because it makes regular reference module and the chunk with smaller id. This is what happens when you add the above example to this configuration run.

Asset Size Chunks Names page2.js 969 bytes 0 [emitted] page2 page1.js 1.01 KiB 1, Currently, 0 [emitted] page1 index.js 1, 2, 0, 1 [emitted] indexCopy the code

SideEffectsFlagPlugin

Webpack. Optimize. SideEffectsFlagPlugin () the plug-in if need to take effect, need two conditions, one is to import the module has been marked sideEffect, Json, sideEffects is false. The second is that the current module references a module that has no sideEffects and is not used. This module will not be packaged into a file when it is packaged.

conclusion

In fact, in production mode, compared with the official document, its configuration is more equivalent to the following configuration:

module.exports = {
    mode:"none",
    optimization:{
        flagIncludedChunks:true,
        minimize: true,
    },
    plugins: [
        new webpack.DefinePlugin({ "process.env.NODE_ENV": JSON.stringify("production") }),
        new webpack.optimize.ModuleConcatenationPlugin(),
        new webpack.NoEmitOnErrorsPlugin(),
        new webpack.optimize.SideEffectsFlagPlugin()
    ]
}
Copy the code

Production Plug-in reference documentation

name effect
FlagDependencyUsagePlugin This plugin is not available through Webpack. I can only import it by forcing a class file in webpack/lib.
SideEffectsFlagPlugin For handling tree shaking.tree shaking.sideEffectThis plugin is used to remove the package if the current module is not referenced and sideEffects is false in package.json.Useful answers on StackOverflow
FlagIncludedChunksPlugin Add the chunkid contained in the current chunk to the chunk name
ModuleConcatenationPlugin Scope lifting
NoEmitOnErrorsPlugin Prevent any errors
OccurrenceOrderPlugin Rank the chunks by the number of calls
UglifyJsPlugin Mixed compression