关于javascript:🌟项目实战🌟优化项目构建时间

背景

前几天早晨上班的时候, 路过隔壁项目组, 听他们在聊我的项目构建的事:

当初线上打包工夫太长了, 修个 bug 1 分钟, 公布一下半小时, 贼好受。

他们我的项目比拟宏大, 线上构建工夫特地长, 根本都在15分钟以上

和他们简略聊了会, 回去瞅了一下本人我的项目的构建工夫:

其实也挺长的, 于是抽空优化了一下, 成果还是比拟显著的:

在注释局部,我将分享的内容次要是:

  • 一些晋升 webpack 打包性能的配置
  • 优化大型项目构建工夫的一些思考

心愿对大家有所启发。

注释

咱们我的项目不是很大, 是一个中型的国际化我的项目, 一百来个页面。

之前本地构建工夫挺长的,首次启动要三次分钟, 前面我配置了 Vite, 本地启动工夫升高到了 20s 左右,感兴趣的能够移步我这篇文章:

Webpack to Vite, 为开发提速!

看了一下,线上构建工夫五六分钟,不痛不痒,然而应该也有优化空间,于是筹备优化一下。

1. 发现问题

既然要优化构建工夫, 第一步当然是先发现问题, 找出比拟耗时的阶段,再加以优化。

这里我用到了SMP 插件。

SMP 插件用法非常简单, 这里也简略提一下:

// webpack.config.js
const SpeedMeasurePlugin = require('speed-measure-webpack-plugin');
const smp = new SpeedMeasurePlugin();

module.exports = smp.wrap({
  // ...
});

利用 SMP 插件得出各个阶段的打包耗时:

发现两个比拟显著的问题:

  1. IgnorePlugin 耗时靠近 20 秒。
  2. less-loader 局部执行了2次,节约了一分多钟。
  3. ts-loader 耗时一分半, 也挺长的。

2. 解决问题

1. IgnorePlugin

查看了一下配置, 发现配置里的 IgnorePlugin 并没有达到预期的成果, 删掉。

2. less-loader

查看配置后发现, 在解决less的局部,的确多解决了一遍。

less 文件的解决,能够间接看官网文档,文档地址:

https://webpack.docschina.org…

我的配置:

{
  test: /\.less$/,
  use: [
    'style-loader',
    'css-loader',
    {
      loader: 'less-loader',
      options: {
        javascriptEnabled: true,
        sourceMap: true,
        modifyVars: {
          // inject our own global vars
          // https://github.com/ant-design/ant-design/issues/16464#issuecomment-491656849
          hack: `true;@import '${require.resolve('./src/vars.less')}';`,
          ...themeVariables,
        },
        limit: 10000,
        name: '[name].[hash:7].[ext]',
        outputPath: 'styles/',
      },
    },
  ],
},
{
  test: /\.css$/,
  use: ['style-loader', 'css-loader'],
},

3. ts-loader

对于ts-loader局部的优化, 能够参考:

https://webpack.js.org/guides…

文档上也有比拟清晰的形容:

文档倡议, 咱们开启transpileOnly选项,敞开类型查看。

如果要类型查看, 能够应用 ForkTsCheckerWebpackPlugin,这个插件会在另外一个过程中做相干的查看。

这个插件,咱们在优化构建时内存溢出的问题上, 也做了摸索, 感兴趣的能够移步我这篇文章:

我的项目构建内存溢出了?看看 Node 内存限度

当初咱们也开启这个选项。

开启之后, 本地构建的时候, 本地报了个正告:

这个谬误, 非常的眼生, 是之前咱们讲过的 import type 的问题,

你不晓得的 「 import type 」

修复一下:

问题解决。

从新构建, 失去如下后果:

优化之后之后, 咱们发现:

  • IgnorePlugin、HtmlWebpackPlugin 工夫大幅缩短。
  • less-loader 等复原了失常,只执行了一次。
  • ts-loader 工夫大幅缩短,由1分30秒缩短为40秒。

本地成果显著,须要去线上构建验证。

3. 确认无效

