WebPack

核心概念

Entry(输入):定义打包文件从哪个文件开始打包

Output(输出):定义文件打包后放在哪里,包叫什么

Loader(翻译):定义非js文件处理逻辑,把这些文件转换为js文件

Plugins(插件):做一些更复杂的操作,包括压缩解压

Mode(模式):分为生产模式和开发模式

配置

初始化:npm init

下载:webpack_test

npm i webpack webpack-cli

开发依赖:npm i webpack webpack-cli -D

新建文件夹:src和build(处理打包后文件)

打包指令:

开发环境:webpack (入口文件路径(要打包的文件路径)) --output-path=(出口文件路径(打包后的文件放置目录)) --output-filename=(出口文件名)--mode=development

生产环境:webpack (入口文件路径(要打包的文件路径)) --output-path=(出口文件路径(打包后的文件放置目录)) --output-filename=(出口文件名)--mode=production

结论:

1、webpack能处理js/json文件,不能处理css/img等文件

2、生产环境和开发环境是将ES6模块化变异常浏览器能识别的模块化

3、生产环境比开发环境多一个压缩js代码

开发模式&生产模式

开发模式:能让代码本地调试运行的环境(将写的代码变成浏览器能识别的代码)

生产模式:能让代码优化上线运行的环境(闪屏现象,代码压缩,兼容性问题)

开发模式

打包样式资源

新建webpack.config.js文件:

配置(最好在最外面文件夹下载):

npm init

npm i webpack webpack-cli -D

npm i css-loader style-loader less-loader -D

npm i less -D

打包css文件:

const {resolve}=require('path')
module.exports={
    //webpack配置
    //入口起点(index.js文件里面引入需要打包的文件)
    entry:'./src/index.js',
    //输出
    output:{
        //文件名
        filename:'built.js',
        //输出路径
        //__dirname node.js的变量,表示当前文件目录的绝对路径,然后输出到build目录下
        path:resolve(__dirname,'build')

    },
    //loader的配置
    module:{
        rules:[
            //详细的loader配置
            {
                //匹配哪些文件
                test:/\.css$/,
                use:[//use中的执行顺序:从右到左,从下到上
                    //创建style标签,将js中的洋柿子园插入进行,添加到head中生效
                    'style-loader',
                    //将css文件变成commonjs模块加载js中,里面内容是样式字符串
                    'css-loader'
                ]
            },
        ]
    },
    //plugins的配置
    plugin:[],
    //模式
    mode:'development',
    // mode:'production'
}

打包less文件:

const {resolve}=require('path')
module.exports={
    entry:'./src/index.js',
    output:{       
        filename:'built.js',             
        path:resolve(__dirname,'build')

    },   
    module:{
        rules:[           
            {
                test:/\.less$/,
                use:[
                    'style-loader',
                    'css-loader',
                    // 把less文件编译成css文件
                    'less-loader'
                ]
            }
        ]
    },    
    plugin:[],    
    mode:'development',
    // mode:'production'
}

页面呈现:

build/index.html文件

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>wabpack</title>
  </head>
  <body>
    //引入打包后的js文件
    <script src="./built.js"></script>
  </body>
</html>

打包文件配置运行:webpack(在需要运行的文件下运行)

打包html资源

配置:npm i html-webpack-plugin -D

webpack.config.js文件:

const {resolve}=require('path');
const HtmlWebpackPlugin=require('html-webpack-plugin')
module.exports={
    entry:'./src/index.js',
    output:{
        filename:'built.js',
        path:resolve(__dirname,'build')
    },
    module:{
        rules:[]
    },
    plugins:[
        //处理html资源
        //功能:默认创建一个空的HTML,自动引入打包输出的所有资源(JS/CSS)
        //new HtmlWebpackPlugin()
        new HtmlWebpackPlugin({
            //复制 ./src/index.html 文件,并自动引入打包输出的所有资源(JS/CSS)
            template:'./src/index.html'
        })
    ],
    mode:"development"
}

注:不要自己在build/index.html文件中再引入一次

打包图片资源

配置:

npm i url-loader file-loader -D

npm i html-loader -D

打包样式里面的图片资源:

const {resolve}=require('path');
const HtmlWebpackPlugin=require('html-webpack-plugin');
module.exports={
    entry:'./src/index.js',
    output:{
        filename:'built.js',
        path:resolve(__dirname,'build'),
    },
    module:{
        rules:[
            {
                test:/\.less$/,
                use:['style-loader','css-loader','less-loader']
            },
            {
                test:/\.(jpg|png|gif)$/,
                loader:'url-loader',
                options:{
                //图片大小小于8kb,就会被base64
                //优点:减少请求数量(减轻服务器压力)
                //缺点:图片体积会更大(文件请求速度更慢)
                //一般会弄小图片
                  limit:8*1024
                }
            },
        ]
    },
    plugins:[
        new HtmlWebpackPlugin({
            template:'./src/index.html'
        })
    ],
    mode:'development'
}

注:这个只能用来打包样式里面的图片资源,无法打包html里面的图片资源

处理html里面的图片:

const {resolve}=require('path');
const HtmlWebpackPlugin=require('html-webpack-plugin');
module.exports={
    entry:'./src/index.js',
    output:{
        filename:'built.js',
        path:resolve(__dirname,'build'),
    },
    module:{
        rules:[
            {
                test:/\.less$/,
                use:['style-loader','css-loader','less-loader']
            },


            //默认处理不了html图片资源
            {
                test:/\.(jpg|png|gif)$/,
                type: 'asset',
                parser: {
                    dataUrlCondition: {
                      maxSize: 8 * 1024 // 小于 8KB 的图片转为 Base64
                    }
                  },
                  generator: {
                    filename: '[name].[hash:6][ext]' // 打包后的图片路径
                  }
                },
            //用来处理html文件中的图片、字体、样式表等资源的引入,相当于辅助plugins处理这些资源
            {
                test:/\.html$/,
                use:{
                    loader:'html-loader',
                    options:{
                        esModule:false
                    }

                }
            }
        ]
    },
    plugins:[
        new HtmlWebpackPlugin({
            template:'./src/index.html'
        })
    ],
    mode:'development'
}

