项目打包体积优化

309 阅读4分钟

项目体积优化

原始: parsed JS 体积 42M.

dist文件夹体积 56.5M

删除无用包

工具: npm install -g depcheck

命令: depcheck

删除

红色字体表示不可删除。

灰色字体表示暂时保留

划线字体表示已经删除。

dependencies

npm uninstall @antv/l7-react @re-editor/core @re-editor/toolbar-antd @types/lodash.debounce lodash.debounce braft-editor @types/numeral bizcharts-plugin-slider gg-editor lodash-decorators mockjs numeral nzh re-editor react-fittext

@antv/data-set@0.11.0

@antv/l7-react@2.1.9

@re-editor/core@0.5.8

@re-editor/toolbar-antd@0.5.8

@types/lodash.debounce@4.0.6

@types/lodash.isequal@4.5.5

@types/numeral@0.0.28

bizcharts-plugin-slider@2.1.1-beta.1

braft-editor@2.3.9

dva@2.4.0

gg-editor@2.0.2

lodash-decorators@6.0.0

lodash.debounce@4.0.8

lodash.isequal@4.5.0

mockjs@1.0.1-beta3

numeral@2.0.6

nzh@1.0.3

re-editor@0.5.8

react-fittext@1.0.0

devDependencies

npm uninstall @types/history @types/jest @types/react-helmet chalk enzyme husky jsdom-global pro-download

@types/history@4.7.2

@types/jest@26.0.0

@types/react-helmet@5.0.13

@umijs/plugin-blocks@2.0.5

@umijs/preset-ant-design-pro@1.2.0

@umijs/preset-react@1.4.8

@umijs/preset-ui@2.0.9

chalk@4.0.0

enzyme@3.11.0

husky@4.0.7

jsdom-global@3.0.2

pro-download@1.0.1

暂时保留

@types/history@4.7.2

@types/jest@26.0.0

@types/react-helmet@5.0.13

优化打包方式

提取公共模块、多核心打包、抽离css等

提取公共模块可以通过使用SplitChunksPlugin来实现。这个插件可以将公共的依赖模块提取出来,形成单独的文件,以便于浏览器进行缓存和复用。

// https://umijs.org/config/
import { defineConfig } from 'umi';
import defaultSettings from './defaultSettings';
import pageRoutes from './router.config';
import proxy from './proxy';
const { REACT_APP_ENV, HIDEHTTPS, NODE_ENV } = process.env;

const HappyPack = require('happypack');
const happyThreadPool = HappyPack.ThreadPool({
  size: require('os').cpus().length,
});


export default defineConfig({
  nodeModulesTransform: { // 加速打包
    type: 'none',
    exclude: [],
  },
  hash: true,
  antd: {},
  dva: {
    hmr: true,
  },
  define: {
    showHttps: HIDEHTTPS ? false : true,
  },
  mock: false,
  locale: {
    default: 'zh-CN',
    antd: true,
    baseNavigator: false,
  },
  dynamicImport: {
    loading: '@/components/PageLoading/index',
  },
  targets: {
    ie: 11,
  },
  routes: pageRoutes,
  theme: {
    'primary-color': defaultSettings.primaryColor,
  },
  // @ts-ignore
  title: false,
  ignoreMomentLocale: true,
  proxy: proxy[REACT_APP_ENV || 'dev'],
  manifest: {
    basePath: '/',
  },
  chunks: NODE_ENV === 'production' ? ['vendors', 'umi'] : undefined,
  chainWebpack: function (config, { webpack, env }) {
    // 加快编译
    config.cache({
      type: 'filesystem',
      allowCollectingMemory: true,
      buildDependencies: {
        config: [__filename],
      },
    });
    // 利用多线程,加快js打包
    config.plugin('HappyPack').use(HappyPack, [{ // 使用 HappyPack 插件
      id: 'js', 
      loaders: ['babel-loader'], // 使用 babel-loader 来处理 JavaScript 文件
      threadPool: happyThreadPool, // 指定使用一个名为 happyThreadPool 的线程池来处理多线程任务
    }]);
    // 提取公共模块,减小体积
    config.merge({
      optimization: {
        minimize: env === 'production',
        splitChunks: {
          chunks: 'all', // async异步代码分割 initial同步代码分割 all同步异步分割都开启
          minSize: 20000, // 表示当模块的大小超过20,000字节时,才会考虑将其拆分为公共模块
          minChunks: 2, // 指定一个模块至少被引用两次才会被提取为公共模块
          automaticNameDelimiter: '.',
          cacheGroups: {
            vendor: {
              name: 'vendors',
              test({ resource }) {
                return /[\/]node_modules[\/]/.test(resource);
              },
              priority: 10,
            },
            // 将css打包到一个css文件里
            styles: {
              name: 'styles',
              test: /.(css|less)$/,
              chunks: 'async',
              minChunks: 1,
              minSize: 0,
            }
          },
        },
      }
    });
  },
  // 加快编译速度
  devtool: NODE_ENV !== 'production' ? 'eval' : false,
  // 暂时还不能用,有bug
  // mfsu: {
  //   production: { output: '.mfsu-production' }
  // },
  esbuild: {}, // 增加压缩速度,可能有bug
  // webpack5: {}
});

