三. webpack开发环境配置

开发环境配置主要是为了能让代码运行。主要考虑以下几个方面:

  • 打包样式资源
    • 将css/less资源打包到style标签
  • 打包 html 资源
  • 打包图片,字体等其他静态资源
  • devServer

    3.1打包css资源

    安装 npm i css-loader style-loader -D ```javascript const { resolve } = require(‘path’)

module.exports = { mode: “development”, // mode: “production”, entry: “./src/index”, output: { filename: ‘built.js’, path: resolve(__dirname, “build”) }, // 配置模块 module: { // 指定规则 rules: [ { test: /.css$/, // 加载顺序,从下到上,从右到左 use: [ // style-loader:创建style标签,将js中的样式资源插入进去,添加到head中生效 ‘style-loader’, // css-loader:将css文件变成commonjs模块加载到js中,里面内容是样式字符串 ‘css-loader’ ] } ] } }

  1. <a name="e4iup"></a>
  2. ## 3.2打包less资源
  3. 安装 `npm i less-loader -D`
  4. ```javascript
  5. const { resolve } = require('path')
  6. module.exports = {
  7. mode: "development",
  8. // mode: "production",
  9. entry: "./src/index",
  10. output: {
  11. filename: 'built.js',
  12. path: resolve(__dirname, "build")
  13. },
  14. // 配置模块
  15. module: {
  16. // 指定规则
  17. rules: [
  18. {
  19. test: /\.css$/,
  20. // 加载顺序,从下到上,从右到左
  21. use: [
  22. // style-loader:创建style标签,将js中的样式资源插入进去,添加到head中生效
  23. 'style-loader',
  24. // css-loader:将css文件变成commonjs模块加载到js中,里面内容是样式字符串
  25. 'css-loader',
  26. ]
  27. },
  28. {
  29. test: /\.less$/,
  30. use: [
  31. 'style-loader',
  32. 'css-loader',
  33. // less-loader:将less文件编译成css文件,需要下载less-loader和less
  34. 'less-loader'
  35. ]
  36. }
  37. ]
  38. }
  39. }

3.3打包html资源

  • html-webpack-plugin
    • 在build文件夹中生成html文件,并自动引入相应资源
    • 指定html模板,设置html变量,指定html名称
      • 指定模板:template:'./src/index.html'
      • 设置变量:title:"黄显瑜你可真是个小天才"不常用
        • 接收变量:<%= htmlWebpackPlugin.options.title %>
      • 指定名称:filename:'index_online.html'
  • 安装 npm i html-webpack-plugin -D
  • 引入插件 const htmlWebpackPlugin = require('html-webpack-plugin') ```javascript const { resolve } = require(‘path’) const miniCssExtractPlugin = require(‘mini-css-extract-plugin’) const htmlWebpackPlugin = require(‘html-webpack-plugin’)

module.exports = { mode: “development”, // mode: “production”, entry: “./src/index”, output: { filename: ‘built.js’, path: resolve(__dirname, “build”) }, // 配置模块 module: { // 指定规则 rules: [ { test: /.css$/, // 加载顺序,从下到上,从右到左 use: [ miniCssExtractPlugin.loader, // css-loader:将css文件变成commonjs模块加载到js中,里面内容是样式字符串 ‘css-loader’, ] }, { test: /.less$/, use: [ miniCssExtractPlugin.loader, ‘css-loader’, // less-loader:将less文件编译成css文件,需要下载less-loader和less ‘less-loader’ ] } ] }, plugins: [ new miniCssExtractPlugin({ filename:’css/other.css’ }), // 压缩html new htmlWebpackPlugin({ // 指定html模板 template:’./src/index.html’,

        // 指定名称
        filename:'index_online.html',

        // 指定变量(不建议将数据写到配置文件中)
        title:"黄显瑜你可真是个小天才"
    })
]

}

<a name="Y8Cgf"></a>
## 3.4资源处理 asset-modules
webpack5使用新增的四种资源模块(Asset Modules)代替了url-loader,file-loader,raw-loader的功能
<a name="L3vSf"></a>
### 3.4.1 asset/resource
将资源分割为**单独的文件**,并导出url,就是之前的file-loader的功能<br />![image.png](https://cdn.nlark.com/yuque/0/2021/png/2634470/1628085996976-33ba4d71-521e-4e73-93ea-97bd406a6944.png#height=103&id=SunYM&margin=%5Bobject%20Object%5D&name=image.png&originHeight=137&originWidth=292&originalType=binary&ratio=1&size=6643&status=done&style=none&width=219)
<a name="O22Fz"></a>
### 3.4.2 asset/inline
将资源导出为dateURL(url(data:))的形式,,之前的url-loader的功能<br />![image.png](https://cdn.nlark.com/yuque/0/2021/png/2634470/1628085984494-1af57030-0ba1-410c-b8d8-a8c3ff377b95.png#height=89&id=Fanpr&margin=%5Bobject%20Object%5D&name=image.png&originHeight=178&originWidth=647&originalType=binary&ratio=1&size=17070&status=done&style=none&width=323.5)
<a name="8mM7k"></a>
### 3.4.3 asset/source
将资源导出为源码(source code),之前的raw-loader功能
<a name="8GIns"></a>
### 3.4.4 asset
自动选择导出为单独文件或者dataURL形式(默认为8KB),之前有url-loader设置 limit 限制实现
<a name="yinlb"></a>
### 3.4.5 资源处理配置文件
```javascript
const { resolve } = require('path')
const htmlWebpackPlugin = require('html-webpack-plugin')

