项目中如何快速接入Webpack5

164 阅读4分钟

本文记录简单的webpack接入流程,不涉及深入的性能优化。本文基于webpack5进行构建。

首先在项目的根目录创建package.json文件,可以通过npm init进行初始化创建。

第一步,区分环境进行分别配置

在根目录下创建webpack.base.js,webpack.dev.jswebpack.prod.js三个文件。

通用的配置放在webpack.base.js中,在另外两个文件通过webpack-merge插件进行配置项的merge。

webpack.dev.js的配置

const path = require('path');
const {merge} = require('webpack-merge');
const common = require('./webpack.base.js');
module.exports = merge(common,{
    mode: "development",
    devtool: 'inline-source-map',
});

webpack.prod.js的配置


const path = require('path');
const {merge} = require('webpack-merge');
const common = require('./webpack.config.js');
const Webpack5QCDNFile = require('@q/webpack5-qcdn-file');
module.exports = merge(common,{
    mode: "production",
    plugins: [
        new Webpack5QCDNFile({
                    qcdnOpt: {
                    https: true,
                    image: {
                    https: true,
                    domains: [
                        "so1.xxx.com",
                        "so2.xxx.com",
                        "so3.xxx.com",
                        "so4.xxx.com",
                        "so5.xxx.com",
                    ]
                },
                static: {
                    domains: [
                        "ss1.xxx.com",
                        "ss2.xxx.com",
                        "ss3.xxx.com",
                        "ss4.xxx.com",
                        "ss5.xxx.com",
                    ],
                }
            },
            resPath: path.resolve(__dirname, "dist")
        })
    ]
});

接下来配置package.json中的scripts


......
"scripts": {
    "dev": "webpack --watch --config webpack.dev.js",
    "build": "webpack --config webpack.prod.js"
}

......

第二步,配置webpack.base.js

项目中最基本的需求是JS和CSS文件的编译打包处理。

首先配置入口文件和输出的文件及路径

const distPath = path.join(__dirname, "dist");
module.exports = {
    entry: './assets/common/base.js',
    output: {
        filename: 'js/[name].bundle.js',
        path: distPath,
    },
}

在base.js文件中,可以把CSS和JS都放在这个文件中,webpack会根据配置进行处理。

// base.js的文件内容
import './reset.less';
import './common.less';
import $ from 'zepto';
$('.js-next-query').on('click',function(e){
//
});

接下来处理CSS和JS的编译

const distPath = path.join(__dirname, "dist");
const htmlTplPath = path.join(__dirname, "templates");
const htmlBuildPath = path.join(__dirname, "views");
module.exports = {
    entry: './assets/common/base.js',
    output: {
        filename: 'js/[name].bundle.js',
        path: distPath,
    },
    module: {
        rules: [
            {
                // 模块规则(配置loader,解析器等选项)
                test: /\.js$/i,
                use: [{
                    loader: 'babel-loader',
                    options: {
                        presets: ['@babel/preset-env'],
                        plugins: []
                    }
                }],
                exclude: /node_modules/,
            },
            {
                test: /\.(less|css)$/i,
                use: [
                    'style-loader',
                    'css-loader',
                    {
                        loader: 'postcss-loader',
                        options: {
                            postcssOptions: {
                                plugins: [
                                    require('postcss-preset-env')({
                                        browsers: 'last 4 versions',
                                    })
                                ]
                            }
                        }
                    },
                    'less-loader'
                ],
            }
        ]
    }
}

如果想把CSS也抽取成独立的文件,需要借助mini-css-extract-plugin插件

