Focus on the front end and make progress every day

“~ Unlock webpack ~”

Unlock webPack Basics

1. Webpack definition

Webpack is a static module wrapper for a modern JavaScript application. When WebPack processes an application, it recursively builds a dependency graph containing each module required by the application, and then packages these modules into one or more bundles.

2. Core concepts of WebPack

1) Entry indicates which module WebPack should use as a starting point for building its internal dependency graph.

2) The output property tells WebPack where to export the bundles it creates and how to name them. The default is./dist

3) Module converter (loader) allows Webpack to process non-javascript files (Webpack itself only understands JavaScript)

4) Plugins, which range from package optimization and compression to redefining variables in the environment

3. Perform initial configuration

Create a new folder, such as Webpack-first (of course, you can use any project name you like). Recommendation: Master Webpack, according to their own needs to configure, is the best configuration.

Mkdir webpack-demo // Create folder

CD webpack-demo // Go to this folder directory

NPM init // initializes the project to generate package.json

To use Webpack, you must install webpack, webpack-CLI:

npm install webpack webpack-cli -DCopy the code

Given the rapid change in front-end technology, this article is based on the version number of WebPack

├ ─ ─ [email protected] └ ─ ─ [email protected]Copy the code

Starting with Wepack V4.0.0, WebPack is out of the box and can be used without introducing any configuration files.

Create a new SRC /index.js file and write something in it:

//index.js
class Animal {    
    constructor(name) {        
        this.name = name;    
    }    
    getName() {        
        return this.name;    
    }
}
const dog = new Animal('dog');Copy the code

Build with NPX webpack –mode=development, default is Production mode, we use development mode to see the packaged code more clearly.

Webpack has default configurations, such as the default entry file is./ SRC, which is packaged into dist/main.js by default.

If you look at the dist/main.js file, you can see that SRC /index.js has not been escaped to a lower version of the code, which is obviously not what we want.

{    
    "./src/index.js":       
         (function (module, exports) {            
            eval("class Animal {\n constructor(name) {\n this.name = name; \n }\n getName() {\n return this.name; \n }\n}\n\nconst dog = new Animal('dog'); \n\n//# sourceURL=webpack:///./src/index.js?"); })}Copy the code

4. Escape JS to a lower version

To convert JS code to a lower version, we need to use babel-loader.

Start by installing the babel-loader

npm install babel-loader -DCopy the code

In addition, we need to configure Babel, for which we install the following dependencies:

npm install @babel/core @babel/preset-env @babel/plugin-transform-runtime -D
npm install @babel/runtime @babel/runtime-corejs3Copy the code

Create webpack.config.js as follows:

