dva+roadhog打包优化

奋斗吧
奋斗吧
擅长邻域:未填写

标签: dva+roadhog打包优化 Webpack博客 51CTO博客

2023-04-27 18:23:53 270浏览

dva+roadhog打包优化,webpck3的性能优化

背景

公司有个老项目,使用还是dva+roadhog的打包构建工具,随着项目越来越大,代码越来越多,引入的包也越来越多,工程构件速度很慢,该项目用的是roadhog打包工具,roadhog引用的是af-webpack,而af-webpack又是对webpack3的封装,导致不能进行一些自定义的扩展,目前roadhog作者已经不维护了,所以想着在换掉roadhog包直接使用webpack3进行打包优化。


思路

删掉roadhog包,安装webpack3,webpack-dev-server,同时配置对应的plugin和loader


plugin和loader版本推荐

webpack包如下

webpack@3.5.6 webpack-dev-server@2.9.4

引入其他的plugin和loader

html-webpack-plugin@2.30.1 //生成html插件
html-webpack-externals-plugin@3.8.0 //外部链接引入包插件
happypack@4.0.0 //并发打包,thread-loader只支持webpack4,所以使用happypack
babel-loader@8.2.2 //解析js,jsx的loader
style-loader@0.20.3 //将编译完的css插入html的loader
css-loader@0.28.7 //将css代码编译的loader
less-loader@4.0.5 //将less转译成css的loader
url-loader@0.6.2 //处理图片资源的loader
file-loader@4.0.0 //处理字体/svg资源的loader
clean-webpack-plugin@2.0.0 //清理打包目录的plugin
uglifyjs-webpack-plugin@1.3.0 //并发压缩js的plugin
copy-webpack-plugin@4.4.1 //拷贝文件的plugin,比如静态图片资源
extract-text-webpack-plugin@3.0.0 //将css单独抽离为文件的

为啥想替换掉roadhog,主要是想用到happypack的并发打包能力,能大大加快打包速度。

项目目录

dva+roadhog打包优化_react

开发环境

下面贴一下开发环境下的webpack配置

let path = require('path')
let webpack = require('webpack')
const HtmlWebpackPlugin = require('html-webpack-plugin');// 2.30.1
const HtmlWebpackExternalsPlugin = require('html-webpack-externals-plugin');

let HappyPack = require('happypack');