module.exports = {
    mode: 'development',
    entry: './src/index',
    output: {
        filename: 'built.js',
        path: resolve(__dirname, "build"),
        // 自定义模块输出的位置和名字
        // assetModuleFilename: 'images/[hash][ext][query]'
    },
    // 配置模块
    module: {
        // 指定规则
        rules: [
            {
                test: /\.css$/,
                use: [
                    'style-loader',
                    'css-loader'
                ]
            },
            {
                test: /\.(png|jpg)$/,
                // 指定资源打包的类型
                type: 'asset/resource',
                // 指定资源打包后输出的位置和名字
                generator:{
                    filename:'imgs/[name]-[hash:5][ext]'
                }
            },
            {
                test: /\.(ttf|woff|woff2)$/,
                // 指定资源打包的类型
                type: 'asset/inline'
            },
            {
                test: /\.txt$/,
                // 指定资源打包的类型
                type: 'asset',
                // 设置限制来判断资源应该单独分割为一个文件,还是导出为dateURL(url(data:))的形式
                parser: {
                    dataUrlCondition: {
                        maxSize: 8 * 1024
                    }
                },
            }

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

3.5 dev server服务器

提供自动化web服务(自动编译,自动打开浏览器,自动刷新浏览器)
特点:只会在内存中编译打包,不会有任何输出
安装: npm i webpack-dev-server -g
启动命令: webpack server
安装: npm i webpack-dev-server -D
启动命令: npx webpack server
文档: https://webpack.docschina.org/configuration/dev-server/

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

module.exports = {
    mode: 'development',
    entry: './src/index',
    output: {
        filename: 'built.js',
        path: resolve(__dirname, "build"),
        // 自定义模块输出的位置和名字
        // assetModuleFilename: 'images/[hash][ext][query]'
    },
    // 配置模块
    module: {
        // 指定规则
        rules: [
            {
                test: /\.css$/,
                use: [
                    'style-loader',
                    'css-loader'
                ]
            },
            {
                test: /\.(png|jpg)$/,
                // 指定资源打包的类型
                type: 'asset/resource',
                // 指定资源打包后输出的位置和名字
                generator:{
                    filename:'imgs/[name]-[hash:5][ext]'
                }
            },
            {
                test: /\.(ttf|woff|woff2)$/,
                // 指定资源打包的类型
                type: 'asset/inline'
            },
            {
                test: /\.txt$/,
                // 指定资源打包的类型
                type: 'asset',
                // 设置限制来判断资源应该单独分割为一个文件,还是导出为dateURL(url(data:))的形式
                parser: {
                    dataUrlCondition: {
                        maxSize: 8 * 1024
                    }
                },
            }

        ]
    },
      //
    devServer:{
        // 指定加载的目录的路径
        contentBase:resolve(__dirname,'build'),

        // 启动gzip压缩,让我们代码体积更小,启动更快
        compress:true,

        // 端口号
        port:6789,

        // 自动打开浏览器
        open:true,

        // 热更新
        // 只在内存中打包
        // 即,打包输出目录中并没有数据
        liveReload:true
    },
    // 只适用于web相关的target
    target:'web',
    plugins: [
        new htmlWebpackPlugin({
            template: './src/index.html',
        })
    ]
}

3.6开发环境的基本配置

安装 npm i -D css-loader style-loader less-loader html-webpack-plugin webpack-dev-server

// resolve用来拼接绝对路径的方法
const { resolve } = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin') // 引用plugin
module.exports = {
    // webpack配置
    entry: './src/index.js', // 入口起点
    output: {
        // 输出
        // 输出文件名
        filename: 'js/build.js',
        // __dirname是nodejs的变量,代表当前文件的目录绝对路径
        path: resolve(__dirname, 'build'), // 输出路径,所有资源打包都会输出到这个文件夹下
    },
    // loader配置
    module: {
        rules: [
            // 详细的loader配置
            // 不同文件必须配置不同loader处理
            {
                // 匹配哪些文件
                test: /\.less$/,
                // 使用哪些loader进行处理
                use: [
                    // use数组中loader执行顺序:从右到左,从下到上,依次执行
                    // style-loader:创建style标签,将js中的样式资源插入进去,添加到head中生效
                    'style-loader',
                    // css-loader:将css文件变成commonjs模块加载到js中,里面内容是样式字符串
                    'css-loader',
                    // less-loader:将less文件编译成css文件,需要下载less-loader和less
                    'less-loader'
                ],
            },
            {
                test: /\.css$/,
                use: ['style-loader', 'css-loader'],
            },
            {
                test: /\.html$/,
                // 处理html文件的img图片(负责引入img,从而能被url-loader进行处理)
                loader: 'html-loader',
                options: {
                  esModule: false
                }
            },
            {
                test: /\.(png|jpg|gif)$/,
                // 指定资源打包的类型
                type: 'asset',
                parser: {
                    dataUrlCondition: {
                        maxSize: 8 * 1024
                    }
                },
                // 指定资源打包后输出的位置和名字
                generator:{
                    filename: 'imgs/[name].[hash:5][ext]'
                }
            },
            // 打包其他资源(除了html/js/css/图片资源以外的资源)
            {
                test: /\.(ttf|woff|woff2)$/,
                // 指定资源打包的类型
                type: 'asset/resource',
                generator:{
                    filename:'media/[name].[hash:5][ext]'
                }
            },
        ],
    },
    // plugin的配置
    plugins: [
        // html-webpack-plugin:默认会创建一个空的html文件,自动引入打包输出的所有资源(JS/CSS)
        // 需要有结构的HTML文件可以加一个template
        new HtmlWebpackPlugin({
            // 复制这个./src/index.html文件,并自动引入打包输出的所有资源(JS/CSS)
            template: './src/index.html',
        }),
    ],
    // 模式
    mode: 'development', // 开发模式
    // 开发服务器 devServer:用来自动化,不用每次修改后都重新输入webpack打包一遍(自动编译,自动打开浏览器,自动刷新浏览器)
    // 特点:只会在内存中编译打包,不会有任何输出(不会像之前那样在外面看到打包输出的build包,而是在内存中,关闭后会自动删除)
    devServer: {
        // 指定加载的目录的路径
        contentBase: resolve(__dirname, 'build'),

        // 启动gzip压缩,让我们代码体积更小,启动更快
        compress: true,

        // 端口号
        port: 6789,

        // 自动打开浏览器
        open: true,

        // 热更新
        // 只在内存中打包
        // 即,打包输出目录中并没有数据
        liveReload: true
    },
    // 只适用于web相关的target
    target: 'web',
}

四. webpack生产环境配置

而生产环境的配置需要考虑以下几个方面:

  • 提取 css 成单独文件
  • css 兼容性处理
  • 压缩 css
  • js 语法检查
  • js 兼容性处理
  • js 压缩
  • html 压缩

    4.1把css打包为单独的文件

  • 安装 npm i mini-css-extract-plugin -D

  • 引入插件 const miniCssExtractPlugin = require('mini-css-extract-plugin')
  • 把 style-loader 替换为 miniCssExtractPlugin.loader ```javascript const { resolve } = require(‘path’) const miniCssExtractPlugin = require(‘mini-css-extract-plugin’)

module.exports = { mode: “development”, // mode: “production”, entry: “./src/index”, output: { filename: ‘built.js’, path: resolve(__dirname, “build”) }, // 配置模块 module: { // 指定规则 rules: [ { test: /.css$/, // 加载顺序,从下到上,从右到左 use: [ miniCssExtractPlugin.loader, // css-loader:将css文件变成commonjs模块加载到js中,里面内容是样式字符串 ‘css-loader’, ] }, { test: /.less$/, use: [ miniCssExtractPlugin.loader, ‘css-loader’, // less-loader:将less文件编译成css文件,需要下载less-loader和less ‘less-loader’ ] } ] }, plugins: [ // 启用插件 new miniCssExtractPlugin({ // 打包后输出的地址 filename:’css/other.css’ }) ] }

<a name="xVqIw"></a>
## 4.2css兼容性处理
安装 `npm install --D postcss-loader postcss-preset-env`
```javascript
const { resolve } = require('path')
const miniCssExtractPlugin = require('mini-css-extract-plugin')

module.exports = {
    mode: "development",
    // mode: "production",
    entry: "./src/index",
    output: {
        filename: 'built.js',
        path: resolve(__dirname, "build")
    },
    module: {
        rules: [
            {
                test: /\.css$/,
                use: [
                    miniCssExtractPlugin.loader,
                    'css-loader',
                  //---------------------------------------
                  //配置文件,官网文档有
                    {
                        loader: "postcss-loader",
                        options: {
                            postcssOptions: {
                                plugins: [
                                    [
                                        "postcss-preset-env",
                                        {
                                            // Options
                                              browsers: 'last 2 versions'
                                        },
                                    ],
                                ],
                            },
                        },
                    },
                  //---------------------------------------
                ]
            },
        ]
    },
    plugins: [
        new miniCssExtractPlugin({
            filename: 'css/other.css'
        })
    ]
}

4.3压缩css

安装 npm i -D css-minimizer-webpack-plugin

const { resolve } = require('path')
const miniCssExtractPlugin = require('mini-css-extract-plugin')
const cssMinimizerWebpackPlugin = require('css-minimizer-webpack-plugin')

module.exports = {
    mode: "development",
    // mode: "production",
    entry: "./src/index",
    output: {
        filename: 'built.js',
        path: resolve(__dirname, "build")
    },
    module: {
        rules: [
            {
                test: /\.css$/,
                use: [
                    miniCssExtractPlugin.loader,
                    'css-loader',
                ]
            },
        ]
    },
    plugins: [
        new miniCssExtractPlugin({
            filename: 'css/other.css'
        }),
           // 不需其他配置,直接使用
        new cssMinimizerWebpackPlugin()
    ]
}

4.4js语法检查

  • 安装 npm i eslint-webpack-plugin eslint eslint-config-airbnb-base eslint-plugin-import -D
  • 只检查自己的js代码,第三方库是不用检查的
  • 设置检查规则:package.json中设置
    {
      ...
    "eslintConfig": {
      "extends": "airbnb-base"
    }
      ...
    }
    
    ```javascript const { resolve } = require(‘path’) const htmlWebpackPlugin = require(‘html-webpack-plugin’) //引入插件 const ESLintPlugin = require(‘eslint-webpack-plugin’);

module.exports = { mode: ‘development’, module: { rules: [ { test: /.css$/, use: [ “style-loader”, “css-loader” ] } ] }, plugins: [ new htmlWebpackPlugin({ template: “./src/index.html” }), // 使用插件 new ESLintPlugin({ // 设置options // 排除第三方包的检查 exclude: ‘node_modules’, // 自动修复eslint的错误 fix:true }) ] }

<a name="RiKoU"></a>
## 4.5js兼容性处理
安装 `npm install -D babel-loader @babel/core @babel/preset-env `

1. 基本js兼容性处理 --> @babel/preset-env
   1. 问题:只能转换基本语法,如promise等高级语法不能转换
   1. 配置
```javascript
const { resolve } = require('path')
const htmlWebpackPlugin = require('html-webpack-plugin')

module.exports = {
    mode: 'development',
    module: {
        rules: [
            {
                test: /\.css$/,
                use: [
                    "style-loader",
                    "css-loader"
                ]
            },
            {
                test: /\.js$/,
                exclude: /node_modules/,
                loader: 'babel-loader',
                options: {
                    // 预设:指示babel做怎么样的兼容性处理
                    presets: [
                        '@babel/preset-env',
                    ]
                }
            }
        ]
    },
    plugins: [
        new htmlWebpackPlugin({
            template: "./src/index.html"
        })
    ]
}
  1. 全部的兼容性处理 —> @babel/polyfill(不考虑
    1. 在入口index.js文件中引入就可以import '@babel/polyfill'
    2. 问题:我只要解决部分兼容性问题,但是将所有兼容性代码全部引入,体积太大了
  2. 需要做兼容性处理的就按需加载 —> core-js (推荐用) ```javascript const { resolve } = require(‘path’) const htmlWebpackPlugin = require(‘html-webpack-plugin’)

module.exports = { mode: ‘development’, module: { rules: [ { test: /.css$/, use: [ “style-loader”, “css-loader” ] }, { test: /.js$/, exclude: /node_modules/, loader: ‘babel-loader’, options: { // 预设:指示babel做怎么样的兼容性处理 //————————————————- presets: [ [ ‘@babel/preset-env’, { // 使用corejs的方式:按需加载 useBuiltIns: ‘usage’, // 指定core-js的版本 corejs: { version: 3 }, // 要兼容的目标浏览器 targets: { chrome: ‘60’, firefox: ‘60’, ie: ‘9’, safari: ‘10’, edge: ‘17’ } } ] ] //————————————————— } } ] }, plugins: [ new htmlWebpackPlugin({ template: “./src/index.html” }) ] }

<a name="Pz0At"></a>
## 4.6压缩js和html
在生产环境(production)下会自动压缩js和html
<a name="6Bkap"></a>
## 4.7生产环境的基本配置
安装 `npm i -D mini-css-extract-plugin postcss-loader postcss-preset-env css-minimizer-webpack-plugin eslint-webpack-plugin eslint eslint-config-airbnb-base eslint-plugin-import babel-loader @babel/core @babel/preset-env`
```javascript
const { resolve } = require('path')
// 引入插件处理html资源
const htmlWebpackPlugin = require('html-webpack-plugin')
// 引入插件将css单独打包为一个文件
const miniCssExtractPlugin = require('mini-css-extract-plugin')
// 引入插件将css压缩
const cssMinimizerWebpackPlugin = require('css-minimizer-webpack-plugin')
// 引入插件进行js语法检查
const ESLintPlugin = require('eslint-webpack-plugin');

//定义变量进行代码复用 
const commonCssLoader = [
    // 单独打包成一个文件有问题
    // miniCssExtractPlugin.loader,
    "style-loader",
    "css-loader",
    {
        // 还需要在package.json中定义browserslist
        // "browserslist": {
        //     "development": [
        //       "last 1 chrome version",
        //       "last 1 firefox version",
        //       "last 1 safari version"
        //     ],
        //     "production": [
        //       ">0.2%",
        //       "not dead",
        //       "not op_mini all"
        //     ]
        //   }
        loader: "postcss-loader",
        options: {
            postcssOptions: {
                plugins: [
                    [
                        "postcss-preset-env",
                        {
                            // Options
                        },
                    ],
                ],
            },
        },
    },
]

module.exports = {
    entry: './src/js/index.js',
    output: {
        filename: "js/built.js",
        path: resolve(__dirname, 'build')
    },
    module: {
        rules: [
            {
                test: /\.css$/i,
                use: [...commonCssLoader]
            },
            {
                test: /\.less$/i,
                use: [...commonCssLoader, "less-loader"]
            },
            {
                // js的兼容性处理
                test: /\.js$/i,
                exclude: /node_modules/i,
                loader: 'babel-loader',
                options: {
                    // 预设:指示babel做怎么样的兼容性处理
                    //---------------------------------
                    presets: [
                        [
                            '@babel/preset-env',
                            {
                                // 按需加载
                                useBuiltIns: 'usage',
                                // 指定core-js的版本
                                corejs: {
                                    version: 3
                                },
                                // 指定兼容性做到哪个版本浏览器
                                targets: {
                                    chrome: '60',
                                    firefox: '60',
                                    ie: '9',
                                    safari: '10',
                                    edge: '17'
                                }
                            }
                        ]
                    ]
                    //----------------------------------
                }
            },
            {
                test: /\.(jpe?g|png|gif)$/i,
                type: 'asset',
                parser: {
                    dataUrlCondition: {
                        maxSize: 8 * 1024
                    }
                },
                // 指定资源打包后输出的位置和名字
                generator: {
                    filename: 'imgs/[name].[hash:5][ext]'
                },
            },
            {
                test: /\.html$/i,
                loader: 'html-loader'
            },
            // {webpack4中打包其他文件的方式,会出现url的问题
            //     exclude:/\.(html|js|css|less|jpg|png|gif)$/i,
            //     loader:'file-loader',
            //     options:{
            //         name:'[name].[hash:5].[ext]',
            //         outputPath:'media',
            //     },
            //     type: 'javascript/auto'
            // },
            {
                // 根据实际文件添加
                test: /\.(txt|woff|ttf|woff2)$/i,
                type: 'asset/resource',
                generator: {
                    filename: "media/[name].[hash:5][ext]"
                }
            }
        ]
    },
    plugins: [
        new htmlWebpackPlugin({
            template: './src/index.html'
        }),
        // 单独打包成一个文件有问题
        // new miniCssExtractPlugin({
        //     //指定css打包后的文件
        //     filename: 'css/built.css'
        // }),
        new cssMinimizerWebpackPlugin(),
        new ESLintPlugin({
            // 设置options,同时还需在package.json文件中配置使用airbnb规则来进行检查
            // "eslintConfig": {
            //     "extends": "airbnb-base"
            //   }
            // 排除第三方包的检查
            exclude: 'node_modules',
            // 自动修复eslint的错误
            fix: true
        })
    ],
    mode: 'production'
}