likes
comments
collection
share

用 webpack-chain 来配置 webpack5

作者站长头像
站长
· 阅读数 34

缘由

webpack 虽然不陌生,但实际配置起来,相信大部分人并没有觉得多轻松。以前在使用 umi 框架时,接触了一点 webpack-chain,感觉很不错的样子。最近想试试 webpack5 的模块联邦,于是把项目里的 webpack4 升级成 webpack5,里面就使用了 webpack-chain。配合 typescript 的类型提示,就很爽。

配置

entry

const path = require("path");
const Config = require("webpack-chain");
const config = new Config();

config.entry("index").add(path.join(__dirname, "../src/index.tsx"));

output

config.output
    .path(path.join(__dirname, "../dist"))
    .pathinfo(true)
    .filename('static/js/[name].[contenthash:8].bundle.js')
    .chunkFilename('static/js/[name].[contenthash:8].chunk.js')
    .publicPath('./')
    .globalObject('this');

resolve

const TsconfigPathsPlugin = require('tsconfig-paths-webpack-plugin');
// 模块查询
config.resolve.modules
  .add('node_modules')
  .end()
  .mainFields.clear()
  .add('main')
  .add('browser')
  .end()
  .extensions
  .add('.ts')
  .add('.tsx')
  .add('.js')
  .end()
  .alias
  .set('@/*', paths.appSrc)
  .end()
  .plugin('tsconfig-path')
  .use(TsconfigPathsPlugin, [
    {
      configFile: path.join(__dirname, "../tsconfig.json"),
    },
  ])
  .end();

fallback

webpack4 默认会添加 node 模块的 polyfill,webpack5 就取消 polyfill 了,所以需要自己设置。

config.resolve.set('fallback', {
  os: require.resolve('os-browserify'),
  path: false,
  zlib: false,
  stream: require.resolve('stream-browserify'),
  fs: false,
  tty: require.resolve('tty-browserify'),
  memcpy: false,
});

module

图片

config.module
  .rule('image')
  .test(/\.(bmp|gif|jpg|jpeg|png)$/)
  .type('asset')
  .parser({
    dataUrlCondition: {
      maxSize: 8 * 1024,
    },
  });

字体文件

config.module
  .rule('assets')
  .test(/\.(ico|woff|woff2|ttf|eot)$/)
  .type('asset/resource');

svg

config.module
  .rule('svg')
  .test(/\.svg$/)
  .use('@svgr/webpack')
  .loader('@svgr/webpack')
  .end()
  .use('url-loader')
  .loader('url-loader');

js、ts、tsx等

config.module
  .rule('babel')
  .test(/\.(js|jsx|ts|tsx|mjs|cjs)$/)
  .exclude.add(/node_modules/)
  .add(/bower_components/)
  .end()
  .include
  .add(path.join(__dirname, "../src"))
  .end()
  .use('thread-loader')
  .loader('thread-loader')
  .end()
  .use('babel-loader')
  .loader('babel-loader')
  .options(babelOptions);

less

const MiniCssExtractPlugin = require('mini-css-extract-plugin');
config.module
  .rule('less')
  .test(/\.less/)
  .when(
    process.env.NODE_ENV === 'developement',
    (c) => c.module.rule('less').use('style-loader').loader('style-loader'),
    (c) => c.module.rule('less').use('css-extract').loader(MiniCssExtractPlugin.loader)
  )
  .end()
  .use('css-loader')
  .loader('css-loader')
  .end()
  .use('postcss-loader')
  .loader('postcss-loader')
  .end()
  .use('less-loader')
  .loader('less-loader')
  .options({
    lessOptions: {
      modifyVars: require('../theme'),
      javascriptEnabled: true,
    },
    sourceMap: true,
  });

这里使用了 when 的语法,根据运行环境的不同,使用不同的 loader 来处理 css

scss

scssless 的配置类似

plugins