注:html-loader是用来处理html文件中的图片、字体、样式表等资源的引入,相当于辅助plugins处理这些资源,不要和HtmlWebpackPlugin弄混了

处理其他资源(asset/resource)

const {resolve}=require('path');
const HtmlWebpackPlugin=require('html-webpack-plugin')
module.exports={
    entry:'./src/index.js',
    output:{
        filename:'built.js',
        path:resolve(__dirname,'build')
    },
    module:{
        rules:[
            {
                test:/\.css$/,
                use:['style-loader','css-loader']
            },
            {
                // 排除 css|js|html 以外的资源
                exclude: /\.(css|js|html)$/,
                type: 'asset/resource',
                generator: {
                    filename: '[name].[hash:6][ext]'
                }
            }
        ]
    },
    plugins:[
        new HtmlWebpackPlugin({
            template:'./src/index.html'
        })
    ],
    mode:'development'
}

编译运行自动化(devServer)

配置:npm i webpack-dev-server -D

启动指令:npx webpack-dev-server

const {resolve}=require('path');
const HtmlWebpackPlugin=require('html-webpack-plugin')
module.exports={
    entry:'./src/index.js',
    output:{
        filename:'built.js',
        path:resolve(__dirname,'build')
    },
    module:{
        rules:[
            {
                test:/\.css$/,
                use:['style-loader','css-loader']
            },
            {               
                exclude: /\.(css|js|html)$/,
                type: 'asset/resource',
                generator: {
                    filename: '[name].[hash:6][ext]'
                }
            }
        ]
    },
    plugins:[
        new HtmlWebpackPlugin({
            template:'./src/index.html'
        })
    ],
    mode:'development',
    //开发服务器 devServer,用来自动编译,自动打开浏览器,自动刷新浏览器
    //特点:只会在内存中编译打包,不会有任何输出
    //启动指令:npx webpack-dev-server
    devServer: {
        // 使用 static 选项代替 contentBase
        static: resolve(__dirname, 'build'),
        // 启动 gzip 压缩
        compress: true,
        // 指定开发服务器端口号
        port: 3000,
        // 自动打开浏览器
        open: true
    }
}

注:webpack会将打包的文件输出到某个目录下

npx webpack-dev-server只会在内存中编译打包,不会输出

构建环境配置

const {resolve}=require('path');
const HtmlWebpackPlugin=require('html-webpack-plugin')
module.exports={
    entry:'./src/js/index.js',
    output:{
        filename:'built.js',
        path:resolve(__dirname,'build'),
        clean: true, // 清空 build 目录
    },
    module:{
        rules:[
            {
                test:/\.css$/,
                use:['style-loader','css-loader']
            },
            {
                test:/\.less$/,
                use: [
                    'style-loader',
                    {
                        loader: 'css-loader',
                        options: {
                            url: true 
                        }
                    },
                    'less-loader'
                ]
            },
            {
                test: /\.(jpg|png|gif)$/,
                type: 'asset',
                parser: {
                    dataUrlCondition: {
                        maxSize: 8 * 1024 
                    }
                },
                generator: {
                    filename: '[name].[hash:6][ext]' 
                }
            },
            
            {
                test:/\.html$/,
                use:{
                    loader:'html-loader',
                    options:{
                        esModule:false
                    }

                },
                
            },
            {
                
                exclude: /\.(css|js|html)$/,
                type: 'asset/resource',
                generator: {
                    filename: '[name].[hash:6][ext]'
                }
            }
        ]
    },
    plugins:[
        new HtmlWebpackPlugin({
            template:'./src/index.html'
        }),     
    ],
    devServer: {
      
        static: resolve(__dirname, 'build'),
        compress: true,       
        port: 3031,       
        open: true,
    },
    mode:'development'
}

如果less文件无法加载,可以将style-loader换成MiniCssExtractPlugin.loader(注:这个属于生产环境):

配置:npm install --save-dev mini-css-extract-plugin

const MiniCssExtractPlugin = require('mini-css-extract-plugin');
//其它代码
module.exports={
    //其它代码
    module:{
        rules:[
           //其它代码
            {
                test:/\.less$/,
                use: [
                    MiniCssExtractPlugin.loader, 
                    {
                        loader: 'css-loader',
                        options: {
                            url: true 
                        }
                    },
                    'less-loader'
                ]
            },
            plugins:[
        new HtmlWebpackPlugin({
            template:'./src/index.html'
        }),
        new MiniCssExtractPlugin({
            filename: '[name].[contenthash].css', 
            chunkFilename: '[id].[contenthash].css'
          })
    ],    
            //其它代码                            
            }
        ]
    },
   //其它代码
}

MiniCssExtractPlugin 是一个非常重要的 Webpack 插件,主要用于以下场景:

  • 生产环境:将 CSS 提取为单独的文件,优化性能和缓存。

  • 代码分割:支持按需加载 CSS,减少初始加载时间。

  • 与 HTML 插件配合:自动生成 <link> 标签,简化开发流程

生产环境

处理样式文件

webpack.config.js文件:

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


module.exports={
    entry:'./src/js/index.js',
    output:{
        filename:'js/built.js',
        path:resolve(__dirname,'build')
    },
    module:{
        rules:[
            {
                test:/\.css$/,
                use:[
                    MiniCssExtractPlugin.loader,
                    'css-loader'
                ]
            }
        ]
    },
    plugins:[
        new HtmlWebpackPlugin({
            template:'./src/index.html'
        }),
        new MiniCssExtractPlugin({
            filename: '[name].[contenthash].css', // 定义输出的 CSS 文件名
            chunkFilename: '[id].[contenthash].css'
        })
    ],
    mode:'production'
}

css文件兼容性处理

配置:npm i postcss-loader postcss-preset-env -D

webpack.config.js文件:

