1, What is scope housing
By default, the module resources packaged by Webpack will be organized into function forms, such as:
For more information on the form of packaged products, please refer to the previous article< Webpack principle series 8: product translation packaging logic>
// common.js export default "common"; // index.js import common from './common'; console.log(common);
The above example will eventually be packaged into a product with the following structure:
"./src/common.js": ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { const __WEBPACK_DEFAULT_EXPORT__ = ("common"); __webpack_require__.d(__webpack_exports__, { /* harmony export */ "default": () => (__WEBPACK_DEFAULT_EXPORT__) /* harmony export */ }); }), "./src/index.js": ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { var _common__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__( /*! ./common */ "./src/common.js"); console.log(_common__WEBPACK_IMPORTED_MODULE_0__) })
This structure has two problems that affect the operation performance:
- Repeated function template code will increase the product volume and consume more network traffic
- The function needs to create and destroy the scope space when it is out of the stack and into the stack, which affects the running performance
To solve these problems, the scope hosting function has been introduced since Webpack 3. In essence, it is to combine multiple qualified modules into the same function space, reduce the template code of function declaration and frequent stack entry and exit operations at runtime, so as to package "smaller volume" and "running performance" Better package. For example, the above example generates code after Scope Hoisting Optimization:
((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { ;// CONCATENATED MODULE: ./src/common.js /* harmony default export */ const common = ("common"); ;// CONCATENATED MODULE: ./src/index.js console.log(common); })
2, Using scope housing
2.1 enable scope hosting feature
Webpack provides three ways to enable the scope hosting function:
- Turn on Production mode
- Using the optimization.concatenateModules configuration item
- Use the ModuleConcatenationPlugin plug-in directly
Corresponding to the following codes:
const ModuleConcatenationPlugin = require('webpack/lib/optimize/ModuleConcatenationPlugin'); module.exports = { // Method 1: set 'mode' to production to start mode: "production", // Method 2: set 'optimization.concatenateModules' to true optimization: { concatenateModules: true, usedExports: true, providedExports: true, }, // Method 3: directly use the 'ModuleConcatenationPlugin' plug-in plugins: [new ModuleConcatenationPlugin()] };
The working principles of the three methods are similar. In the end, ModuleConcatenationPlugin will be used to complete module analysis and merging. The only thing to note is that when using optimization.concatenateModules, usedExports and providedExports need to be set to true at the same time, and the import and export variables of the module can be marked to complete the merging operation.
2.2 module consolidation rules
After enabling scope hosting, Webpack will merge as many modules as possible into the same function scope. However, the merge function depends on the static analysis capability of ESM on the one hand, and on the other hand, it needs to ensure that the merge operation will not cause code redundancy. Therefore, developers should note that scope hosting will fail in the following scenarios:
2.2.1 non ESM modules
For modules such as AMD and CMD, due to the dynamic import and export content of modules, Webpack cannot ensure that the merged modules will not have side effects on the original code semantics, resulting in the failure of scope hosting, for example:
// common.js module.exports = 'common'; // index.js import common from './common';
In the above example, because common.js uses CommonJS to import module content, scope hosting fails, and the two modules cannot be merged.
This problem is particularly common when importing NPM packages. Since most frameworks are self packaged and then uploaded to NPM, and the CommonJS module scheme with better compatibility is exported by default, the scope hosting function cannot be used. At this time, you can try to import the ESM version of the framework through the mainfiles attribute:
module.exports = { resolve: { // Give priority to the ES6 modular syntax file pointed to in jsnext:main mainFields: ['jsnext:main', 'browser', 'main'] }, };
2.2.2 the module is referenced by multiple chunks
If a module is referenced by multiple chunks at the same time, in order to avoid repeated packaging, scope hosting will also fail, for example:
// common.js export default "common" // async.js import common from './common'; // index.js import common from './common'; import("./async");
In the above example, the entry index.js imports the async.js module by asynchronous reference, and both async.js and index.js depend on the common.js module. According to the running rules of Chunk, async.js will be processed as a separate Chunk, which means that the common.js module is referenced by the Initial Chunk corresponding to index.js and the Async Chunk corresponding to async.js at the same time. At this time, scope hoistin G is invalid. Common.js cannot be merged into any Chunk, but is generated as a separate scope. The final packaging result is:
"./src/common.js": (() => { var __WEBPACK_DEFAULT_EXPORT__ = ("common"); }), "./src/index.js": (() => { var _common__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__( /*! ./common */ "./src/common.js"); __webpack_require__.e( /*! import() */ "src_async_js").then(__webpack_require__.bind(__webpack_require__, /*! ./async */ "./src/async.js")); }),
❝ for more information about Chunk, please refer to:
- <Webpack Performance Series IV: subcontracting optimization>
- <A little difficult knowledge: detailed explanation of Webpack Chunk subcontracting rules>❞
3, Summary
By default, Webpack will package modules into separate functions, which will cause code redundancy and running performance problems to a certain extent. In this case, since the introduction of ModuleConcatenationPlugin in Webpack 3.0, developers can use scope hosting technology to combine multiple modules into one function to reduce performance problems.