const path = require('path');
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const distPath = path.join(__dirname, "dist");
const htmlTplPath = path.join(__dirname, "templates");
const htmlBuildPath = path.join(__dirname, "views");
module.exports = {
    entry: './assets/common/base.js',
    output: {
        filename: 'js/[name].bundle.js',
        path: distPath,
    },
    module: {
        rules: [
            {
                // 模块规则(配置loader,解析器等选项)
                test: /\.js$/i,
                use: [{
                    loader: 'babel-loader',
                    options: {
                        presets: ['@babel/preset-env'],
                        plugins: []
                    }
                }],
                exclude: /node_modules/,
            },
            {
                test: /\.(less|css)$/i,
                use: [
                    'style-loader',
                    {
                        loader: MiniCssExtractPlugin.loader,
                    },
                    'css-loader',
                    {
                        loader: 'postcss-loader',
                        options: {
                            postcssOptions: {
                                plugins: [
                                    require('postcss-preset-env')({
                                        browsers: 'last 4 versions',
                                    })
                                ]
                            }
                        }
                    },
                    'less-loader'
                ],
            }
        ],
        plugins: [
            new MiniCssExtractPlugin({
                filename: "css/[name].bundle.css"
            }),
        ]
    }
}

文件打包好之后需要引用的地方替换成最新的,可以借助html-webpack-plugin插件。


const path = require('path');
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const HtmlWebpackPlugin = require('html-webpack-plugin');

const distPath = path.join(__dirname, "dist");
const htmlTplPath = path.join(__dirname, "templates");
const htmlBuildPath = path.join(__dirname, "views");
module.exports = {
    entry: './assets/common/base.js',
    output: {
        filename: 'js/[name].bundle.js',
        path: distPath,
    },
    module: {
        rules: [
            {
                // 模块规则(配置loader,解析器等选项)
                test: /\.js$/i,
                use: [{
                    loader: 'babel-loader',
                    options: {
                        presets: ['@babel/preset-env'],
                        plugins: []
                    }
                }],
                exclude: /node_modules/,
            },
            {
                test: /\.(less|css)$/i,
                use: [
                    'style-loader',
                    {
                        loader: MiniCssExtractPlugin.loader,
                    },
                    'css-loader',
                    {
                        loader: 'postcss-loader',
                        options: {
                            postcssOptions: {
                                plugins: [
                                    require('postcss-preset-env')({
                                        browsers: 'last 4 versions',
                                    })
                                ]
                            }
                        }
                    },
                    'less-loader'
                ],
            }
        ],
        plugins: [
            new MiniCssExtractPlugin({
                filename: "css/[name].bundle.css"
            }),
            new HtmlWebpackPlugin({
                filename: path.join(htmlBuildPath, 'index.html'), // 处理后的文件路径
                template: path.join(htmlTplPath, `index.html`), // 待处理的文件路径
                inject: 'body', // js文件在body的底部插入
                minify: false // 是否开启html代码的压缩
            }),
        ]
    }
}

配置完后基本上就可以使用了

Zepto这类不支持import使用库的接入

zepto不支持common.js这样在使用时就不能使用import的形式。可以通过exports-loaderscript-loader插件解决。

需要再webpack配置的rules中处理:

{
    test: require.resolve('zepto'),
    use: [
        'exports-loader?window.Zepto',
        'script-loader'
    ]
}

完整的配置如下:


const path = require('path');
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const HtmlWebpackPlugin = require('html-webpack-plugin');

const distPath = path.join(__dirname, "dist");
const htmlTplPath = path.join(__dirname, "templates");
const htmlBuildPath = path.join(__dirname, "views");
module.exports = {
    entry: './assets/common/base.js',
    output: {
        filename: 'js/[name].bundle.js',
        path: distPath,
    },
    module: {
        rules: [
            {
                // 模块规则(配置loader,解析器等选项)
                test: /\.js$/i,
                use: [{
                    loader: 'babel-loader',
                    options: {
                        presets: ['@babel/preset-env'],
                        plugins: []
                    }
                }],
                exclude: /node_modules/,
            },
            {
                test: /\.(less|css)$/i,
                use: [
                    'style-loader',
                    {
                        loader: MiniCssExtractPlugin.loader,
                    },
                    'css-loader',
                    {
                        loader: 'postcss-loader',
                        options: {
                            postcssOptions: {
                                plugins: [
                                    require('postcss-preset-env')({
                                        browsers: 'last 4 versions',
                                    })
                                ]
                            }
                        }
                    },
                    'less-loader'
                ],
            },
            {
                test: require.resolve('zepto'),
                use: [
                    'exports-loader?window.Zepto',
                    'script-loader'
                ]
            }
        ],
        plugins: [
            new MiniCssExtractPlugin({
                filename: "css/[name].bundle.css"
            }),
            new HtmlWebpackPlugin({
                filename: path.join(htmlBuildPath, 'index.html'), // 处理后的文件路径
                template: path.join(htmlTplPath, `index.html`), // 待处理的文件路径
                inject: 'body', // js文件在body的底部插入
                minify: false // 是否开启html代码的压缩
            }),
        ]
    }
}

