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 packagingproduction
anddevelopment
The 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.
none
Module 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 |