const webpack = require("webpack");
const MiniCssExtractPlugin = require('mini-css-extract-plugin');

config
  .plugin('define-plugin')
  .use(webpack.DefinePlugin, [env.stringified])
  .end()
  .plugin('ignore-plugin')
  .use(webpack.IgnorePlugin, [/^\.\/locale$/, /moment$/])
  .end()
  .plugin('provider-plugin')
  .use(webpack.ProvidePlugin, [
    {
      Buffer: ['buffer', 'Buffer'],
    },
  ])
  .end()
  .when(process.env.NODE_ENV === 'production', (c) => c.config.plugin('css-extract-plugin').use(MiniCssExtractPlugin, [
    {
      filename: 'static/css/[name].css',
      chunkFilename: 'static/css/[name].[contenthash:8].css',
    },
  ]))

DefinePlugin

常见用法
config.plugin('define-plugin').use(webpack.DefinePlugin, [{
    "process.env.API_URL": JSON.stringify('http://api.xxxx.com')
}])
高级用法

借助 dotenvcross-env

dotenv 可以读取 .env 这类文件的里写的环境变量。

eg: .env.development

# 开发环境接口地址
REACT_APP_API_URL=http://api.xxx.com

eg: .env.js, 读取自定义的环境变量

const path = require("path");
const fs = require("fs");

const dotenv = path.join(__dirname, "../.env");
// 读取.env, .env.xxx, .env.xxx.local 文件,读取环境变量
var dotenvFiles = [
  `${dotenv}.${NODE_ENV}.local`,
  `${dotenv}.${NODE_ENV}`,
  NODE_ENV !== 'test' && `${dotenv}.local`,
  dotenv,
].filter(Boolean);

dotenvFiles.forEach((dotenvFile) => {
  if (fs.existsSync(dotenvFile)) {
    require('dotenv').config({
      path: dotenvFile,
    });
  }
});

const REACT_APP = /^REACT_APP_/i;

function getClientEnvironment(publicUrl) {
  const raw = Object.keys(process.env)
    .filter((key) => REACT_APP.test(key))
    .reduce(
      (env, key) => {
        env[key] = process.env[key];
        return env;
      },
      {
        NODE_ENV: process.env.NODE_ENV || 'development',
        PUBLIC_URL: publicUrl,
      }
    );
  // Stringify all values so we can feed into Webpack DefinePlugin
  const stringified = {
    'process.env': Object.keys(raw).reduce((env, key) => {
      env[key] = JSON.stringify(raw[key]);
      return env;
    }, {}),
  };

  return { raw, stringified };
}

optimization

const CssMinimizerPlugin = require('css-minimizer-webpack-plugin');

config.optimization
  .splitChunks({
    chunks: 'async',
    minSize: 20000,
    minChunks: 1,
    maxAsyncRequests: 5,
    maxInitialRequests: 3,
    name: false,
    cacheGroups: {
      common: {
        name: 'common',
        test: /[\\/]src[\\/]/,
        chunks: 'initial',
        minChunks: 2, //一般为非第三方公共模块
        priority: -20,
        reuseExistingChunk: true,
      },
    },
  })
  .runtimeChunk('multiple')
  .minimizer('css-minimizer')
  .use(CssMinimizerPlugin) // 压缩css
  .end()
  .minimizer('teser-plugin')
  .use(TerserPlugin) // 压缩js
  .end()
  .concatenateModules(true)
  .minimize(true);

导出配置


module.exports = config.toConfig();

npm scripts

{
    "scripts": {
        "start": "webpack serve --config ./config/webpack.config.dev.js --progress",
        "build:prod": "cross-env REACT_APP_API_URL=http://api.xxx.com webpack --config ./config/webpack.config.prod.js --progress"
    }
}

总结

总的来说,配合 ts 的类型提示,不用一直去翻文档,写起来比较方便。推荐大家可以尝试下。

转载自:https://juejin.cn/post/7006675512290443295
评论
请登录