const HtmlWebpackPlugin = require('html-webpack-plugin');
const {resolve}=require('path');;
const MiniCssExtractPlugin=require('mini-css-extract-plugin')
process.env.NODE_ENV='development'//设置开发环境为默认环境变量,如果不设置默认为生产环境

module.exports={
    entry:'./src/js/index.js',
    output:{
        filename:'js/built.js',
        path:resolve(__dirname,'build')
    },
    module:{
        rules:[
            {
                test:/\.css$/,
                use:[
                    MiniCssExtractPlugin.loader,
                    'css-loader',
                    /*css兼容性处理:postcss-->postcss-loader plstcss-preset-env 
                      帮postcss找到package.json中browserslist里面的配置,通过配置加载指定的css兼容性样式
                    */
                    //使用loader的默认配置
                    // 'postcss-loader',
                    //修改loader配置
                    {
                        loader: 'postcss-loader',
                        options: {
                            postcssOptions: {
                                plugins: [
                                    require('postcss-preset-env')()
                                ]
                            }
                        }
                    }
                ]
            }
        ]
    },
    plugins:[
        new HtmlWebpackPlugin({
            template:'./src/index.html'
        }),
        new MiniCssExtractPlugin({
            filename: '[name].[contenthash].css', // 定义输出的 CSS 文件名
            chunkFilename: '[id].[contenthash].css'
        })
    ],
    mode:'production'
}

package.json文件(补充,其他不动):

"browserslist":{
    "development":[
      "last 1 chrome version",
      "last 1 firefox version",
      "last 1 safari version"
    ],
    //默认是看生产环境,如果要默认为开发环境,则要设置node.js的环境变量process.env.NODE_ENV='development'

    "production":[
      ">0.2%",
      "not dead",
      "not op_mini all"
    ]
  },

压缩css资源

配置:npm install css-minimizer-webpack-plugin -D

const HtmlWebpackPlugin = require('html-webpack-plugin');
const {resolve}=require('path');;
const MiniCssExtractPlugin=require('mini-css-extract-plugin')
const CssMinimizerPlugin = require('css-minimizer-webpack-plugin');
process.env.NODE_ENV='development'//设置开发环境为默认环境变量,如果不设置默认为生产环境

module.exports={
    entry:'./src/js/index.js',
    output:{
        filename:'js/built.js',
        path:resolve(__dirname,'build')
    },
    module:{
        rules:[
            {
                test:/\.css$/,
                use:[
                    MiniCssExtractPlugin.loader,
                    'css-loader',
                    {
                        loader: 'postcss-loader',
                        options: {
                            postcssOptions: {
                                plugins: [
                                    require('postcss-preset-env')()
                                ]
                            }
                        }
                    }
                ]
            }
        ]
    },
    plugins:[
        new HtmlWebpackPlugin({
            template:'./src/index.html'
        }),
        new MiniCssExtractPlugin({
            filename: '[name].[contenthash].css', 
            chunkFilename: '[id].[contenthash].css'
        })
    ],
    optimization:{
        minimize:true,
        minimizer:[new CssMinimizerPlugin()]
    },
    mode:'development'
}
const HtmlWebpackPlugin = require('html-webpack-plugin');
const {resolve}=require('path');;
const MiniCssExtractPlugin=require('mini-css-extract-plugin')
const CssMinimizerPlugin = require('css-minimizer-webpack-plugin');

module.exports={
    entry:'./src/js/index.js',
    output:{
        filename:'js/built.js',
        path:resolve(__dirname,'build')
    },
    module:{
        rules:[
            {
                test:/\.css$/,
                use:[
                    MiniCssExtractPlugin.loader,
                    'css-loader',
                    {
                        loader: 'postcss-loader',
                        options: {
                            postcssOptions: {
                                plugins: [
                                    require('postcss-preset-env')()
                                ]
                            }
                        }
                    }
                ]
            }
        ]
    },
    plugins:[
        new HtmlWebpackPlugin({
            template:'./src/index.html'
        }),
        new MiniCssExtractPlugin({
            filename: '[name].[contenthash].css', // 定义输出的 CSS 文件名
            chunkFilename: '[id].[contenthash].css'
        })
    ],
    optimization:{
        minimize:true,
        minimizer:[new CssMinimizerPlugin()]
    },
    //环境设置为生产环境,同时也不要    process.env.NODE_ENV='development'
    mode:'production'
}

js语法检查

配置:npm i eslint-loader eslint eslint-config-airbnb-base eslint-plugin-import -D

package.json文件(补充):

"eslintConfig":{
    "extends": "airbnb-base"
  },

其他的语法可以查找网站npmjs

webpack.config.js文件:

const {resolve}=require('path');
const HtmlWebpackPlugin=require('html-webpack-plugin');

module.exports={
    entry:'./src/js/index.js',

output:{
    filename:'js/built.js',
    path:resolve(__dirname,'build')
},
module:{
    rules:[
        /*
        语法检查:eslint-loader eslint
        只检查源代码,不检查第三方库的代码
        设置检查规则:在package.json中eslintConfig中设置
        */
       {
        test:/\.js$/,
        exclude:/node_modules/,
        loader:'eslint-loader',
        options:{
            //自动修复eslint的错误
            fix:true
        }
       }
    ]
},
plugins:[
    new HtmlWebpackPlugin({
        template:'./src/index.html'
    })
],
mode:'development'
}

js文件兼容性处理

配置:npm i babel-loader @babel/core @babel/preset-env -D

方法一(简单处理):

webpack.config.js文件:

const {resolve}=require('path');
const HtmlWebpackPlugin=require('html-webpack-plugin');

module.exports={
    entry:'./src/js/index.js',

output:{
    filename:'js/built.js',
    path:resolve(__dirname,'build')
},
module:{
    rules:[
      /*
      js兼容性处理:babel-loader @babel/core @babel/preset-env
      */
      {
        test: /\.js$/,
        exclude: /node_modules/,
        use: {
            loader: 'babel-loader',
            //传递配置选项
            options: {
                //指定 Babel 使用的插件
                presets: [
                    [
                        '@babel/preset-env',
                        {
                            //指定希望支持的目标环境
                            targets: {
                                "esmodules": false,//是否生成 ES 模块语法的代码
                                "browsers": [//指定希望支持的浏览器版本
                                    "last 2 versions", // 支持最近两个版本的浏览器
                                    "ie >= 11" // 支持 IE 11
                                ]
                            }
                        }
                    ]
                ]
            }
        }
    }
    ]
},
plugins:[
    new HtmlWebpackPlugin({
        template:'./src/index.html'
    })
],
mode:'development'
}

