美文网首页
webpack4配置记录

webpack4配置记录

作者: 漫漫江雪 | 来源:发表于2019-12-10 10:29 被阅读0次

    webpack学习笔记

    一、 学习webpack

    1. webpack基本环境

    1. npm init -y
    2. cnpm i webpack webpack-cli -D
    3. package.json下增加打包脚本
    "scripts": {
        "build": "webpack"
      },
    
    1. npm run build执行打包, webpack默认是执行src/index.js,然后生成到dist目录, 相当于如下的配置文件webpack.config.js
    const path = require('path')
    
    module.exports = {
      entry: {
        main: './src/index.js'
      },
      output: {
        filename: 'main.js',
        path: path.resolve(__dirname, 'dist')
      }
    }
    
    1. webpack默认会读取根目录下的webpack.config.js,默认的模式是production会启用压缩,增加脚本
    "scripts": {
        "dev": "webpack --mode=development",
        "build": "webpack"
      },
    

    2. webpack打包样式

    1. index.css
    * { margin: 0; padding: 0;}
    body {
      background-color: red;
    }
    
    1. index.js
    import './index.css'
    
    console.log('webpack learning')
    
    1. 要打包样式需要用到 style-loadercss-loader
    • cnpm i style-loader css-loader -D
    • 配置 webpackmodule节点
    const path = require('path')
    
    module.exports = {
      entry: {
        main: './src/index.js'
      },
      output: {
        filename: 'bundle.js',
        path: path.resolve(__dirname, 'dist')
      },
      module: {
        rules: [
          { test: /\.css$/, use: ['style-loader','css-loader']}
        ]
      }
    }
    

    3. html-webpack-plugin插件

    1. cnpm i html-webpack-plugin -D
    2. 配置webpack
    const HtmlWebpackPlugin = require('html-webpack-plugin')
    
      plugins: [
        new HtmlWebpackPlugin({
          title: 'webpack + react学习',
          template: 'index.html'
        })
      ]
    
    1. index.html模板文件
    <!DOCTYPE html>
    <html lang="en">
    <head>
      <meta charset="UTF-8">
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
      <meta http-equiv="X-UA-Compatible" content="ie=edge">
      <title><%= htmlWebpackPlugin.options.title %></title>
    </head>
    <body>
      
    </body>
    </html>
    

    4. 样式文件打包到单独的文件中

    1. cnpm i mini-css-extract-plugin -D
    2. 配置
    const MiniCssExtractPlugin = require('mini-css-extract-plugin')
    
    module: {
        rules: [
          { test: /\.css$/, use: [{
            loader: MiniCssExtractPlugin.loader
          },'css-loader']}
        ]
      },
      plugins: [
        new HtmlWebpackPlugin({
          title: 'webpack + react学习',
          template: 'index.html'
        }),
        new MiniCssExtractPlugin({
          filename: '[name].css',
          chunkFilename: '[id].css', // 这里的id就是 entry 对象的 main
          ignoreOrder: false, // Enable to remove warnings about conflicting order
        })
      ]
    

    5. 区别开发环境和生产环境

    1. cnpm i cross-env -D
    2. 改写package.json的执行脚本
    "scripts": {
        "dev": "cross-env NODE_ENV=development webpack --mode=development",
        "build": "cross-env NODE_ENV=production webpack"
      },
    
    1. 改写 mini-css-extract-plugin的配置在开发环境下启用 hmr(hot module replacement)
    const devMode = process.env.NODE_ENV !== 'production'
    const MiniCssExtractPlugin = require('mini-css-extract-plugin')
    
    module: {
      rules: [
        { test: /\.css$/, use: [{
          loader: MiniCssExtractPlugin.loader,
          options: {
            hmr: process.env.NODE_ENV === 'development'
          }
        },'css-loader']}
      ]
    },
    plugins: [
      new HtmlWebpackPlugin({
        title: 'webpack + react学习',
        template: 'index.html'
      }),
      new MiniCssExtractPlugin({
        filename: devMode ? '[name].css' : '[name].[hash].css',
        chunkFilename: devMode ? '[id].css' : '[id].[hash].css', // 这里的id就是 entry 对象的 main,此选项决定了非入口(non-entry) chunk 文件的名称。
        ignoreOrder: false, // Enable to remove warnings about conflicting order
      })
    ]
    

    6. webpack-dev-server

    1. cnpm i webpack-dev-server -D
    2. webpack.config.js配置文件增加devServer配置节
    devServer: {
      contentBase: './dist',
      // host: '0.0.0.0',
      port: 3000,
      open: true
    },
    
    1. 修改package.json中的启动脚本
    "scripts": {
        "dev": "cross-env NODE_ENV=development webpack-dev-server --mode=development",
        "build": "cross-env NODE_ENV=production webpack"
      },
    

    7. 热模块替换

    1. 首先在devServer配置节启用热模块替换
    const webpack = require('webpack')
    
    
    devServer: {
      contentBase: './dist',
      // host: '0.0.0.0',
      port: 3000,
      hot: true, // 启用热模块替换
      open: true
    },
    plugins: [
      new webpack.NamedModulesPlugin(),
      new webpack.HotModuleReplacementPlugin()
    ]
    
    1. css的打包修改成开发时使用 style-loader, 生产环境使用mini-css-extract-plugin
    module: {
      rules: [
        { test: /\.css$/, use: [
          devMode ? 'style-loader' :
          {
          loader: MiniCssExtractPlugin.loader,
          options: {
            hmr: process.env.NODE_ENV === 'development'
          }
        },'css-loader']}
      ]
    },
    

    8. webpackdevtool

    可以参考: https://segmentfault.com/a/1190000008315937

    1. 开发环境下一般配置成: devtool: 'cheap-module-source-map',
    2. 启用css-loadersourceMap
    module: {
      rules: [
        { test: /\.css$/, use: [
          devMode ? 'style-loader' :
          {
            loader: MiniCssExtractPlugin.loader,
            options: {
              hmr: process.env.NODE_ENV === 'development'
            }
          }, {
            loader: 'css-loader',
            options: { sourceMap: true }
        }]}
      ]
    },
    
    1. 几个关键字意义
    • eval: 使用eval包裹模块代码
    • source-map: 产生.map文件
    • cheap: 不包含列信息(关于列信息的解释下面会有详细介绍)也不包含loader的sourcemap
    • module: 包含loader的sourcemap(比如jsx to js ,babel的sourcemap)
    • inline: 将.map作为DataURI嵌入,不单独生成.map文件(这个配置项比较少见)

    9. 给样式加浏览器厂商前缀

    1. 安装 cnpm i postcss-loader autoprefixer -D
    2. 配置
    module: {
      rules: [
        { test: /\.css$/, use: [
          devMode ? 'style-loader' :
          {
            loader: MiniCssExtractPlugin.loader,
            options: {
              hmr: process.env.NODE_ENV === 'development'
            }
          }, {
            loader: 'css-loader',
            options: { sourceMap: true, importLoaders: 1 }
        }, "postcss-loader"]}
      ]
    },
    

    注意上面的css-loader增加了importLoaders: 1选项,该选项表示的是在交给css-loader处理前的 处理loader数量,默认值是0,上面配置了postcss-loader,所以改成1

    1. 添加 postcss.config.js
    module.exports = {
      plugins: [
        require('autoprefixer')
      ]
    }
    

    10. 清理dist目录

    1. cnpm i clean-webpack-plugin -D
    2. 使用
    const { CleanWebpackPlugin } = require('clean-webpack-plugin')
    
    plugins: [
        new CleanWebpackPlugin(),
        ...
    ]
    

    11. 处理图片资源

    1. cnpm i file-loader url-loader -D
    2. 配置webconfig.js
    module: {
      rules: [
        { test: /\.css$/, use: [
          devMode ? 'style-loader' :
          {
            loader: MiniCssExtractPlugin.loader,
            options: {
              hmr: process.env.NODE_ENV === 'development',
              publicPath: '../'
            }
          }, {
            loader: 'css-loader',
            options: { sourceMap: true, importLoaders: 1 }
          }, "postcss-loader"]
        },
        {
          test: /\.(png|jpg|gif)$/i,
          use: [
            {
              loader: 'url-loader',
              options: {
                limit: 1024 * 500, // 500KB以下会被转成base64
                name: 'images/[name].[hash:8].[ext]',
              },
            },
          ],
        },
      ]
    },
    plugins: [
      new MiniCssExtractPlugin({
        filename: devMode ? 'css/[name].css' : 'css/[name].[hash].css',
        chunkFilename: devMode ? 'css/[id].css' : 'css/[id].[hash].css', // 这里的id就是 entry 对象的 main,此选项决定了非入口(non-entry) chunk 文件的名称。
        ignoreOrder: false, // Enable to remove warnings about conflicting order
      })
    ]
    

    上面有个路径问题需要特别注意

    • MiniCssExtractPluginfilename增加了css/,也就是将提取的css都放到 css目录
    • 图片资源放置到 images目录,所以url-loader也给name增加了 images/
    • 因为样式都被放到了css目录,要相应的给MiniCssExtractPlugin.loader 增加 publicPath: '../'

    12. 字体文件

    1. cnpm i file-loader -D
    2. 配置
    module: {
      rules: [
        {
          test: /\.(woff|woff2|eot|ttf|otf)$/i,
          use: [
            {
              loader: 'file-loader',
              options: {
                name: 'fonts/[name].[hash:8].[ext]'
              }
            }
          ]
        }
      ]
    }
    

    13. 使用babel

    1. cnpm install -D babel-loader @babel/core @babel/preset-env
    2. 根目录下增加babel的配置文件.babelrc
    {
      "presets": ["@babel/preset-env"]
    }
    
    1. 修改webpack.config.js启用babel-loader
    output: {
      filename: 'js/bundle.js', // 将js都保存到js目录
      path: path.resolve(__dirname, 'dist')
    },
    module: {
      rules: [
        { test: /\.js$/, exclude: /node_modules/, loader: "babel-loader" }
      ]
    }
    

    14. 完整的webpack.config.js

    1. webpack.config.js
    const path = require('path')
    const devMode = process.env.NODE_ENV !== 'production'
    
    const HtmlWebpackPlugin = require('html-webpack-plugin')
    const MiniCssExtractPlugin = require('mini-css-extract-plugin')
    const webpack = require('webpack')
    const { CleanWebpackPlugin } = require('clean-webpack-plugin')
    
    module.exports = {
      entry: {
        main: './src/index.js'
      },
      output: {
        filename: 'js/bundle.js', // 将js都保存到js目录
        path: path.resolve(__dirname, 'dist')
      },
      devtool: 'cheap-module-source-map',
      devServer: {
        contentBase: './dist',
        // host: '0.0.0.0',
        port: 3000,
        hot: true, // 启用热模块替换
        open: true
      },
      module: {
        rules: [
          { test: /\.css$/, use: [
            devMode ? 'style-loader' :
            {
              loader: MiniCssExtractPlugin.loader,
              options: {
                hmr: process.env.NODE_ENV === 'development',
                publicPath: '../'
              }
            }, {
              loader: 'css-loader',
              options: { sourceMap: true, importLoaders: 1 }
            }, "postcss-loader"]
          },
          {
            test: /\.(png|jpg|gif)$/i,
            use: [
              {
                loader: 'url-loader',
                options: {
                  limit: 1024 * 500, // 500KB以下会被转成base64
                  name: 'images/[name].[hash:8].[ext]',
                },
              },
            ],
          },
          {
            test: /\.(woff|woff2|eot|ttf|otf)$/i,
            use: [
              {
                loader: 'file-loader',
                options: {
                  name: 'fonts/[name].[hash:8].[ext]'
                }
              }
            ]
          },
          { test: /\.js$/, exclude: /node_modules/, loader: "babel-loader" }
        ]
      },
      plugins: [
        new CleanWebpackPlugin(),
        new HtmlWebpackPlugin({
          title: 'webpack + react学习',
          template: 'index.html'
        }),
        new MiniCssExtractPlugin({
          filename: devMode ? 'css/[name].css' : 'css/[name].[hash].css',
          chunkFilename: devMode ? 'css/[id].css' : 'css/[id].[hash].css', // 这里的id就是 entry 对象的 main,此选项决定了非入口(non-entry) chunk 文件的名称。
          ignoreOrder: false, // Enable to remove warnings about conflicting order
        }),
        new webpack.NamedModulesPlugin(),
        new webpack.HotModuleReplacementPlugin()
      ]
    }
    
    1. package.json中的脚本
    "scripts": {
      "dev": "cross-env NODE_ENV=development webpack-dev-server --mode=development",
      "devTest": "cross-env NODE_ENV=development webpack --mode=development",
      "build": "cross-env NODE_ENV=production webpack"
    },
    

    15. 将开发和生产环境的公共配置抽离出来

    因为开发和生产的配置有些是共用的配置,有些是不同的配置, 如: 开发时使用style-loader方便hmr,不需要mini-css-extract-plugin,有devServer配置

    而生产环境是不需要热模块替换的(hot module replacement)

    1. 建立build文件夹
    2. cnpm i webpack-merge -D
    3. build/webpack.common.js
    const path = require('path')
    const HtmlWebpackPlugin = require('html-webpack-plugin')
    const { CleanWebpackPlugin } = require('clean-webpack-plugin')
    
    module.exports = {
      entry: {
        main: path.resolve(__dirname, '../src/index.js')
      },
      output: {
        filename: 'js/bundle.js', // 将js都保存到js目录
        path: path.resolve(__dirname, '../dist')
      },
      module: {
        rules: [
          {
            test: /\.(png|jpg|gif)$/i,
            use: [
              {
                loader: 'url-loader',
                options: {
                  limit: 1024 * 500, // 500KB以下会被转成base64
                  name: 'images/[name].[hash:8].[ext]',
                },
              },
            ],
          },
          {
            test: /\.(woff|woff2|eot|ttf|otf)$/i,
            use: [
              {
                loader: 'file-loader',
                options: {
                  name: 'fonts/[name].[hash:8].[ext]'
                }
              }
            ]
          },
          { test: /\.js$/, exclude: /node_modules/, loader: "babel-loader" }
        ]
      },
      plugins: [
        new CleanWebpackPlugin(),
        new HtmlWebpackPlugin({
          title: 'webpack + react学习',
          template: 'index.html'
        })
      ]
    }
    
    1. build/webpack.dev.js
    const merge = require('webpack-merge')
    const webpack = require('webpack')
    const common = require('./webpack.common')
    
    module.exports = merge(common, {
      mode: 'development',
      devtool: 'cheap-module-source-map',
      devServer: {
        contentBase: '../dist',
        // host: '0.0.0.0',
        port: 3000,
        hot: true, // 启用热模块替换
        open: true
      },
      module: {
        rules: [
          { test: /\.css$/, use: [
            'style-loader', 
            {
              loader: 'css-loader',
              options: { sourceMap: true, importLoaders: 1 }
            }, 
            'postcss-loader']
          },
        ]
      },
      plugins: [
        new webpack.NamedModulesPlugin(),
        new webpack.HotModuleReplacementPlugin()
      ]
    })
    
    1. build/webpack.prod.js
    const merge = require('webpack-merge')
    const MiniCssExtractPlugin = require('mini-css-extract-plugin')
    const common = require('./webpack.common')
    
    module.exports = merge(common, {
      mode: 'production',
      devtool: 'source-map',
      module: {
        rules: [
          { test: /\.css$/, use: [
            {
              loader: MiniCssExtractPlugin.loader,
              options: {
                publicPath: '../'
              }
            }, 
            {
              loader: 'css-loader',
              options: { sourceMap: true, importLoaders: 1 }
            }, 
            'postcss-loader']
          },
        ]
      },
      plugins: [
        new MiniCssExtractPlugin({
          filename: 'css/[name].[hash].css',
          chunkFilename: 'css/[id].[hash].css', // 这里的id就是 entry 对象的 main,此选项决定了非入口(non-entry) chunk 文件的名称。
          ignoreOrder: false, // Enable to remove warnings about conflicting order
        })
      ]
    })
    
    1. 最后修改package.json中的脚本
    "scripts": {
      "dev": "cross-env NODE_ENV=development webpack-dev-server --config build/webpack.dev.js",
      "devTest": "cross-env NODE_ENV=development webpack --config build/webpack.dev.js",
      "build": "cross-env NODE_ENV=production webpack --config build/webpack.prod.js"
    },
    

    遗留配置:

    1. 使用 scss、stylus等css预处理器
    2. treeshaking 配置
    3. 公共模块的打包配置 (多页面需要重点考虑,使用默认也可以)

    相关文章

      网友评论

          本文标题:webpack4配置记录

          本文链接:https://www.haomeiwen.com/subject/djbwgctx.html