Skip to content

优化 webpack 配置

开发环境有开发环境的配置, 生产环境有生产环境的配置, 但是两种环境都有共同的配置, 为了便于维护, 可以将配置文件根据环境需要抽离, 使用 webpack-merge 插件

  • 安装
sh
npm i -D webpack-merge@4.2

抽离共同配置文件 webpack.base.js

js
const path = require("path");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const { CleanWebpackPlugin } = require("clean-webpack-plugin");
const CopyWebpackPlugin = require("copy-webpack-plugin");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");

module.exports = {
  entry: "./src/index.js",
  output: {
    path: path.resolve(__dirname, "dist"),
    filename: "bundle.js",
  },

  module: {
    rules: [
      // 处理 js
      {
        test: /\.js$/,
        exclude: /node_modules/, // 排除 node_modules 目录
        include: path.resolve(__dirname, "src"),
        use: [
          {
            loader: "babel-loader",
            options: {
              presets: [
                [
                  "@babel/preset-env",
                  {
                    targets: {
                      chrome: "50",
                    },
                  },
                ],
              ],

              // babel 插件
              plugins: [
                [
                  "@babel/plugin-transform-runtime",
                  {
                    absoluteRuntime: false,
                    corejs: 2, // 不污染全局作用域
                    helpers: true,
                    regenerator: true,
                    useESModules: false,
                  },
                ],
              ],
            },
          },
          {
            loader: "eslint-loader",
            options: {
              enforce: "pre",
              fix: true,
            },
          },
        ],
      },

      // 处理字体
      {
        test: /\.(eot|json|svg|ttf|woff|woff2)$/,
        use: [
          {
            loader: "file-loader",
            options: {
              filename: "[name].[ext]",
              outputPath: "fonts",
            },
          },
        ],
      },

      // 处理图片
      {
        test: /\.(gif|png|jpe?g|svg)$/i,
        use: [
          {
            loader: "url-loader",
            options: {
              name: "[hash].[ext]",
              outputPath: "images/",
              limit: 1024 * 100, // 100k
            },
          },
          {
            loader: "image-webpack-loader",
            options: {
              mozjpeg: {
                progressive: true,
                quality: 65,
              },
              optipng: {
                enabled: false,
              },
              pngquant: {
                quality: [0.65, 0.9],
                speed: 4,
              },
              gifsicle: {
                interlaced: false,
              },
              webp: {
                quality: 75,
              },
            },
          },
        ],
      },

      // 处理样式
      {
        test: /\.(c|le)ss$/,
        use: [
          {
            loader: MiniCssExtractPlugin.loader, // 将css代码抽离为为单独的文件, 然后使用 link 标签导入
          },
          "css-loader",
          "less-loader",
          "postcss-loader",
        ],
      },
    ],
  },

  plugins: [
    // 将打包内容插入到html模板插件
    new HtmlWebpackPlugin({
      minify: {
        collapseWhitespace: true, // 删除空格和换行
        removeComments: true, // 删除注释
        useShortDoctype: true, // 使用 html5 的的 doctype
      },
      template: "./index.html",
    }),

    // 抽离 css 插件
    new MiniCssExtractPlugin(),

    // 清除上一次打包结果插件
    new CleanWebpackPlugin(),

    // 复制静态文件插件
    new CopyWebpackPlugin([
      {
        from: "./docs",
        to: "docs",
      },
    ]),
  ],
};

开发环境 webpack.dev.js

js
const Merge = require("webpack-merge");
const baseConfig = require("./webpack.base.js");

module.exports = Merge(baseConfig, {
  mode: "development",
  devtool: "cheap-module-eval-source-map",

  devServer: {
    port: 8888, // 服务端监听端口
    compress: true, // 压缩
    contentBase: "./dist", // 指定提供内容的目录
    proxy: {
      // 请求代理设置
      "^/api": {
        // 域名后以
        target: "http://localhost:3000/api",
        secure: false,
      },
    },
  },

  module: {
    rules: [
      {
        enforce: "pre",
        test: /\.js$/,
        exclude: /node_modules/,
        include: `${__dirname}/src`,
        loader: "eslint-loader",
        options: {
          fix: true,
        },
      },
    ],
  },
});

生产环境 webpack.prod.js

js
const TerserJSPlugin = require("terser-webpack-plugin");
const OptimizeCSSAssetsPlugin = require("optimize-css-assets-webpack-plugin");
const baseConfig = require("./webpack.base.js");
const Merge = require("webpack-merge");

module.exports = Merge(baseConfig, {
  mode: "production",
  devtool: "cheap-module-source-map",

  // 优化压缩选项
  optimization: {
    minimizer: [new TerserJSPlugin({}), new OptimizeCSSAssetsPlugin({})],
  },
});

package.json 中配置打包命令

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

其他配置文件

  • postcss.config.js
js
module.exports = {
  plugins: {
    autoprefixer: {
      overrideBrowserslist: [
        "ie >= 8", // 兼容 ie7 以上浏览器
        "Firefox >= 3.5", // 兼容火狐版本大于 3.5 以上浏览器
        "chrome >= 35", // 兼容谷歌版本大于 35 以上浏览器
        "opera >= 11.5", // 兼容欧朋大于 11.5 以上浏览器
      ],
    },

    "postcss-sprites": {
      // 合并的图片的保存位置
      spritePath: "./dist/images",

      // 分组打包(根据文件夹分组)
      groupBy: function (img) {
        const path = img.url.substr(0, img.url.lastIndexOf("/"));
        const dir = path.substr(path.lastIndexOf("/") + 1);
        return Promise.resolve(dir);
      },

      // 过滤不需要被合并的图片(如果是jpg就不合并)
      filterBy: function (img) {
        if (/\.jpg$/i.test(img.url)) {
          return Promise.reject();
        } else {
          return Promise.resolve();
        }
      },
    },
  },
};
  • eslintrc.js 配置
js
module.exports = {
  env: {
    browser: true,
    es6: true,
  },
  extends: ["airbnb-base"],
  globals: {
    Atomics: "readonly",
    SharedArrayBuffer: "readonly",
  },
  parserOptions: {
    ecmaVersion: 2018,
    sourceType: "module",
  },
  rules: {
    // override rules
  },
};

Released under the MIT License.