缺点:只能处理简单的js兼容性,promise处理不了

处理全部的js文件兼容性:

方法二(按需加载):

配置:npm i core-js -D

webpack.config.js文件:

const {resolve}=require('path');
const HtmlWebpackPlugin=require('html-webpack-plugin');

module.exports={
    entry:'./src/js/index.js',

output:{
    filename:'js/built.js',
    path:resolve(__dirname,'build')
},
module:{
    rules:[
      {
        test: /\.js$/,
        exclude: /node_modules/,
        use: {
            loader: 'babel-loader',
            
            options: {
               
                presets: [
                    [
                        '@babel/preset-env',
                        {
                            //按需加载
                            useBuiltIns: 'usage',
                            corejs: { version: 3 },
                           
                            targets: {
                                "esmodules": false,
                                "browsers": [
                                    "last 2 versions", 
                                    "ie >= 11" 
                                ],
                                
                                chrome:'60',
                                firefox:'60',
                                ie:'9',
                                safari:'10',
                                edge:'17'
                            }
                        }
                    ]
                ]
            }
        }
    }
    ]
},
plugins:[
    new HtmlWebpackPlugin({
        template:'./src/index.html'
    })
],
mode:'development'
}

注:使用方法三则不能使用方法二的import '@babel/polyfill',需要注释掉

优势:减小built.js的体积,同时能处理所有需要兼容性处理的js资源

压缩js&html资源

压缩js资源:生产环境下会自动压缩js代码,不需要额外配置,把mode设为production即可

压缩html资源:

const {resolve}=require('path');
const HtmlWebpackPlugin=require('html-webpack-plugin');

module.exports={
    entry:'./src/js/index.js',

output:{
    filename:'js/built.js',
    path:resolve(__dirname,'build')
},
plugins:[
    new HtmlWebpackPlugin({
        template:'./src/index.html',
        //压缩html代码
        minify:{
            //移除空格
            collapseWhitespace:true,
            //移除注释
            removeComments:true
        }
    })
],

mode:'production'
}

构建环境配置

const {resolve}=require('path')
const HtmlWebpackPlugin=require('html-webpack-plugin')
const MiniCssExtractPlugin=require('mini-css-extract-plugin')
const CssMinimizerPlugin=require('css-minimizer-webpack-plugin')
module.exports={
    entry:'./src/js/index.js',
    output:{
        filename:'js/built.js',
        path:resolve(__dirname,'build')
    },
    module:{
        rules:[
            {
                test:'/\.css$/',
                use:[
                    MiniCssExtractPlugin.loader,
                    'css-loader'
                ]
            },
            {
                test:'/\.less$/',
                use:[
                    MiniCssExtractPlugin.loader,
                    'css-loader',
                    'less-loader'
                ]
            },
            {
                test:'/\.js$/',
                exclude:'(/node_modules/)|(webpack.config.js)',
                loader:'eslint-loader',
                options:{
                    fis:true
                }
            },
            {
                test:'/\.js$/',
                exclude:'/node_modules/',
                loader:'babel-loader',
                options:{
                    presets:[
                        '@babel/preset-env',
                        {
                            useBuiltIns:'usage',
                            corejs:{version:3},
                            targets:{
                                'esmodules':false,
                                'browsers':['last 2 version',
                                'ie>=11'],
                                chrome:'60',
                                firefox:'60',
                                ie:'9',
                                safari:'10',
                                edge:'17'
                            }
                        }
                    ]
                }
            },
            {
                test:'/\.(jpg|png|gif)$/',
                type:'asset',
                parset:{
                    dataUrlCondition:{
                        maxSize:8*1024
                    }
                },
                generator:{
                    filename:'[name].[hash:6][ext]'
                }
            },
            {
                test:'/\.html$/',
                use:{
                    loader:'html-loader',
                    options:{
                        esModule:false
                    }
                }
            },
            {
                exclude:/\..(js|css|less|html|jpg|png|gif)$/,
                type:'asset/resource',
                generator:{
                    filename:'[name].[hash:6][ext]'

                }
            }
        ]
    },
    plugins:[
        new MiniCssExtractPlugin({
            filename:'css/built.css'
        }),
        new CssMinimizerPlugin(),
        new HtmlWebpackPlugin({
            template:'./src/index.html',
            minify:{
                collapseWhitespace:true,
                removeComments:true
            }
        }),

    ],
    mode:"production"
}

性能优化

开发环境性能优化

  • 优化打包构建速度

  • 优化代码调试

HMR-模块热替换

解决问题:不管哪个模块发生变化,整个打包文件也会重新全部加载,效率低。

解决方式:一个模块发生变化,只会重新打包这一个模块,不会重新打包所有模块

注:当修改了webpack配置(plugins),必须重启server(Ctrl+C),且只有开发环境可以用HMR,生产环境不可以用

样式文件:

webpack.config.js文件:

const {resolve}=require('path');
const HtmlWebpackPlugin=require('html-webpack-plugin')
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
module.exports={
    entry:'./src/js/index.js',
    output:{
        filename:'built.js',
        path:resolve(__dirname,'build'),
        clean: true, 
    },
    module:{
        rules:[
            {
                test:/\.css$/,
                use:['style-loader','css-loader']
            },
            {
                test: /\.(jpg|png|gif)$/,
                type: 'asset',
                parser: {
                    dataUrlCondition: {
                        maxSize: 8 * 1024 
                    }
                },
                generator: {
                    filename: '[name].[hash:6][ext]' 
                }
            },
           
            {
                test:/\.html$/,
                use:{
                    loader:'html-loader',
                    options:{
                        esModule:false
                    }

                },
                
            },
            {
               
                exclude: /\.(css|js|html)$/,
                type: 'asset/resource',
                generator: {
                    filename: '[name].[hash:6][ext]'
                }
            }
        ]
    },
    plugins:[
        new HtmlWebpackPlugin({
            template:'./src/index.html'
        }),
        new MiniCssExtractPlugin({
            filename: '[name].[contenthash].css', 
            chunkFilename: '[id].[contenthash].css'
          })
    ],
    devServer: {
        
        static: resolve(__dirname, 'build'),
       
        compress: true,
        
        port: 3031,
        
        open: true,
        //模块热替换
        hot:true
    },
    mode:'development'
}

