Improve webpack packaging speed: Happypack and DLL packaging

background

I have been developing a backend management system using React, and accidentally added a rich text editor the other day (github.com/jpuri/react…). After that, webpack packaging plummeted, and it felt like it was time to start a wave of optimization.

The current configuration is 8GB ram, i5CPU MAC, Node V8.2.1, Webpack 3.5.5, and the data packed once in this configuration is

Compiled successfully in 46.5s. File sizes after gzip: Dist /js/common.js 149.49 KB (-1 B) Dist /js/atadd.997ff5.js dist/js/ index.css 15.32 KB (-8 B) Dist/js/cpadd. 5 c7f29. Js 4.45 KB dist/js/cpsupple. 9 fe38b. Js 3.3 KB (+ 13 B) dist/js/cplist. 3 a5f02. Js 3.08 KB Dist /js/ cpView.e68fe9.js 2.91 KB Dist /js/atview.2a5aac.js 2.89 KB Dist /js/atlist.6d166c.js 2.24 KB dist/js/atuser.30b019.js 295 B dist/js/activity.4e286a.js 291 B dist/js/coupon.3dd30f.jsCopy the code

Happypack multithreaded packaging

Normally, JS is single-threaded, but Node is not. Happypack can be multithreaded to take advantage of the multi-threaded environment provided by Node. Basically open the official website to look at the readme can be configured, especially I only optimized for JS compilation, configuration is relatively simple.

{ test:/\.js$/, loader:'happypack/loader', } //... New HappyPack({loaders:....) {loaders:.... })Copy the code

Here is an explanation of happypack’s principle. The happypack data is packaged as follows:

Compiled successfully in 45.7s. File sizes after gzip: Dist /js/common.js 150.06 KB (+144.13 KB) Dist /js/ atAdd.5afe2c.js 34.06 KB Dist/CSS /index.css 15.32 KB Dist/js/cpadd. 5 c7f29. Js 4.45 KB dist/js/cpsupple. 9 fe38b. Js 3.3 KB dist/js/cplist. 3 a5f02. Js 3.08 KB Dist /js/ cpView.e68fe9.js 2.91 KB Dist /js/atview.2a5aac.js 2.89 KB Dist /js/atlist.6d166c.js 2.24 KB dist/js/atuser.30b019.js 295 B dist/js/activity.4e286a.js 291 B dist/js/coupon.3dd30f.jsCopy the code

There doesn’t seem to be much difference 😂

DLL packaging

Going back to the original problem, the rich text editor is extremely slow after being added, so we should specifically extract the rich text editor and not analyze it every time we package it. Webpack itself provides this functionality, called DLL packaging, and requires two plug-ins, DllPlugin and DllReferencePlugin. The former is used to package dL.js, and the latter is used to reference dL.js when packaging the main process. For details, see the official website.

I applied DLL to package two files, one is vendor file, the other is editor file, the relevant configuration is as follows

//webpack.config.dll.js const path = require('path'); const webpack=require('webpack'); const env = 'production'; const vendors=[ 'react', 'react-dom', 'react-router', 'history', 'redux', 'dva', 'axios', 'qs', 'moment', 'styled-components' ]; const editor = [ 'react-draft-wysiwyg', 'draftjs-to-html', 'html-to-draftjs', 'draft-js' ] const libname = '[name]_lib' module.exports={ entry:{ 'vendor':vendors, 'editor':editor, }, output:{ path:path.join(__dirname, 'dll'), filename:'[name].[hash:4].dll.js', library:libname, }, plugins:[ new webpack.HashedModuleIdsPlugin(), / / keep other packages will not change the hash of the new webpack.optimize.Com monsChunkPlugin ({names: [' vendor '], minChunks: 2, // Extract the react code from vendor}), new webpack.DllPlugin({path: path.resolve(__dirname, 'dll', 'manifest-[name].json'), name: Libname, context:process.cwd() // is the context in which the package path is resolved, this should be consistent with webpack.config.js.}),...uglify, // Uglifyjs and other plug-in configurations that should be used in production environments]}Copy the code

Run it again webpack – p – config. / config/webpack config. DLL. Js. The vendor can generate DLL. Js and editor. DLL. Js

Vendor.dll. Js is the basic file, which will be introduced as soon as you enter the page, so you can directly add it in the HTML

//webpack.config.js const dir = fs.readdirSync(path.resolve(__dirname,'dll')); New HtmlWebpackPlugin({... otherConfig, scripts: env === 'production' ? dir.map(file=>{ if(/vendor\.. {4} \. DLL \. Js $/. The test (file)) {return ` ${publicPath} js / ${file} ` / / publicPath is global configuration publicPath}}) : [XXX].Copy the code

Dynamic loading of DLL scripts

There is also an editor.dll. Js file, after gzip more than 160 K, is the need for rich text editor pages need to use, I do not want to use the page as soon as the page is loaded, so I thought of a black method, when the page first load editor, asynchronous introduction of the DLL file and then render. The key codes are as follows:

import Async from 'react-code-splitting'; let editorScriptloaded = __DEV__; Let editorScriptStartload = false; // Let editorScriptStartload = false; Export Default Class AsyncEditor extends React.Component {render(){return <Async load={new Promise((res,rej)=>{ if(typeof window ! == 'undefined'){ if(editorScriptloaded){ resolveEditor(res, rej); }else if(! editorScriptStartload){ editorScriptStartload = true; var doc = window.document; var s = doc.createElement('script'); s.src=__EDITOR_URL__; Function (){editorScriptloaded = true; // This is a DefinePlugin variable. resolveEditor(res, rej); }; doc.body.appendChild(s); } }else{ res(null) } })} componentProps={this.props}/> } } function resolveEditor(res, rej){ @res class RichEditor extends React.Component { //...... }Copy the code

Simply introduce AsyncEditor and use it like a normal React component, which automatically loads dependent DLL files dynamically and only once.

The optimization results

Not counting the packaging of the two DLLS, the time is suddenly reduced considerably and the result is as follows

Compiled successfully in 25.3 S. File sizes after gzip: 172.04 KB dist/js/common. Js 160.28 KB dist/js/editor. 7517. DLL. Js 130.92 KB dist/js/vendor. 7517. DLL. Js 34.06 KB Dist/CSS /index.css 15.32 KB Dist /js/ cpAdd.be002d.js 5.93 KB (-144.13 KB) Dist /js/ atAdd.18beb0.js 4.45 KB Dist/js/cpsupple. 9 fe38b. Js 3.3 KB dist/js/cplist. 3 a5f02. Js 3.08 KB dist/js/cpview e68fe9. Js 2.91 KB Dist /js/atview.2a5aac.js 2.89 KB Dist /js/atlist.6d166c.js 2.24 KB Dist /js/atuser.30b019.js 295b dist/js/activity.4e286a.js 291 B dist/js/coupon.3dd30f.jsCopy the code

Efficiency increased by 46%! 😀 Careful students will notice a slight increase in the size of the package later, but this is acceptable compared to the packaging time. If you want to reduce the size, there are many internationalized files in React – draft-WySIWYG, and draft-JS does not support tree shaking, we can explore these optimizations later.