在线上执行之后, 失去如下后果:

而后去查看了一下页面,也都是失常的。

完满!

回头看,不难发现,其实也没改多少货色, 就播种了不错的成果。

针对中小型我的项目来说, 改改配置往往就能达到咱们的要求, 然而如果是面对大型项目呢?

比方那种数十个模块, 几百个页面的我的项目。

回到结尾那个问题: 修个 bug 1 分钟, 公布一下半小时

简略的批改配置, 都无奈把工夫降下来, 这时候该怎么办呢?

优化大型项目构建工夫的一些思考

拆分子利用

假如咱们有一个我的项目,大模块就有将近30个:

每个大模块外面又有几十个页面,这种零碎构建工夫会比拟久, 须要做优化。

而且到了我的项目前期,问题会越来越显著, 比方:

  • 代码越来越臃肿
  • 业务模块自身无关联
  • 构建速度越来越慢
  • 无奈独立部署

面对这种状况,一种可行的做法是:拆分子利用

拆分之后的架构:

每个子项目都有独自的入口, 是能够独立部署的我的项目。

子项目打成独自umd包:

在主我的项目启动的时候, 再去加载这些子项目:

加载实现之后, 须要解决路由以及store, 示例代码:

// base
export const bootstrap = () => {
  // ...
  ReactDOM.render((
    <Provider store={store}>
      <Router history={history}>
        <App defaultInitialData={_initialData} />
      </Router>
    </Provider>
  ), document.getElementById('root'));
  return Promise.resolve();
};

// main
const loadSubApp = (htmlEntry: string) => {
  return importHTML(`${htmlEntry}?${Date.now()}`)
    .then((res: any) => res.execScripts())
    .then((exportedValues: any) => {
      console.log(`importHTML: ${htmlEntry} loaded, exports:`, exportedValues);
      const { store, router } = exportedValues || {} as any;
      router && addCustomRouter(router);
      store && addCustomStore(store);
    })
    .catch(e => {
      console.error('importHTML: ${htmlEntry} load error:', e);
    });
};

const load = () => {
  if (__ENV__ !== 'dev') {
    const paths: string[] = [];
    subAppConfig.subApps.forEach(item => {
      if (item.project === localStorage.getItem('ops_project')) {
        paths.push(...item.paths);
      }
    });
    Promise.all(paths.map(path => loadSubApp(path)))
      .catch(e => console.log(e))
      .finally(setAllLoaded);
  } else {
    setAllLoaded();
  }
};

const init = () => {
  console.log('init: Start to bootstrap the main APP');
  addCustomStore(rootStore);
  bootstrap().then(() => {
    load();
  });
};

init();

代码共享

  • common
    • component
    • utils
    • typings
    • ..
  • externals
    • react全家桶
    • moment
    • antd
    • ..

款式隔离

给款式增加以子项目为名的 namespace :

开发调试

以 ops 我的项目为例。

让开发调试 ops-common 包像本地文件一样不便:

  1. 让我的项目来编译 common 包

  1. wepback alias

  1. TS alias

独立部署

在同一个project上为每个子项目申请独立module

拆分子利用的优缺点

长处:

  • 每个子利用都能够独立公布, 子模块和主模块解偶
  • 子项目是能够独自编译的,主我的项目只须要做引入即可, 以此缩小主模块的构建工夫

毛病:

  • 额定的复杂性和保护老本

论断

一般来说,对于中小型我的项目,做好打包配置的优化, 可能解决一部分问题。

大型项目的构建工夫优化, 能够思考拆分子利用的模式。

只不过这种模式须要思考一些保护的问题,比方如何保护版本 tag、如何疾速回滚等。

这些须要联合你们我的项目的理论状况再做决定。

明天的内容就这么多,心愿对大家有所启发。

最初

祝大家五一高兴~~

如果感觉文章内容有帮忙, 能够关注下我哦, 把握最新动静。

也能够加我微信 「 scaukk 」, 一起探讨。

评论

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

这个站点使用 Akismet 来减少垃圾评论。了解你的评论数据如何被处理