注:webpack配置文件中的css和less文件解析必须是'style-loader'而不是'MiniCssExtractPlugin.loader'

js文件:

webpack.config.js文件不变

index.js文件:

//导入模块文件
//自己的文件代码
//监听模块更新
if(module.hot){
module.hot.accept('模块文件相对路径',()=>{
const 模块名=require(模块文件路径).default;
模块名();
})

html文件(不能热更新(HMR),但是可以正常更新):
webpack.config.js:

//其它代码
module.exports={
    //将html文件引入入口
    entry:['./src/js/index.js','./src/index.html'],
//其它代码
}

source-map(源代码到构建后代码映射技术)

如果构建后代码出错了,通过映射可以追踪源代码错误(控制台会报出源文件的具体错误位置)

webpack.config.js文件:

//其它代码
module.exports={
//其它代码
devtool:'source-map'
}

devtool配置:

source-map、inline-source-map和eval-source-map可以生成错误代码准确信息和源代码错误位置,其他不能全部生成。

开发环境:从速度快和友好要求下,建议eval-source-map>eval-cheap-module-source-map(只有行没有列提示)

生产环境:从占用内存和友好要求下,建议source-map>cheap-module-source-map

生产环境性能优化

  • 优化打包构建速度

  • 优化代码运行的性能

oneOf

每个文件只会匹配一个module的rules配置,不会每个都过一遍

//其它代码
module.exports={
    entry:'./src/js/index.js',
    output:{
        filename:'js/built.js',
        path:resolve(__dirname,'build')
    },
    module:{
        rules:[
            {
                oneOf:[
            {
                test:'/\.css$/',
                use:[
                    MiniCssExtractPlugin.loader,
                    'css-loader'
                ]
            },
            {
                test:'/\.less$/',
                use:[
                    MiniCssExtractPlugin.loader,
                    'css-loader',
                    'less-loader'
                ]
            },
            {
                test:'/\.js$/',
                exclude:'(/node_modules/)|(webpack.config.js)',
                loader:'eslint-loader',
                options:{
                    fis:true
                }
            },
            {
                test:'/\.js$/',
                exclude:'/node_modules/',
                loader:'babel-loader',
                options:{
                    presets:[
                        '@babel/preset-env',
                        {
                            useBuiltIns:'usage',
                            corejs:{version:3},
                            targets:{
                                'esmodules':false,
                                'browsers':['last 2 version',
                                'ie>=11'],
                                chrome:'60',
                                firefox:'60',
                                ie:'9',
                                safari:'10',
                                edge:'17'
                            }
                        }
                    ]
                }
            },
            {
                test:'/\.(jpg|png|gif)$/',
                type:'asset',
                parset:{
                    dataUrlCondition:{
                        maxSize:8*1024
                    }
                },
                generator:{
                    filename:'[name].[hash:6][ext]'
                }
            },
            {
                test:'/\.html$/',
                use:{
                    loader:'html-loader',
                    options:{
                        esModule:false
                    }
                }
            },
            {
                exclude:/\..(js|css|less|html|jpg|png|gif)$/,
                type:'asset/resource',
                generator:{
                    filename:'[name].[hash:6][ext]'

                }
            }
        ]
    },
    ]
    },
    plugins:[
        new MiniCssExtractPlugin({
            filename:'css/built.css'
        }),
        new CssMinimizerPlugin(),
        new HtmlWebpackPlugin({
            template:'./src/index.html',
            minify:{
                collapseWhitespace:true,
                removeComments:true
            }
        }),

    ],
    mode:"production"
}

注:如果有两个配置处理同一个文件的,则需要将这几个配置大于一个的配置放到oneOf外面:

//其它代码
module.exports={
    entry:'./src/js/index.js',
    output:{
        filename:'js/built.js',
        path:resolve(__dirname,'build')
    },
    module:{
        
        rules:[
            {
                test:'/\.js$/',
                exclude:'/node_modules/',
                loader:'babel-loader',
                options:{
                    presets:[
                        '@babel/preset-env',
                        {
                            useBuiltIns:'usage',
                            corejs:{version:3},
                            targets:{
                                'esmodules':false,
                                'browsers':['last 2 version',
                                'ie>=11'],
                                chrome:'60',
                                firefox:'60',
                                ie:'9',
                                safari:'10',
                                edge:'17'
                            }
                        }
                    ]
                }
            },
            {
                oneOf:[
            {
                test:'/\.css$/',
                use:[
                    MiniCssExtractPlugin.loader,
                    'css-loader'
                ]
            },
            {
                test:'/\.less$/',
                use:[
                    MiniCssExtractPlugin.loader,
                    'css-loader',
                    'less-loader'
                ]
            },
            {
                test:'/\.js$/',
                exclude:'(/node_modules/)|(webpack.config.js)',
                loader:'eslint-loader',
                options:{
                    fis:true
                }
            },
            
            {
                test:'/\.(jpg|png|gif)$/',
                type:'asset',
                parset:{
                    dataUrlCondition:{
                        maxSize:8*1024
                    }
                },
                generator:{
                    filename:'[name].[hash:6][ext]'
                }
            },
            {
                test:'/\.html$/',
                use:{
                    loader:'html-loader',
                    options:{
                        esModule:false
                    }
                }
            },
            {
                exclude:/\..(js|css|less|html|jpg|png|gif)$/,
                type:'asset/resource',
                generator:{
                    filename:'[name].[hash:6][ext]'

                }
            }
        ]
    },
    ]
    },
    plugins:[
        new MiniCssExtractPlugin({
            filename:'css/built.css'
        }),
        new CssMinimizerPlugin(),
        new HtmlWebpackPlugin({
            template:'./src/index.html',
            minify:{
                collapseWhitespace:true,
                removeComments:true
            }
        }),

    ],
    mode:"production"
}

缓存

将编译好的文件进行缓存处理,如果没有变化,则直接运行缓存的文件,如果变化了再重新编译缓存运行

本质:第二次构建的时候会读取之前的缓存:

const { resolve } = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const CssMinimizerPlugin = require('css-minimizer-webpack-plugin');

module.exports = {
    entry: './src/js/index.js',
    output: {
        filename: 'js/built.[contenthash:10].js',
        path: resolve(__dirname, 'build')
    },
    module: {
        rules: [
            
            {
                test: /\.js$/,
                exclude: /node_modules|webpack\.config\.js$/,
                loader: 'babel-loader',
                options: {
                    presets: [
                        [
                            '@babel/preset-env',
                            {
                                useBuiltIns: 'usage',
                                corejs: { version: 3 },
                                targets: {
                                    esmodules: false,
                                    browsers: ['last 2 versions', 'ie >= 11'],
                                    chrome: '60',
                                    firefox: '60',
                                    ie: '9',
                                    safari: '10',
                                    edge: '17'
                                }
                            }
                        ]
                    ],
                    //开启babel缓存,第二次构建的时候会读取之前的缓存
                    cacheDirectory: true
                }
            },
           
            {
                oneOf: [
                    {
                        test: /\.css$/,
                        use: [
                            MiniCssExtractPlugin.loader,
                            'css-loader'
                        ]
                    },
                    {
                        test: /\.less$/,
                        use: [
                            MiniCssExtractPlugin.loader,
                            'css-loader',
                            'less-loader'
                        ]
                    },
                    {
                        test: /\.js$/,
                        exclude: /node_modules|webpack\.config\.js$/,
                        loader: 'eslint-loader',
                        options: {
                            fix: true
                        }
                    },
                    {
                        test: /\.(jpg|png|gif)$/,
                        type: 'asset',
                        parser: {
                            dataUrlCondition: {
                                maxSize: 8 * 1024
                            }
                        },
                        generator: {
                            filename: '[name].[hash:6][ext]'
                        }
                    },
                    {
                        test: /\.html$/,
                        use: {
                            loader: 'html-loader',
                            options: {
                                esModule: false
                            }
                        }
                    },
                    {
                        exclude: /\.(js|css|less|html|jpg|png|gif)$/,
                        type: 'asset/resource',
                        generator: {
                            filename: '[name].[contenthash:6][ext]'
                        }
                    }
                ]
            }
        ]
    },
    plugins: [
        new MiniCssExtractPlugin({
            filename: 'css/built.[contenthash:10].css'
        }),
        new CssMinimizerPlugin(),
        new HtmlWebpackPlugin({
            template: './src/index.html',
            minify: {
                collapseWhitespace: true,
                removeComments: true
            }
        })
    ],
    mode: "production",
    devtool: "source-map"
};

注:js文件和css文件打包后的文件名必须是每次修改后都不一样的才能正确更新,建议直接定义为built.[contenthash:10].css/js,这样,每次修改都会生成一个新的哈希值,这样能保证文件的正常更新,且两个文件的哈希值不相同。

测试缓存:

服务器开启(server.js):

//服务器代码
const express=require('express');
const app=express();
app.use(express.static('build',{maxAge:1000*3600}));
app.listen(3030);

运行server.js:node server.js

每次修改完文件要重新输入指令:webpack

终止端口占用:

1、终端输入 netstat -ano | findstr :端口名

2、获取 LISTENING后面的数字

3、 taskkill /PID LISTENING后面的数字 /F

tree_shaking(去除无用代码)

前提:

1、使用ES6模块化

2、开启production环境

优点:减少代码体积

package.json文件:

//将这个插入到配置中
"sideEffects":false

表示所有代码都可以进行去除无用代码

副作用:会把css/@babel/polyfill文件删除

解决:将"sideEffects":false改为"sideEffects":["*css",...]//将可能会被删除的文件放到数组里面,相当于屏蔽这些类型文件的tree_shaking作用,防止被删除。

code split(代码分割)

方法一(直接设置两个入口文件):

webpack.config.js文件:

const { resolve } = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports = {
    entry: {
        main:'./src/js/index.js',
        test:'./src/js/test.js'
      },
    //其它代码
};

注:输出的时候文件名可以设置为[name].[contenthash:10].js,防止打包文件名不好区分

方法二:

webpack.config.js文件:

const { resolve } = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports = {
    entry: {
      main:'./src/js/index.js',
      test:'./src/js/test.js'
    },
    output: {
        filename: 'js/[name].[contenthash:10].js',
        path: resolve(__dirname, 'build')
    },
    module: {
        rules: [
            
            {
                test: /\.js$/,
                exclude: /node_modules|webpack\.config\.js$/,
                loader: 'babel-loader',
                options: {
                    presets: [
                        [
                            '@babel/preset-env',
                            {
                                useBuiltIns: 'usage',
                                corejs: { version: 3 },
                                targets: {
                                    esmodules: false,
                                    browsers: ['last 2 versions', 'ie >= 11'],
                                    chrome: '60',
                                    firefox: '60',
                                    ie: '9',
                                    safari: '10',
                                    edge: '17'
                                }
                            }
                        ]
                    ],
                   
                    cacheDirectory: true
                }
            },
            
            {
                oneOf: [
                    {
                        test: /\.js$/,
                        exclude: /node_modules|webpack\.config\.js$/,
                        loader: 'eslint-loader',
                        options: {
                            fix: true
                        }
                    },
                    {
                        test: /\.(jpg|png|gif)$/,
                        type: 'asset',
                        parser: {
                            dataUrlCondition: {
                                maxSize: 8 * 1024
                            }
                        },
                        generator: {
                            filename: '[name].[hash:6][ext]'
                        }
                    },
                    {
                        test: /\.html$/,
                        use: {
                            loader: 'html-loader',
                            options: {
                                esModule: false
                            }
                        }
                    },
                    {
                        exclude: /\.(js|css|less|html|jpg|png|gif)$/,
                        type: 'asset/resource',
                        generator: {
                            filename: '[name].[contenthash:6][ext]'
                        }
                    }
                ]
            }
        ]
    },
    plugins: [
        new HtmlWebpackPlugin({
            template: './src/index.html',
            minify: {
                collapseWhitespace: true,
                removeComments: true
            }
        })
    ],
    //可以将node_modules中代码单独打包一个chunk最终输出,自动分析多入口chunk中,有没有公共的文件,如果有会打包成一个单独的chunk
    optimization:{
        splitChunks:{
            chunks:'all'
        }
    },
    mode: "production",
};

要打包的js文件(每一个都要):

import $ from 'jquery'

优点:可以将node_modules中代码单独打包一个chunk最终输出,自动分析多入口chunk中,有没有公共的文件,如果有会打包成一个单独的chunk

方法三:

webpack.config.js文件:

const { resolve } = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports = {
    entry: './src/js/index.js',
    output: {
        filename: 'js/[name].[contenthash:10].js',
        path: resolve(__dirname, 'build')
    },
    module: {
        rules: [
            {
                test: /\.js$/,
                exclude: /node_modules|webpack\.config\.js$/,
                loader: 'babel-loader',
                options: {
                    presets: [
                        [
                            '@babel/preset-env',
                            {
                                useBuiltIns: 'usage',
                                corejs: { version: 3 },
                                targets: {
                                    esmodules: false,
                                    browsers: ['last 2 versions', 'ie >= 11'],
                                    chrome: '60',
                                    firefox: '60',
                                    ie: '9',
                                    safari: '10',
                                    edge: '17'
                                }
                            }
                        ]
                    ],
                    cacheDirectory: true
                }
            },
            {
                oneOf: [
                    {
                        test: /\.js$/,
                        exclude: /node_modules|webpack\.config\.js$/,
                        loader: 'eslint-loader',
                        options: {
                            fix: true
                        }
                    },
                    {
                        test: /\.(jpg|png|gif)$/,
                        type: 'asset',
                        parser: {
                            dataUrlCondition: {
                                maxSize: 8 * 1024
                            }
                        },
                        generator: {
                            filename: '[name].[hash:6][ext]'
                        }
                    },
                    {
                        test: /\.html$/,
                        use: {
                            loader: 'html-loader',
                            options: {
                                esModule: false
                            }
                        }
                    },
                    {
                        exclude: /\.(js|css|less|html|jpg|png|gif)$/,
                        type: 'asset/resource',
                        generator: {
                            filename: '[name].[contenthash:6][ext]'
                        }
                    }
                ]
            }
        ]
    },
    plugins: [
        new HtmlWebpackPlugin({
            template: './src/index.html',
            minify: {
                collapseWhitespace: true,
                removeComments: true
            }
        })
    ],
    
    optimization:{
        splitChunks:{
            chunks:'all'
        }
    },
    mode: "production",
};

index.js文件:

//通过js代码,让某个文件被单独打包成一个chunk,能将某个文件单独打包
import (/*webpackChunkName:'test'*/'./test')
.then((mul,count)=>{
    //eslint-disable-next-line
    console.log(mul(2,5),count);
}).catch(err=>{
    console.log(err);
})
//其它代码

/*webpackChunkName:'test'*/指的是生成的打包文件名以test开头,不是注释

lazy loading(懒加载和预加载)

懒加载(事件触发的时候才加载引入的文件)

index.js文件(test.js文件懒加载):

document.getElementById('btn').onclick=function(){
    //懒加载(点击了按钮才会下载test.js文件,从而打印test文件中的输出,避免了一加载页面时就下载test.js文件)
    import (/*webpackChunkName:'test'*/'./test').then(({mul})=>{
        console.log(mul(4,5));
    })
   
}

预加载(页面加载的时候就加载好引入的文件,但是不使用,等事件触发的时候再使用)

index.js文件:

document.getElementById('btn').onclick=function(){
    import (/*webpackChunkName:'test',webpackPrefetch:true*/'./test').then(({mul})=>{
        console.log(mul(4,5));
    })
}

要点:在import文件中注释webpackPrefetch:true

PWA(渐进式网络开发应用程序:离线也可以访问)

配置:

下载workbox:npm i workbox-webpack-plugin -D

const { resolve } = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const CssMinimizerPlugin = require('css-minimizer-webpack-plugin');
const WorkboxWebpackPlugin=require('workbox-webpack-plugin');
module.exports = {
    entry: './src/js/index.js',
    output: {
        filename: 'js/built.[contenthash:10].js',
        path: resolve(__dirname, 'build')
    },
    module: {
        rules: [
            
            {
                test: /\.js$/,
                exclude: /node_modules|webpack\.config\.js$/,
                loader: 'babel-loader',
                options: {
                    presets: [
                        [
                            '@babel/preset-env',
                            {
                                useBuiltIns: 'usage',
                                corejs: { version: 3 },
                                targets: {
                                    esmodules: false,
                                    browsers: ['last 2 versions', 'ie >= 11'],
                                    chrome: '60',
                                    firefox: '60',
                                    ie: '9',
                                    safari: '10',
                                    edge: '17'
                                }
                            }
                        ]
                    ],
                   
                    cacheDirectory: true
                }
            },
          
            {
                oneOf: [
                    {
                        test: /\.css$/,
                        use: [
                            MiniCssExtractPlugin.loader,
                            'css-loader'
                        ]
                    },
                    {
                        test: /\.less$/,
                        use: [
                            MiniCssExtractPlugin.loader,
                            'css-loader',
                            'less-loader'
                        ]
                    },
                    {
                        test: /\.js$/,
                        exclude: /node_modules|webpack\.config\.js$/,
                        loader: 'eslint-loader',
                        options: {
                            fix: true
                        }
                    },
                    {
                        test: /\.(jpg|png|gif)$/,
                        type: 'asset',
                        parser: {
                            dataUrlCondition: {
                                maxSize: 8 * 1024
                            }
                        },
                        generator: {
                            filename: '[name].[hash:6][ext]'
                        }
                    },
                    {
                        test: /\.html$/,
                        use: {
                            loader: 'html-loader',
                            options: {
                                esModule: false
                            }
                        }
                    },
                    {
                        exclude: /\.(js|css|less|html|jpg|png|gif)$/,
                        type: 'asset/resource',
                        generator: {
                            filename: '[name].[contenthash:6][ext]'
                        }
                    }
                ]
            }
        ]
    },
    plugins: [
        new MiniCssExtractPlugin({
            filename: 'css/built.[contenthash:10].css'
        }),
        new CssMinimizerPlugin(),
        new HtmlWebpackPlugin({
            template: './src/index.html',
            minify: {
                collapseWhitespace: true,
                removeComments: true
            }
        }),
        //生成一个serviceworker配置文件
       new  WorkboxWebpackPlugin.GenerateSW({
            clientsClaim:true,//帮助serviceworker快速启动
            skipWaiting:true//删除旧的serviceworker
       })
    ],
    mode: "production",
    devtool: "source-map"
};

index.js文件:

//其它代码
//注册代码
if('serviceWorker' in navigator){
  window.addEventListener('load',()=>{
    navigator.serviceWorker.register('/service-worker.js').then(reg=>{
      console.log('service worker注册成功',reg);
    }).catch(err=>{
      console.log('service worker注册失败',err);
    })
  })
}

多进程打包

配置:npm i thread-loader -D

webpack.config.js文件:

const { resolve } = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const CssMinimizerPlugin = require('css-minimizer-webpack-plugin');
const WorkboxWebpackPlugin=require('workbox-webpack-plugin');
module.exports = {
    entry: './src/js/index.js',
    output: {
        filename: 'js/built.[contenthash:10].js',
        path: resolve(__dirname, 'build')
    },
    module: {
        rules: [
           
            {
                test: /\.js$/,
                exclude: /node_modules|webpack\.config\.js$/,
                use:[
                  
                    {
                        loader: 'thread-loader',
                        options:{
                            workers:2//进程2个
                        }
                    },
                    {
                        loader: 'babel-loader',
                options: {
                    presets: [
                        [
                            '@babel/preset-env',
                            {
                                useBuiltIns: 'usage',
                                corejs: { version: 3 },
                                targets: {
                                    esmodules: false,
                                    browsers: ['last 2 versions', 'ie >= 11'],
                                    chrome: '60',
                                    firefox: '60',
                                    ie: '9',
                                    safari: '10',
                                    edge: '17'
                                }
                            }
                        ]
                    ],
                  
                    cacheDirectory: true
                }
                    }
                ]
                
            },
           
            //其它代码
    },
    plugins: [
        new MiniCssExtractPlugin({
            filename: 'css/built.[contenthash:10].css'
        }),
        new CssMinimizerPlugin(),
        new HtmlWebpackPlugin({
            template: './src/index.html',
            minify: {
                collapseWhitespace: true,
                removeComments: true
            }
        }),
       
       new  WorkboxWebpackPlugin.GenerateSW({
            clientsClaim:true,
            skipWaiting:true,
            runtimeCaching: [
                {
                    urlPattern: /\.css$/,
                    handler: 'CacheFirst',
                    options: {
                        cacheName: 'css-cache',
                        expiration: {
                            maxEntries: 50,
                            maxAgeSeconds: 7 * 24 * 60 * 60 // 7天
                        }
                    }
                }
            ]
       })
    ],
    mode: "production",
    devtool: "source-map"
};

externals(拒绝打包)

webpack.config.js:

//其它代码
module.exports={
    //其它代码
    externals:{
        //拒绝jQuery被打包进来,如果有这个则相应的包不会引进,如果要使用则要在html文件中手动引入
        jquery:'jQuery'
    }
}

用处:有些包是由cdn引进来的,需要屏蔽打包,手动引入

dll(将第三方库进行单独打包)

新建webpack.dll.js文件:

const {resolve}=require('path');
const webpack=require('webpack');
module.exports={
    entry:{
        jquery:['jquery']//打包生成的名字:['要打包的库']
    },
    output:{
        filename:'[name].js',
        path:resolve(__dirname,'dll'),
        library:'[name]_[hash]'//打包的库里面向外暴露出去的内容名字
    },
    plugins:[
        //打包生成json文件,并提供jquery映射的内容的名称
        new webpack.DllPlugin({
            name:'[name]_[hash]',//映射库的暴露的内容名称
            path:resolve(__dirname,'dll/manifest.json')//输出文件路径
        })
    ],
    mode:'production'
}

运行:webpack --config webpack.dll.js

webpack.config.js文件:

配置:npm i add-asset-html-webpack-plugin -D

const {resolve}=require('path');
const HtmlWebpackPlugin=require('html-webpack-plugin')
const webpack=require('webpack');
const AddAssetHtmlPlugin = require('add-asset-html-webpack-plugin');
module.exports={
    entry:'./src/index.js',
    output:{
        filename:'built.js',
        path:resolve(__dirname,'build')
    },
    module:{
        rules:[

        ]
    },
    plugins:[
        new HtmlWebpackPlugin({
            template:'./src/index.html'
        }),
        //告诉webpack哪些库不参与打包,同时使用的时候名称要变
        new webpack.DllReferencePlugin({
            manifest:resolve(__dirname,'dll/manifest.json')
        }),
        //将某个文件打包输出去,并在html中自动引入该资源
        new AddAssetHtmlPlugin({
            filepath:resolve(__dirname,'dll/jquery.js')
        })
    ],
    mode:"production"
}


WebPack
http://localhost:8090//archives/pinia
作者
林依琪
发布于
2025年04月23日
许可协议