代码中使用了zepto这个脚本库,在生产环境通常直接使用zepto的cdn地址,文件打包时就需要将zepto排除。可以在webpack的配置文件中配置


externals: {
    zepto: 'Zepto'
}

最终版完整的代码:


const path = require('path');
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const HtmlWebpackPlugin = require('html-webpack-plugin');

const distPath = path.join(__dirname, "dist");
const htmlTplPath = path.join(__dirname, "templates");
const htmlBuildPath = path.join(__dirname, "views");
module.exports = {
    entry: './assets/common/base.js',
    output: {
        filename: 'js/[name].bundle.js',
        path: distPath,
    },
    module: {
        rules: [
            {
                // 模块规则(配置loader,解析器等选项)
                test: /\.js$/i,
                use: [{
                    loader: 'babel-loader',
                    options: {
                        presets: ['@babel/preset-env'],
                        plugins: []
                    }
                }],
                exclude: /node_modules/,
            },
            {
                test: /\.(less|css)$/i,
                use: [
                    'style-loader',
                    {
                        loader: MiniCssExtractPlugin.loader,
                    },
                    'css-loader',
                    {
                        loader: 'postcss-loader',
                        options: {
                            postcssOptions: {
                                plugins: [
                                    require('postcss-preset-env')({
                                        browsers: 'last 4 versions',
                                    })
                                ]
                            }
                        }
                    },
                    'less-loader'
                ],
            },
            {
                test: require.resolve('zepto'),
                use: [
                    'exports-loader?window.Zepto',
                    'script-loader'
                ]
            }
        ],
        plugins: [
            new MiniCssExtractPlugin({
                filename: "css/[name].bundle.css"
            }),
            new HtmlWebpackPlugin({
                filename: path.join(htmlBuildPath, 'index.html'), // 处理后的文件路径
                template: path.join(htmlTplPath, `index.html`), // 待处理的文件路径
                inject: 'body', // js文件在body的底部插入
                minify: false // 是否开启html代码的压缩
            }),
        ],
        externals: {
            zepto: 'Zepto'
        }
    }
}

package.json配置

{
  "name": "test",
  "version": "1.0.0",
  "description": "test",
  "main": "index.js",
  "private": "true",
  "scripts": {
    "dev": "webpack --progress  --profile   --watch --config webpack.dev.js",
    "build": "webpack --config webpack.prod.js"
  },
  "author": "xxx",
  "license": "ISC",
  "dependencies": {
    "webpack": "^5.75.0",
    "webpack-cli": "^5.0.1"
  },
  "devDependencies": {
    "@babel/core": "^7.21.0",
    "@babel/preset-env": "^7.20.2",
    "@q/webpack5-qcdn-file": "^1.0.0",
    "babel-loader": "^9.1.2",
    "css-loader": "^6.7.3",
    "exports-loader": "^4.0.0",
    "html-webpack-plugin": "^5.5.0",
    "less": "^4.1.3",
    "less-loader": "^11.1.0",
    "mini-css-extract-plugin": "^2.7.2",
    "postcss-loader": "^7.0.2",
    "postcss-preset-env": "^8.0.1",
    "script-loader": "^0.7.2",
    "style-loader": "^3.3.1",
    "webpack-merge": "^5.8.0",
    "zepto": "^1.2.0",
  }
}