// const DIST_PATH = path.resolve(__dirname, '../dist'); // 生产目录
const APP_PATH = path.resolve(__dirname, '../src'); // 源文件目录
const theme = require('../src/theme');
// 主题颜色
module.exports = {
  // bundle入口
  entry: {
    index: './src/index.js',
  },
  devtool: 'eval-cheap-module-source-map',
  // bundle输出
  output: {
    path: path.join(__dirname, 'dist'),
    filename: '[name].[contenthash].js',
    chunkFilename: '[name].[contenthash].async.js',
    publicPath: '/',
  },
  plugins: [
    new HtmlWebpackExternalsPlugin({
      externals: [
        {
          // 引入的模块
          module: 'lodash',
          // cdn的地址
          entry: 'https://xxxxxxxxx/lodash.js/4.17.21/lodash.min.js',
          // 挂载到了window上的名称
          global: '_',
        },
        {
          // 引入的模块
          module: 'ali-oss',
          // cdn的地址
          entry: 'https://xxxxxxxxx/xxx/xxx/aliyun-oss-sdk.min.1208.js',
          // 挂载到了window上的名称
          global: 'OSS',
        },
      ],
    }),
    // 处理html
    new HtmlWebpackPlugin({
      template:
        process.env.API_ENV == 'prod'
          ? './src/index-prod.ejs'
          : process.env.API_ENV == 'staging'
            ? './src/index-staging.ejs'
            : process.env.API_ENV == 'test'
              ? './src/index-test.ejs'
              : process.env.API_ENV == 'dev'
                ? './src/index-dev.ejs'
                : './src/index.ejs',
      inject: 'body',
      minify: {
        html5: true,
      },
      hash: false,
      chunksSortMode: 'manual',
      chunks: ['manifest', 'vendor', 'antd', 'react', 'pdf', 'components', 'index'],
    }),
    new HappyPack({
      id: 'babel',
      loaders: [
        {
          loader: 'babel-loader',
          options: {
            cacheDirectory: true,
          },
        },
      ],
    }),
    
    new HappyPack({
      id: 'css1',
      loaders: [
        { loader: 'style-loader' },
        {
          loader: 'css-loader',
          options: {
            sourceMap: false,
          },
        },
      ],
    }),
    new HappyPack({
      id: 'less1',
      loaders: [
        { loader: 'style-loader' },
        {
          loader: 'css-loader',
          options: {
            modules: true, // true -> import styles from 'xxx.less'  false -> import 'xxx.less'
            sourceMap: false,
            localIdentName:
                 process.env.NODE_ENV === 'production' ? '[hash:base64]' : '[path][name]__[local]', // 指定样式名,加快本地开发编译速度,
          },
        },
        {
          loader: 'less-loader',
          options: { javascriptEnabled: true, modifyVars: theme, sourceMap: false },
        },
      ],
    }),
    
    new webpack.HotModuleReplacementPlugin(),

    new webpack.optimize.CommonsChunkPlugin({
      name: 'manifest',
      minChunks: Infinity,
    }),

  ],
  module: {
    noParse: /jquery/,
    rules: [
      {
        test: /\.(js|jsx)?$/,
        exclude: /node_modules/,
        include: APP_PATH,
        use: ['happypack/loader?id=babel'],
      },
      {
        test: /\.css$/,
        use: ['happypack/loader?id=css1'],
      },
      {
        test: /\.less$/,
        use: ['happypack/loader?id=less1'],
      },
      {
        test: /\.(jpg|png|gif|bmp|jpeg)$/,
        use: "url-loader",
      },
      {
        test: /\.(woff|svg)$/,
        use: 'file-loader',
        exclude: /node_modules/,
      },
    ],
    /*
     *解决Critical dependency: require function is used in a way in which dependencies cannot be statically extracted的问题
     *unknownContextCritical : false,
     *解决the request of a dependency is an expression
     */
    exprContextCritical: false,

  },
  resolve: {
    alias: {
      components: path.resolve(__dirname, '../src/components/'),
      services: path.resolve(__dirname, '../src/services/'),
      common: path.resolve(__dirname, '../src/common/'),
      utils: path.resolve(__dirname, '../src/utils/'),
      routes: path.resolve(__dirname, '../src/routes/'),
      assets: path.resolve(__dirname, '../src/assets/'),
      '@': path.resolve(__dirname, '../src/'),
    },
    extensions: ['.js', '.jsx'], // 解析文件后缀
  },
  devServer: {
    overlay: {
      errors: true,
    },
    /*
     * 用来编译完成之后最终控制台显示的输出
     *stats: "errors-only",
     */
    port: 8009,
    host: 'localhost', // '0.0.0.0',
    compress: true, // 启用 gzip
    historyApiFallback: true,
    hot: true, // 开启
    https: false,
    inline: true,
    open: true,
    // publicPath: '/',
    headers: {
      'Access-Control-Allow-Origin': '*',
    },
    proxy: {
      // 连后端对应开发者电脑
      '/zhApi': {
        target: 'http://xxx.xx.xx.xxx:7014',
        changeOrigin: true,
        pathRewrite: {
          '^/zhApi': '',
        },
      },
    },
  },
}

配合开发环境的hmr,要把.babelrc.js也配置一下

@babel/preset-env
@babel/preset-react
@babel/plugin-proposal-class-properties@7.17.12
@babel/plugin-proposal-decorators@7.18.2
@babel/plugin-proposal-private-methods@7.17.12
@babel/plugin-proposal-private-property-in-object@7.17.12
@babel/plugin-transform-runtime@7.4.4
babel-plugin-dva-hmr //这个是hmr的关键,其他的都是针对js新特性的一些编译包
babel-plugin-dynamic-import-node@2.3.3 //这个能加速开发时编译速度
const path = require('path');

module.exports = {
  presets: [
    ['@babel/preset-env'],
    ['@babel/preset-react', {runtime: 'automatic'}],
  ],
  plugins: [
    [
      'module-resolver',//个人感觉不需要
      {
        alias: {
          components: path.join(__dirname, './src/components'),
        },
      },
    ],
    [
      'import',
      {
        libraryName: 'antd',
        libraryDirectory:"es",
        style: "css", // or 'css'
      },
    ],
    ["@babel/plugin-proposal-decorators", { legacy: true}],
    ["@babel/plugin-proposal-class-properties", { "loose" : true }],
    ["@babel/plugin-proposal-private-property-in-object", { "loose": true }],
    ["@babel/plugin-proposal-private-methods", { "loose": true }],
    '@babel/plugin-transform-runtime',
    'dva-hmr',
    '@babel/plugin-syntax-dynamic-import'
  ],
  'env': {
    'development': {
      'plugins': ['dynamic-import-node']
    }
  }
};

