Skip to content

webpack

webdesc
office中文

常用模块

sh
pnpm add -D webpack webpack-cli html-webpack-plugin css-loader style-loader sass-loader webpack-dev-server copy-webpack-plugin mini-css-extract-plugin uglifyjs-webpack-plugin css-minimizer-webpack-plugin ejs-loader clean-webpack-plugin

热加载

sh
pnpm add -D webpack-dev-server

loader

模版内联loader

sh
import 'style-loader!css-loader!./index.css'

自定义loader

js
// xxx-loader.js
const REG = /<script>([\s\S]+?)<\/script>/
module.exports = function (source) {
    console.log('test-loader');
    const __source__ = source.match(REG)
    console.log(__source__);
    return __source__ && __source__[1] ? __source__[1] : ''
}

if (require.main === module) {
    const source = `
        <script>
            console.log('test')
        </script>
    `
    __source__ = source.match(REG)
    console.log(__source__)
}

plugin

hooks

自定义plugin

js
// FooterPlugin.js
const {ConcatSource} = require("webpack-sources");

class FooterPlugin {
    constructor(options) {
        this.options = options;
        console.log('FooterPlugin constructor', options);
    }

    apply(compiler) {
        console.log('This is my footer plugin!', typeof compiler);
        compiler.hooks.compilation.tap('FooterPlugin', (compilation) => {
            compilation.hooks.processAssets.tap('FooterPlugin', (assets) => {
                const chunks = compilation.chunks;
                console.log(chunks);
                for (const chunk of compilation.chunks) {
                    for (const file of chunk.files) {
                        console.log('file: ', file);
                        const comment = `/* ${this.options.banner} */`;
                        compilation.updateAsset(file, (old) => new ConcatSource(old, '\n', comment));
                    }
                }
            })
        })
    }
}

module.exports = FooterPlugin

优化

treeshaking

  1. 通过解构的方式获取方法
  2. 调用的npm包必须使用ESM,如lodash,lodash-es
  3. 同一文件的treeshaking触发条件是在mode=production
  4. 一定要使用解构来加载模块,不要导出对象使用,如lodash,要用{get}代替_.get

配置

基础配置

js
const HtmlWebpackPlugin = require('html-webpack-plugin');
const webpack = require('webpack');
const path = require('path');
const CopyWebpackPlugin = require('copy-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const UglifyjsPlugin = require('uglifyjs-webpack-plugin');
const cssMinimizerPlugin = require('css-minimizer-webpack-plugin');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');


module.exports = {
    mode: 'development',
    // mode: 'production',
    devServer: {
        static: {
            directory: path.join(__dirname, '../dist'),
        },
        compress: true,
        port: 9000,
        hot: true,
    },
    entry: {
        index: path.resolve(__dirname,'../src/index.js'),
        login: path.resolve(__dirname,'../src/login.js')
    },
    output: {
        filename: 'js/[name]-[hash:6].js',
        path: path.resolve(__dirname, '../dist')
    },
    module: {
        rules: [
            {
                test: /\.css$/,
                use: [MiniCssExtractPlugin.loader, 'css-loader'] //MiniCssExtractPlugin.loader 替换 style-loader
            },
            {
                test: /\.(png|jpg|gif|jpeg)$/i, // 匹配图片文件
                type: "asset", // 使用资源模块
                parser: {
                    dataUrlCondition: {
                        maxSize: 4 * 1024,
                    },
                },
                generator: { // 自定义文件输出路径
                    filename: 'images/[name].[hash:6][ext]'
                }
            },
            {
                test: /\.ejs/,
                loader: "ejs-loader",
                options: {
                    esModule: false
                }
            }
        ]
    },
    plugins: [
        new HtmlWebpackPlugin({
            template: path.resolve(__dirname,'../src/index.html'),
            filename: 'index.html',
            chunks: ['index']
        }),
        new HtmlWebpackPlugin({
            template: path.resolve(__dirname,'../src/login.html'),
            filename: 'login.html',
            chunks: ['login']
        }),
        new webpack.ProvidePlugin({ // 全局引入jQuery
            $: 'jquery'
        }),
        new webpack.ProvidePlugin({ // 全局引入jQuery
            jQuery: 'jquery'
        }),
        new CopyWebpackPlugin({
            patterns: [
                {
                    from: path.resolve(__dirname, '../src/img'),
                    to: path.resolve(__dirname, '../dist/img')
                }
            ]
        }),
        new MiniCssExtractPlugin({
            filename: 'css/[name].[hash:6].css',
            chunkFilename: 'css/[name].[hash:6].chunk.css'
        }),
        new CleanWebpackPlugin()
    ],
    //压缩和剥离
    optimization: {
        minimize: true,
        minimizer: [
            new UglifyjsPlugin({
                sourceMap: true
            }),
            new cssMinimizerPlugin(),
        ],
        splitChunks: {
            chunks: 'all',
            minSize: 30 * 1024,
            name: 'common',
            cacheGroups: {
                jquery: {
                    name: 'jquery',
                    test: /jquery/,
                    chunks: 'all'
                }
            }
        },
    }
}

自定义vue环境配置

sh
pnpm add vue-template-compiler @vue/compiler-sfc vue-loader --save-dev

性能分析

插件desc
speed-measure-webpack-plugin