start

Preface: Webpack has been in use since entering the line until now, during which I have learned some things intermittently. The article plans to record what I learned from it. Just recently, Webpack 5 has been updated

Version 5.65.0 is used for this article

Initialize the project

1. Create folder, initialize NPM and install Webpack

NPM init // Enter all the way to NPM I webpack webpack-cli -dCopy the code

2. Create the project entry file SRC /index.js with a console

console.log('hello')
Copy the code

Initial Configuration

1. Create webPack configuration file, set entry and Output

We create webpack.config.js directly in the current directory

const path = require('path') module.exports = { entry: { index: path.resolve(__dirname, 'src/index.js') }, output: Resolve (__dirname, 'dist'), filename: '[name].js', clean: true // Clear directory before each packing}}Copy the code

In older versions, clean uses the clean-webpack-plugin

2, Add build command, add build command to script in package.json

"scripts": {
    "build": "webpack --config webpack.config.js"
},
Copy the code

3. Run NPM run build, and if nothing goes wrong, it will generate dist/index.js, which is all we need to reference

html-webpack-plugin

We could write an index. HTML file in the dist directory by hand, but with clean enabled, it would not be appropriate to write every package by hand. In this case, we could use a plugin to solve the HTML-webpack-plugin

1. Install htML-webpack-plugin

npm i html-webpack-plugin -D
Copy the code

2. Add plugins to package.json

plugins: [
    new HtmlWebpackPlugin({
        template: path.resolve(__dirname, './index.html'),
        filename: 'index.html'
    })
]
Copy the code

3. Run NPM run build again

We can see that after build the dist directory came with index.html, and the HTML automatically introduced index.js. We even kindly added defer, which you can add if you don’t want to for compatibility

scriptLoading: 'blocking'
Copy the code

More configuration

Development mode

Now we can do very simple packaging, but there is still a lot of work to do, for example, every time we change the file, we need to repackage the code to see the effect, which is very unfriendly to development, so we need a development mode, there are two common ones, Watch and devServer

watch

This mode, as the name indicates, is automatically packaged to listen for file changes, and is easy to configure. We only need to add a command

"watch": "webpack --config webpack.config.js --watch"
Copy the code

Then we run NPM run watch to see that the current process did not terminate, tried to change index.js, repackaged, the contents of index.js also changed

devServer

This mode is to start a service locally that listens for changes, automatically refreshes, and so on

1. Install webpack-dev-server

npm i webpack-dev-server -D
Copy the code

2. Add configuration to webpack.config.js

DevServer: {port: 3000, // port open: true, // automatically open compress: true, // Enable gzip compression client: {progress: true // Browser printing progress}}Copy the code

Package. json add command

"dev": "webpack serve --config webpack.config.js"
Copy the code

After that we run NPM dev. After that the browser automatically opens localhost:3000 and changes to index.js will refresh automatically

Support the React

Now we need to add React support for our project

Install Babel

NPM i@babel /preset-env -d // NPM i@babel /preset-env -d // Escape JS syntax, promise, async, etc. NPM i@babel /preset-react -d // React syntax (JSX) NPM I babel-loader -d //loaderCopy the code

Configure the loader

1. Add webPack configuration, yes Babel handles our JS and JSX files

Module: {rules: [{test: / (\. JSX | \. Js) $/, use: [" Babel - loader "], exclude: excludes node_modules files/node_modules / / /}],}Copy the code

2. Add the Babel configuration, add the babel.config.js file under the project, and add the following configuration

{
    "presets": [
        [
            "@babel/preset-env",
            {
                "useBuiltIns": "usage",
                "corejs": 3
            }
        ],
        "@babel/preset-react"
    ]
}
Copy the code

Add. Browserslistrc file to configure browserslist

> 1%
last 2 versions
not ie <= 8
Copy the code

4. Test code

index.js

import {render} from 'react-dom'
import React from 'react'
import App from './App';

render(<App />, document.getElementById('root'))
Copy the code

App.js

import React from 'react'

const App = () => {
    return <div>Hello React</div>
}

export default App
Copy the code

Then run NPM run dev and it will work

Handle exceptions

You might see a warning when it runs here

asset size limit: The following asset(s) exceed the recommended size limit (244 KiB). This can impact web performance.
Copy the code

This is because the size of a single file exceeds the size of the Webpack performance item configuration, which can be skipped in webPack plus the following configuration

performance: {
    hints: false 
},
Copy the code

With CSS

Working with CSS filescss-loader style-loader

1. Install dependencies

NPM I CSs-loader -d // Processes the CSS file. NPM I style-loader -d // Inserts the CSS file with style after processingCopy the code

2. Add the configuration under rules

{
    test: /\.css$/,
    use:["style-loader","css-loader"],
    exclude: /node_modules/
},
Copy the code

Now let’s import a CSS file and see that we have a style in our packaged page

Process SCSS filessass-loader sass

1. Install dependencies

NPM I sass -d // core NPM I sass-loader -d // loaderCopy the code

2. Add the configuration under rules

{
    test: /\.s(a|c)ss$/,
    use:["style-loader","css-loader","sass-loader"],
    exclude: /node_modules/
}
Copy the code

Separating CSS files

We now have a configuration that inserts CSS into JS, and then uses the style tag to insert the JS when it is executed. This significantly increases the package size of JS. In production environments, we usually separate CSS and JS files, which requires the use of a webpack plugin called mini-CSS-extract-plugin. We can still use style-loader in the development environment because it is faster than the mini-CSs-extract-plugin

1, install,

npm i mini-css-extract-plugin -D
Copy the code

2, use,

. const MiniCssExtractPlugin = require('mini-css-extract-plugin'); const IS_DEV = process.env.NODE_ENV === 'development' ... {test: /\. CSS $/, use: [IS_DEV? "style-loader" : MiniCssExtractPlugin.loader, "css-loader"], exclude: /node_modules/ }, { test: /\.s(a|c)ss$/, use: [IS_DEV ? "style-loader" : MiniCssExtractPlugin.loader, "css-loader", "sass-loader"], exclude: /node_modules/} // Add new MiniCssExtractPlugin({filename: '[name].[hash].css' // Generate hash name}),Copy the code

CSSModule

You only need to enable modules in CSS-loader. The configuration is as follows

{
    test: /\.s(a|c)ss$/,
    use: [
        IS_DEV ? "style-loader" : MiniCssExtractPlugin.loader,
        {
            loader: "css-loader",
            options: {
                modules: {
                    localIdentName: '[local]--[hash:base64:5]'
                },
            }
        },
        "sass-loader"
    ],
    exclude: /node_modules/
}
Copy the code

usepostcssAutomatically adds the vendor prefix

Function: Auto each browser vendor prefix

1, install,

npm i postcss -D
npm i postcss-loader -D
npm i postcss-preset-env -D
Copy the code

2, configuration,

Add postCSS-loader to handle CSS location in Webpack after adding

{
    test: /\.s(a|c)ss$/,
    use: [
        IS_DEV ? "style-loader" : MiniCssExtractPlugin.loader,
        {
            loader: "css-loader",
            options: {
                modules: {
                    localIdentName: '[local]--[hash:base64:5]'
                },
                sourceMap: IS_DEV
            }
        },
        "postcss-loader",
        "sass-loader"
    ],
    exclude: /node_modules/
}
Copy the code

Then create a configuration file postcss.config.js in the root directory

module.exports = {
    plugins: [
        ['postcss-preset-env']
    ]
}
Copy the code

Handle fileassetreplacefile-loaderurl-loader

Before Webpack5, we deal with image resource files generally file-loader combined with URL-loader, small files base64 into JS, large files output files, Webpack5 directly has its own file processing function assetModule, configuration is relatively simple

{ test: /\.(png|svg|jpg|jpeg|gif)$/i, type: 'asset', parser: { dataUrlCondition: { maxSize: }}, Generator: {filename: 'static/[hash][ext][query]'}}Copy the code

To distinguish the environment

We usually have two environments in development, development environment and production environment. Webpack provides mode for us to distinguish configuration, while in packaging configuration, the same Loader may be configured differently for different environments, which makes us need two different configuration files

1. First we install the dependencies we need

NPM I webpack-merge -d // Merge configuration files NPM I cross-env -d // process.env is compatible with multiple environmentsCopy the code

2. Create a build directory for the package configuration and create the following file

  • webpack.development.jsDevelopment Environment Configuration
Module. exports = {mode: 'development', performance: {hints: false}, devServer: {port: 1000, // port open: Client: {progress: true // Browser printing progress}}}Copy the code
  • webpack.production.jsDevelopment Environment Configuration
module.exports = {
    mode: "production"
}
Copy the code
  • webpack.common.jsCommon configuration, used by both dev and PROd environments
const path = require('path'); const HtmlWebpackPlugin = require('html-webpack-plugin'); module.exports = { entry: { index: path.resolve(__dirname, '.. /src/index.js') }, output: { path: path.resolve(__dirname, '.. /dist'), filename: '[name].js', clean: true }, module: { rules: [ { test: /(\.jsx|\.js)$/, use: ["babel-loader"], exclude: /node_modules/ } ], }, plugins: [ new HtmlWebpackPlugin({ template: path.resolve(__dirname, '../index.html'), filename: 'index.html', scriptLoading: 'blocking' }) ] }Copy the code
  • webpack.config.jsUse different configurations depending on your environment
const merge = require('webpack-merge').default;
const commonConfig = require('./webpack.common');
const devConfig = require('./webpack.development');
const proConfig = require('./webpack.production');

module.exports = () => {
    if(process.env.NODE_ENV === 'development') {
        return merge(commonConfig, devConfig, {mode: 'development'})
    }
    return merge(commonConfig, proConfig, {mode: 'production'})
}
Copy the code

3. Modify the command

"build": "cross-env NODE_ENV=production webpack --config ./build/webpack.config.js",
"dev": "cross-env NODE_ENV=development webpack serve --config ./build/webpack.config.js"
Copy the code

Now we run NPM run dev during development, and run NPM run build package online

Why usecross-env

This is because different system commands vary when setting environment variables

  • Windows
set NODE_ENV=development
Copy the code
  • Max
export NODE_ENV=development
Copy the code

Cross-env helps us to be compatible with different systems

At the end

The React project has been developed and packaged with many optimizations, which will be written later