生产环境

let path = require('path')
let webpack = require('webpack')
const HtmlWebpackPlugin = require('html-webpack-plugin');// 2.30.1
const HtmlWebpackExternalsPlugin = require('html-webpack-externals-plugin');

let HappyPack = require('happypack');
const CleanWebpackPlugin = require('clean-webpack-plugin');
const UglifyJsPlugin = require('uglifyjs-webpack-plugin');


const CopyWebpackPlugin = require('copy-webpack-plugin');
const ExtractTextPlugin = require('extract-text-webpack-plugin'); // 单独打包css

const DIST_PATH = path.resolve(__dirname, '../dist'); // 生产目录
const APP_PATH = path.resolve(__dirname, '../src'); // 源文件目录
let Webpack = require('webpack');

const SRC_PUBLIC_PATH = path.resolve(__dirname, '../public');
const theme = require('../src/theme');
// 主题颜色
module.exports = {
  // bundle入口
  entry: {
    index: './src/index.js',
  },
  devtool: 'hidden-source-map',
  output: {
    path: path.join(__dirname, '../dist'),
    filename: '[name].[contentHash].js',
    chunkFilename: '[name].[contentHash].async.js',
    publicPath: '/',
    pathinfo: false,
  },
  plugins: [
    new HtmlWebpackExternalsPlugin({
      externals: [
        {
          // 引入的模块
          module: 'lodash',
          // cdn的地址
          entry: 'https://xxxxxxx/xxx/xxxx/lodash.js/4.17.21/lodash.min.js',
          // 挂载到了window上的名称
          global: '_',
        },
        {
          // 引入的模块
          module: 'ali-oss',
          // cdn的地址
          entry: 'https://xxxxxx/xxxx/xxx/aliyun-oss-sdk.min.1208.js',
          // 挂载到了window上的名称
          global: 'OSS',
        },
      ],
    }),
    // 处理html
    new HtmlWebpackPlugin({
      template:
        process.env.API_ENV == 'prod'
          ? './src/index-prod.ejs'
          : process.env.API_ENV == 'staging'
            ? './src/index-staging.ejs'
            : process.env.API_ENV == 'test'
              ? './src/index-test.ejs'
              : process.env.API_ENV == 'dev'
                ? './src/index-dev.ejs'
                : './src/index.ejs',
      favicon: `${SRC_PUBLIC_PATH}/favicon.png`,
      minify: {
        removeComments: true,
        collapseWhitespace: true,
        removeAttributeQuotes: true,
      },
      hash: false,
      chunksSortMode: 'manual',
      chunks: ['manifest', 'vendor', 'antd', 'react', 'pdf', 'components', 'index'],
    }),
    new UglifyJsPlugin({
      sourceMap: false,
      cache: false, // 是否启用文件缓存,默认缓存在node_modules/.cache/uglifyjs-webpack-plugin.目录
      parallel: true, // 使用多进程并行运行来提高构建速度
      extractComments: false,
      uglifyOptions: {
        warnings: false,
        compress: {
          drop_console: true,
          drop_debugger: true,
          unused: false,
        },
      },
    }),
    new HappyPack({
      id: 'babel',
      loaders: [
        {
          loader: 'babel-loader',
          options: {
            cacheDirectory: true,
          },
        },
      ],
    }),
     
    new HappyPack({
      id: 'css1',
      loaders: [
        // { loader: 'style-loader' },
        { loader: 'css-loader',
          options: { sourceMap: false },
        },
      ],
    }),
    new HappyPack({
      id: 'less1',
      loaders: [
        // { loader: 'style-loader' },
        {
          loader: 'css-loader',
          options: {
            modules: true, // true -> import styles from 'xxx.less'  false -> import 'xxx.less'
            sourceMap: false,
            localIdentName:
                 process.env.NODE_ENV === 'production' ? '[hash:base64]' : '[path][name]__[local]', // 指定样式名,加快本地开发编译速度,
          },
        },
        {
          loader: 'less-loader',
          options: { javascriptEnabled: true, modifyVars: theme, sourceMap: false },
        },
      ],
    }),
    
    new webpack.optimize.CommonsChunkPlugin({
      names: ['vendor'],   /* 对应上面的提取的公共文件模块  */
      chunks: ['index'],
      minChunks(module) {
        return (
          module.resource && /\.(js|jsx)$/.test(module.resource) && module.resource.includes('node_modules')
        )
      },
    }),
    new webpack.optimize.CommonsChunkPlugin({
      name: 'antd',
      chunks: ['vendor'],
      minChunks(module) {
        return module.resource && /(\/antd|\/antd-mobile|\/dva|\/dva-loading)/.test(module.resource)
      },
    }),
    new webpack.optimize.CommonsChunkPlugin({
      name: 'react',
      chunks: ['vendor'],
      minChunks(module) {
        const tests = /(\/react-redux\/)|(\/react\/)|(\/react-router-dom\/)|(\/react-lazy-load\/)|(\/react-router-redux\/)|(\/react-router\/)|(\/react-is\/)|(\/react-dom\/)|(\/react-lifecycles-compat\/)/
        return module.context && tests.test(module.context)
      },
    }),
    new webpack.optimize.CommonsChunkPlugin({
      name: 'pdf',
      chunks: ['vendor'],
      minChunks(module) {
        return module.context && /(react-pdf)|(pdfjs-dist)/.test(module.context)
      },
    }),
    new webpack.optimize.CommonsChunkPlugin({
      names: ['components'],
      chunks: ['index'],
      minChunks(module) {
        const flag = module.resource && (/src\/(components|common|layouts|models|services|utils)/.test(module.resource));
        return (
          module.resource && /\.(js|jsx)$/.test(module.resource) && flag
        )
      },
    }),

    new webpack.optimize.CommonsChunkPlugin({
      name: 'manifest',
      minChunks: Infinity,
    }),
    new CleanWebpackPlugin(),
    new CopyWebpackPlugin([
      {
        from: `${SRC_PUBLIC_PATH}`,
        to: `${DIST_PATH}/static`,
      },
    ]),
    new ExtractTextPlugin({
      filename: '[name].[contenthash:8].css',
      allChunks: true,
    }),
    new Webpack.IgnorePlugin(/\.\/locale/, /moment/), // moment这个库中,如果引用了./locale/目录的内容,就忽略掉,不会打包进去
  ],
  module: {
    noParse: /jquery/,
    rules: [
      {
        test: /\.(js|jsx)?$/,
        exclude: /node_modules/,
        include: APP_PATH,
        use: ['happypack/loader?id=babel'],
      },
      {
        test: /\.css$/,
        use: ExtractTextPlugin.extract({
          fallback: "style-loader",
          use: `${path.resolve(__dirname, '../node_modules', 'happypack/loader')}?id=css1`,
        }
        ),
      },
      {
        test: /\.less$/, // ['happypack/loader?id=less1']
        include: APP_PATH,
        use: ExtractTextPlugin.extract({
          fallback: "style-loader",
          use: `${path.resolve(__dirname, '../node_modules', 'happypack/loader')}?id=less1`,
        }),
      },
      {
        test: /\.(jpg|png|gif|bmp|jpeg)$/,
        use: {
          loader: "url-loader",
          options: {
            esModule: false, // 这里设置为false
            // outputPath:'static/',//输出**文件夹
            publicPath: '/',
            name: '[name].[ext]',
            limit: 8 * 1024, // 是把小于8 kb的文件打成Base64的格式,写入JS
          },
        },
      },
      {
        test: /\.(woff|svg)$/,
        use: 'file-loader',
        exclude: /node_modules/,
      },
    ],
    /*
     *解决Critical dependency: require function is used in a way in which dependencies cannot be statically extracted的问题
     *unknownContextCritical : false,
     *解决the request of a dependency is an expression
     */
    exprContextCritical: false,
  },
  resolve: {
    alias: {
      components: path.resolve(__dirname, '../src/components/'),
      services: path.resolve(__dirname, '../src/services/'),
      common: path.resolve(__dirname, '../src/common/'),
      utils: path.resolve(__dirname, '../src/utils/'),
      routes: path.resolve(__dirname, '../src/routes/'),
      assets: path.resolve(__dirname, '../src/assets/'),
      '@': path.resolve(__dirname, '../src/'),
    },
    extensions: ['.js', '.jsx'], // 解析文件后缀
  },
}


问题

1.HardSourceWebpackPlugin 这个缓存插件好像跟happypack不兼容,不然开发环境二次编译会更加快速

2.webpack3还是比较老了,很多新特性和新插件都不支持,所以后续考虑升级到webpack5试试

好博客就要一起分享哦!分享海报

此处可发布评论

评论(0展开评论

暂无评论,快来写一下吧

展开评论

您可能感兴趣的博客

客服QQ 1913284695