打包时间根据当时机器可用硬件资源不同而不同,只做参考。

esbuild压缩

同样 npm run analyze, 时间从 280s -> (150s - 100s)

打包时间 290s -> (150s - 70s) 提速50%以上

打包后js 体积(parsed) 从 42M -> 5.6M,减少87%

打包后 css文件体积 减少 9.92M -> 0.62M, 减少94%

dist总体体积: 56.5 M -> 8.7M , 减少85%

压缩器选择

esbuild vs terserOptions vs mfsu

初始采用了mfsu,但是有bug,无法获取正确文件,项目无法启动。具体原因还没细查。

使用esbuild时,项目js打包体积 5.6M。

使用 terser 时, js打包体积进一步压缩。 5.6M -> 4.8M。

Terser压缩

打包的js,42M -> 4.8M,减少89%

dist总体积, 56.5M -> 7.8M,减少87%

如果打包结果有问题,且无法解决,尝试切换esbuild压缩。

经测试发现,Terser压缩后有点问题,build后react会报错。

EventPluginRegistry: Cannot inject event plugins that do not exist in the plugin ordering, TB.


可能是配置项设置设置的原因。目前使用esbuild打包。

{
  // esbuild: {}, // 增加压缩速度,可能有bug.如遇bug无法解决。尝试使用terserOptions压缩
  terserOptions: {
    parse: {
      // parse options
    },
    compress: {
      // compress options
    },
    mangle: {
      // mangle options
      properties: {
        // mangle property options
      }
    },
    format: {
      // format options (can also use `output` for backwards compatibility)
    },
    sourceMap: {
      // source map options
    },
    ecma: 5, // specify one of: 5, 2015, 2016, etc.
    enclose: false, // or specify true, or "args:values"
    keep_classnames: false,
    keep_fnames: false,
    ie8: false,
    module: false,
    nameCache: null, // or specify a name cache object
    safari10: false,
    toplevel: false
  },
}

大体积包按需加载?

bizcharts 这个打包体积看起来很多,尝试按需加载

bizcharts parsed 体积从 757.3k -> 40.5K, 体积减小95%。

// 过去
// import { Axis, Chart, Geom, Tooltip, AxisProps } from 'bizcharts';
// 现在
import Chart from 'bizcharts/lib/components/Chart';
import Axis from 'bizcharts/lib/components/Axis';
import Geom from 'bizcharts/lib/components/Geom';
import Tooltip from 'bizcharts/lib/components/Tooltip';
import type AxisProps from 'bizcharts/typings'

替换

todo:

用dayjs 替换掉 moment ?

externals

设置哪些模块可以不被打包,通过

export default {
  // 配置 external
  externals: {
    'react': 'window.React',
    'react-dom': 'window.ReactDOM',
  },

  // 引入被 external 库的 scripts
  // 区分 development 和 production,使用不同的产物
  scripts: process.env.NODE_ENV === 'development' ? [
    'https://gw.alipayobjects.com/os/lib/react/16.13.1/umd/react.development.js',
    'https://gw.alipayobjects.com/os/lib/react-dom/16.13.1/umd/react-dom.development.js',
  ] : [
    'https://gw.alipayobjects.com/os/lib/react/16.13.1/umd/react.production.min.js',
    'https://gw.alipayobjects.com/os/lib/react-dom/16.13.1/umd/react-dom.production.min.js',
  ],
};

todo:

react、antd、biecharts 这些比较大的包,是否可以使用 externals的方式进行加载?

这个要根据业务具体、部署方式、用户的网络情况来判断。

启动优化

启动速度很慢,需要优化。

wait~