//webpack.config.js
    module.exports = {    
        module: {        
            rules: [            
                {                
                    test: /\.jsx? $/, use: ['babel-loader'], exclude: /node_modules/ // exclude node_modules directory}]}}Copy the code

You are advised to specify either include or exclude for the loader. The node_modules directory usually does not need to be compiled. After excluding the node_modules directory, the compilation efficiency is improved.

Note:

Loader needs to be configured in module.rules, which is an array.

The loader format is:

{
    test: /\.jsx? $/,// use:'babel-loader'
}Copy the code

Or you could do something like this:

// Applies to only one loader {test: /\.jsx? $/, loader:'babel-loader', options: { //... }}Copy the code

The test field is a matching rule and is processed for files that match the rule.

The use field can be written several ways

1) It can be a string, such as use: ‘babel-loader’ above

Use: [‘style-loader’, ‘css-loader’]

3) Each item of the use array can be either a string or an object. When we need to configure loader in the configuration file of Webpack, we need to write it as an object and configure it in the options field of this object, for example:

rules: [    
    {           
        test: /\.jsx? $/, use: { loader:'babel-loader',            
            options: {                
                presets: ["@babel/preset-env"]            
             }        
         },        
        exclude: /node_modules/    
    }
]Copy the code

5, mode

Add mode to webpack.config.js:

module.exports = {    
    //....    
    mode: "development", module: { //... }}Copy the code

The mode configuration item tells Webpack to use the built-in optimizations for the corresponding mode.

The mode configuration item supports the following two configurations:

1) development: set process.env.node_env to development and enable NamedChunksPlugin and NamedModulesPlugin

2) production: Set process.env.node_env to production, Enable FlagDependencyUsagePlugin FlagIncludedChunksPlugin, ModuleConcatenationPlugin NoEmitOnErrorsPlugin, OccurrenceOrderPlugin, SideEffectsFlagPlugin and UglifyJsPlugin.

6. View the page in your browser

We can use the HTML-webpack-plugin to help us do this.

First, install the plugin:

npm install html-webpack-plugin -DCopy the code

Create a new public directory and create a new index.html file in it (vscode quick! + tab)

Modify the webpack.config.js file.

// const HtmlWebpackPlugin = require('html-webpack-plugin'); module.exports = { //... New HtmlWebpackPlugin({template:'./public/index.html',           
            filename: 'index.html'// Minify: {removeAttributeQuotes:false// Whether to delete attribute double quotes collapseWhitespace:false, // whether to fold blank}, //hash: true// Whether to addhashThe default isfalse}})]Copy the code

At this point, we can see that the index. HTML file is added in the dist directory, and the <script> script is automatically inserted in the file, and the js file is introduced after we pack.

More htML-webpack-plugin configuration items

How do I display it in real time in the browser

Don’t say much, first install dependence:

npm install webpack-dev-server -DCopy the code

Modify the scripts of our package.json file:

"scripts": {    
        "dev": "cross-env NODE_ENV=development webpack-dev-server"."build": "cross-env NODE_ENV=production webpack"
},Copy the code

NPM run dev in console, start normal, nothing on the page, modify our JS code, add some content to the page, normal refresh (that is, no configuration is required to use).

However, other webpack-dev-server configurations can be performed in webpack.config.js, such as specifying the port number, setting browser console messages, whether to compress, and so on:

//webpack.config.js
module.exports = {    
    //...    
    devServer: {        
        port: '3000'// Default is 8080 quiet:false// Inline is not enabled by default:true, // The inline mode is enabled by defaultfalseIframe stats:"errors-only"// Terminal only prints error overlay:false// clientLogLevel is disabled by default:"silent", // log level compress:true// Enable gzip compression}}Copy the code

7, devtool

There are some Settings in devtool that help us map the compiled code back to the original source. Different values can significantly affect the speed of builds and rebuilds.

For me, it’s just a matter of being able to locate the line of source code. Therefore, considering the build speed, I set devtool to be cheap-module-eval-source-map in development mode.

//webpack.config.js
module.exports = {    
    devtool: 'cheap-module-eval-source-map'// Use} in development environmentCopy the code

The production environment can use None or source-map. Source-map will eventually result in a separate.map file, which we can use to parse the error message and locate the source.

Source-map and hidden-source-map are both packaged to generate a separate.map file. The difference is that source-map adds a reference comment to the packaged JS file so that the developer knows where to find it. Hidden-source-map does not add reference comments to packaged JS.

8. How to handle style files

Webpack cannot handle CSS directly, you need to use loader. If it is.css, we need the loader

Install the dependencies you need to use:

npm install style-loader less-loader css-loader postcss-loader autoprefixer less -DCopy the code

A brief description of configuration:

Style-loader dynamically creates a style tag and inserts CSS into the head.

Css-loader processes statements such as @import.

Postcss-loader and Autoprefixer automatically generate browser compatibility prefixes

Less-loader processes compiled. Less files and converts them to CSS

Between us in webpack.config.js autoprefixer needs compatible browsers, just for ease of presentation. It is recommended that you create.browserslistrc in the root directory and write the corresponding rules in this file, except for autoprefixer.

Note:

Loaders are executed from right to left, that is, the later loader is executed first, and the previous loader is executed in the following order: less-loader —> postcss-loader —> css-loader —> style-loader

9. Image/font file processing

We can use url-loader or file-loader to handle local resource files. Url-loader and file-loader have similar functions, but url-loader can specify to return DataURL when the file size is smaller than the specified limit. Therefore, url-loader is preferred by individuals.

First install dependencies:

npm install url-loader -DCopy the code

Configure in webpack.config.js:

//webpack.config.js
module.exports = {    
    //...    
    modules: {        
        rules: [            
            {                
                test: /\.(png|jpg|gif|jpeg|webp|svg|eot|ttf|woff|woff2)$/,                
                use: [                    
                        {                        
                            loader: 'url-loader',                        
                            options: {                            
                                limit: 10240, //10K                            
                                esModule: false                        
                            }                    
                        }                
                     ],                
                        exclude: /node_modules/            
                    }        
                ]    
            }
}Copy the code

Limit is set to 10240, that is, when the resource size is less than 10K, the resource will be converted to Base64, and when the resource size exceeds 10K, the image will be copied to dist directory. <img SRC =[Module Object] /> ={require(‘ xxx.jpg ‘)} />

Converting resources to Base64 can reduce the number of network requests. However, the data in Base64 is large. If too many resources are Base64, the load will be slow.

10. Handle local images in HTML

Install htMl-withimg-loader.

npm install html-withimg-loader -DCopy the code

Modify the webpack. Config. Js:

module.exports = {    
    //...    
    module: {        
        rules: [            
            {                
                test: /.html$/,                
                use: 'html-withimg-loader'}}}]Copy the code

11. Entrance configuration

The entry field is entry

//webpack.config.js
module.exports = {    
        entry: './src/index.js'// Default configuration of webpack}Copy the code

The value of entry can be a string, an array, or an object.

12. Export configuration

Configuring the Output option controls how WebPack outputs compiled files.

const path = require('path');
module.exports = {    
    entry: './src/index.js',    
    output: {        
        path: path.resolve(__dirname, 'dist'), // Must be an absolute path filename:'bundle.js',        publicPath: '/'// Usually CDN address}}Copy the code

13. Clear the dist directory before each packing

We need plugin: clean-webpack-plugin, install dependency:

npm install clean-webpack-plugin -DCopy the code

Previously, the clean-webpack-plugin was exported by default, but now it is not, so be careful when referencing it. In addition, the constructor now takes an object, which can be defaulted.

//webpack.config.js
const { CleanWebpackPlugin } = require('clean-webpack-plugin'); module.exports = { //... Plugins: [// do not need to pass parameters oh, it can find outputPath new CleanWebpackPlugin()]}Copy the code

Now you modify the file and reproduce the build, and the resulting hash is different from the previous DIST, but because each clean-webpack-plugin helps us clean out a wave of dist directories first.

14. Hot updates

1) First set devServer’s hot to true

2) and add new plugins in webpack. HotModuleReplacementPlugin ()

//webpack.config.js
const webpack = require('webpack');
module.exports = {    
    //....    
    devServer: {        
        hot: true}, plugins: [new webpack HotModuleReplacementPlugin () / / hot update plugins]}Copy the code

15. Multi-page application packaging

//webpack.config.js
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {    
    entry: {        
        index: './src/index.js',        
        login: './src/login.js'    
    },    
    output: {        
        path: path.resolve(__dirname, 'dist'),        
        filename: '[name].[hash:6].js'    
    },    
    //...    
    plugins: [        
        new HtmlWebpackPlugin({            
            template: './public/index.html',            
            filename: 'index.html'}), new HtmlWebpackPlugin({template:'./public/login.html',            
            filename: 'login.html'// Packaged file name}),]}Copy the code

Use Webpack to solve cross-domain problems

Assuming that the front-end is at port 3000 and the server is at port 4000, we implement cross-domain through webPack configuration.

First, we create a server.js locally:

let express = require('express');
let app = express();
app.get('/api/user', (req, res) => {    
    res.json({name: 'Joe'});
});
app.listen(4000);Copy the code

Request/API /user in index.js and modify index.js as follows:

Fetch (localhost:4000 (server))"/api/user")    
    .then(response => response.json())    
    .then(data => console.log(data))    
    .catch(err => console.log(err));Copy the code

Configure the agent

Modify the WebPack configuration:

//webpack.config.jsmodule.exports = {    
    //...    
    devServer: {        
        proxy: {            \
            "/api": "http://localhost:4000"}}}Copy the code

Rerunning NPM run dev, you can see that the console prints {name: “Zhang SAN “}, implementing cross-domain.



2. Unlock webPack optimization

1, quantitative

Sometimes, when what we think of as optimization is negative optimization, it would be nice to have a quantitative indicator to see before and after.

The speed-measure-webpack-plugin can measure the time spent by various plug-ins and loaders. After use, when building, you will get information like the following:



The Speed-measure-webpack-plugin is easy to use and can be wrapped directly with it
WebpackConfiguration:
//webpack.config.js
const SpeedMeasurePlugin = require("speed-measure-webpack-plugin"); const smp = new SpeedMeasurePlugin(); const config = { //... Module.exports = smp.wrap(config);Copy the code

2, exclude/include

We can use exclude and include configurations to ensure that as few files are translated as possible. As the name implies, exclude specifies the files to exclude and include specifies the files to include.

Exclude has a higher priority than include. Use an absolute path array in include and exclude. Avoid exclude and prefer include.

//webpack.config.js
const path = require('path');
module.exports = {    
//...    
module: {        
    rules: [            
        {                
            test: /\.js[x]? $/, use: ['babel-loader'],                
            include: [path.resolve(__dirname, 'src']}]},}Copy the code

3, the cache – loader

Add cache-loader before some performance expensive loaders to cache the results to disk. The default directory is node_modueles/. Cache /cache-loader.

First install dependencies:

npm install cache-loader -DCopy the code

The configuration of cache-loader is simple and can be placed before other loaders. Modify the Webpack configuration as follows:

module.exports = { //... Module: {// In my project,babel-loader takes a long time, so I have configured it with 'cache-loader' rules: [{test: /\.jsx? $/, use: ['cache-loader'.'babel-loader'}]}}Copy the code

4. Remove common code

Pulling out common code is for multi-page applications. If multiple pages introduce some common modules, they can be pulled out and packaged separately. Common code only needs to be downloaded once and then cached, avoiding repeated downloads. The CommonsChunkPlugin has been removed.

Pulling out common code should make no difference in configuration between a single page application and a multi-page application, all configured in optimization.splitchunks.

//webpack.config.js module.exports = {optimization: {splitChunks: {// cacheGroups: {vendor: {// 1, // Set the priority, first remove the third-party module name:'vendor'.test: /node_modules/,                    
                        chunks: 'initial', minSize: 0, minChunks: 1 // introduce at least 1}, // cache group common: {// common module chunks:'initial',                    
                            name: 'common', minSize: 100, // Over 100 bytes minChunks: 3 // introduced at least 3 times}}}}}Copy the code

5, the CDN

For the processing of static resources, adding CDN is a good choice. The configuration of CDN in Webpack is as follows:

output: {    
        path: path.resolve(__dirname, 'dist'),    
        filename: '[name]_[hash:8].js',    
        publicPath: 'http://static.xxxx.com/'
},Copy the code

6, happypack

With a large number of files to parse and process, building is a file read and write and computation-intensive operation, and the Webpack build slowness can become a serious problem especially as the number of files increases. File reads and writes and computations are inevitable, so what if Webpack could handle multiple tasks at a time, leveraging the power of a multi-core CPU computer to speed up builds?

HappyPack allows Webpack to do this by splitting tasks into sub-processes for concurrent execution, which then send the results back to the main process.

First you need to install happypack:

npm install happypack -DCopy the code

Modifying a configuration file:

const Happypack = require('happypack');
module.exports = {    
    //...    
    module: {        
            rules: [            
                {                
                    test: /\.js[x]? $/, use:'Happypack/loader? id=js',                
                    include: [path.resolve(__dirname, 'src')]}, {test: /\.css$/,                
                    use: 'Happypack/loader? id=css',                
                    include: [                    
                            path.resolve(__dirname, 'src'),                    
                            path.resolve(__dirname, 'node_modules'.'bootstrap'.'dist')                
                    ]            
                   }        
                ]    
            },    
            plugins: [        
                new Happypack({            
                        id: 'js'If id=js, use: ['babel-loader'] // Must be array}), new Happypack({id:'css',// and rule id= CSS corresponding to use: ['style-loader'.'css-loader'.'postcss-loader'],})]}Copy the code

When postcss-loader is configured in Happypack, postcss.config.js must be created in the project.

//postcss.config.js
module.exports = {    
        plugins: [        
            require('autoprefixer') (the)]}Copy the code

In addition, if your project is not very complex, you don’t need to configure Happypack, because process allocation and management also take time, which does not improve the build speed, or even slow down.

7, HardSourceWebpackPlugin

HardSourceWebpackPlugin provides an intermediate cache for modules. The default cache path is node_modules/. Cache /hard-source.

With the hard-source-webpack-plugin, the first build time doesn’t change much, but the second build time can be saved by about 80%.

First install dependencies:

npm install hard-source-webpack-plugin -DCopy the code

Modify webPack configuration:
//webpack.config.js
    var HardSourceWebpackPlugin = require('hard-source-webpack-plugin');
    module.exports = {    
        //...    
        plugins: [        
            new HardSourceWebpackPlugin()    
        ]}Copy the code

Build output analysis
The code output from Webpack was very unreadable and the files were very large, which gave us a headache. In order to analyze the output more easily and intuitively, a number of visual analysis tools have emerged in the community. Next, we’ll look at the analysis tool used in the VUE project: Webpack-bundle-Analyzer.
Configure webpack.prod.conf.js in the project:
if (config.build.bundleAnalyzerReport) {  
    const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin  
    webpackConfig.plugins.push(new BundleAnalyzerPlugin())
}Copy the code

The analysis report is generated after executing $NPM run build –report

Find this article helpful? Please share it with more people

Pay attention to “front-end academy” plus star mark, improve front-end skills