vlambda博客
学习文章列表

打造基于Webpack的构建流程与性能改进

作者 | Tobias Uhlig
译者 | 王强
策划 | 李俊辰

本文最初发布于 Medium 网站,经原作者授权由 InfoQ 中文站翻译并分享。

大家可能经常会有这样的经历:随着一个项目一天天成长,你也跟着添加了一个个的构建任务,并没有做过什么细致的优化。

然后在某一天你看了下自己的 package.json 脚本,它已经变成了类似这个样子:

打造基于Webpack的构建流程与性能改进

使用 neo.mjs 框架就会是这样的结果。package.json 文件太大的话,调用“npmpublish”时就容易出问题,导致仓库超时;对于刚开始使用这个框架的开发新人来说,文件内容变成这个样子也很容易把人绕晕。

所以是时候来一次大规模的重构了。重构后新的 package.json 会变成这个样子:

打造基于Webpack的构建流程与性能改进

当然,之前的任务还是一个不能少,而且接下来任务的数量很可能会进一步增长。

这篇文章讲的是如何调整 neo.mjs 框架:https://github.com/neomjs/neo

这个代码库是基于 MIT 许可分发的,因此就算你不直接使用它,也可以把它涉及的概念应用到自己的项目中。它应该能帮的上你的忙。

1. buildAll 程序
新的入口点是 buildAll 程序。其实我在 package.json 中添加了它两次,因为你既可以通过命令行选项使用它,也可以通过可视查询界面使用它(具体取决于你喜欢哪种模式,完全个性化的选择)。
> node ./buildScripts/buildAll.js — help
打造基于Webpack的构建流程与性能改进
> npm run build-all-questions1

打造基于Webpack的构建流程与性能改进

程序源代码在下面的链接查看:

https://github.com/neomjs/neo/blob/dev/buildScripts/buildAll.js

出于显而易见的原因,这个程序将 env 和 noquestions 选项传递给子程序。如果你只是克隆了存储库,则很可能只想调用:
> npm run build-all

并且所有子程序运行时都不会弹出问题。build-all 只是用来组合其他程序的切入点,因此它自己不会进行任何构建。

2. buildThreads 程序

接下来我们来看一下 buildThreads 程序:

https://github.com/neomjs/neo/blob/dev/buildScripts/webpack/buildThreads.js

打造基于Webpack的构建流程与性能改进

它与 buildAll 遵循相同的设计模式(其他程序也是如此)。

默认情况下,neo.mjs 使用 4 个线程:

  1. main(默认顶级进程)

  2. app(webworker)

  3. data(webworker)

  4. vdom(webworker)

与其他框架相比,这里的概念是非常独特的,因为这个框架的大部分内容以及使用它构建的应用都运行在 app 线程中。

每个 app 针对 main、data 和 vdom 都使用相同的构建,因此你很少需要构建这些线程。

main 线程非常模块化 =>你可以为框架配置自由选择插件。每个插件都会延迟加载(动态导入)。

将每个线程的基于 Webpack 的入口点隔离开来是很有意义的,因为在不同领域之间共享块是不可能的。

有关 main 线程插件的更多内容,请参考我以前的文章:

https://codeburst.io/using-js-libraries-inside-a-multithreading-environment-835cd8cbc30b

重点在于,每个 app 只会在其 index.html 文件中包含主块,并且 main 会根据需要导入要使用的 app。

由于 app 线程是 app worker 和你的应用代码的组合,因此不包含在 buildThreads 程序中。

3. buildMyApps 程序

https://github.com/neomjs/neo/blob/dev/buildScripts/webpack/buildMyApps.js

打造基于Webpack的构建流程与性能改进

buildMyApps 为 apps 使用动态程序选项 =>它将显示存储库中的所有可用 apps(你可以使用 create-app 脚本创建新的 app)。

Covid Dashboard 应用就是一个很好的例子,它有大约 2500 行代码(不包括注释)。

打造基于Webpack的构建流程与性能改进

在我的机器上,为开发环境构建它(未压缩,使用源映射)需要 0.98s。

打造基于Webpack的构建流程与性能改进

打造基于Webpack的构建流程与性能改进

生产环境的构建(压缩,没有源映射)结果差不多:1.05s。

像 neo.mjs RealWorld 这样的小型应用要快一些:

打造基于Webpack的构建流程与性能改进

4. buildThemes 程序

接下来我们看一下 buildThemes:

https://github.com/neomjs/neo/blob/dev/buildScripts/webpack/buildThemes.js

打造基于Webpack的构建流程与性能改进

有黑暗和明亮两个主题可以选择。

我选择使用 SCSS 来实现它们,因为包装器允许我们生成(可选)是否包含 CSS 变量的输出(选项名称为 CSS4)。

构建过程使用的是 PostCSS,因此你无需使用前缀为不同的浏览器编写不同的规则。

这不是固定的途径,你也可以添加通过 JS 生成 CSS 的 PR(不过是否能与 PostCSS 一起使用就说不准了)。

使用 CSS var 的好处是,你可以轻松地为一个应用加入多个主题,并将这些主题应用在不同的部分。所有主题共享一个相同的 CSS 源,并为每种模式提供一个 CSS var 文件(假设你确实要使用 CSS var)。这样以来,就算你用了多个主题,对整体 CSS 文件大小的影响也会很小。

打造基于Webpack的构建流程与性能改进

5. buildDocsExamples 程序

https://github.com/neomjs/neo/blob/dev/buildScripts/webpack/buildDocsExamples.js

打造基于Webpack的构建流程与性能改进

从屏幕快照中可以看出,docs 应用也是 neo.mjs 应用。由于我们希望能够根据需要(延迟)加载示例应用,因此为 docs 应用和示例应用构建的 app 线程组合在了一起。

尽管 main 线程已经支持基于 Webpack 的块拆分,但是对于 app 而言这还是做不到的。具体原因相当复杂,但这个问题已经在处理计划上了。

6. jsdoc-x 解析

neo.mjs 使用 jsdoc-x,可用来直接创建框架与你自己应用的文档输出。

打造基于Webpack的构建流程与性能改进

在我的机器上总构建时间高达 140s+,这实在太不合理了。

我深入研究了 jsdoc-x 源代码,并创建了一个小的覆盖。现在对于 neo.mjs 上下文,构建时间减少到了只有 5s:

https://github.com/onury/jsdoc-x/issues/14

包括 npm install 在内,几乎所有内容的总构建时间减少到了 35.5s。

打造基于Webpack的构建流程与性能改进

由于你很少需要 buildAll,因此这样的结果已经很不错了。

7. Webpack 调整

当我想将这个新版本部署到 Github 页面时(在线示例):

https://neomjs.github.io/pages/

Webpack 为拆分块创建了完全不同的输出。8 个 main 线程插件中有 6 个是正常的,而另外两个在路径内添加了一个 vendors 前缀,结果搞坏了输出。这肯定是因为将框架包含在了一个 node_modules 文件夹中。我用了一个小技巧修复了这个问题,更多细节在此:

https://github.com/webpack/webpack/issues/10949

8. 完全没有 JS 构建的开发模式

谈了这么多关于新的构建程序的内容后,我觉得接下来有必要讲一下关于 neo.mjs 的最重要部分:

node 和 Webpack 应该是用来以 dist 模式构建和打包应用的工具。

开发应用时,如果能直接在浏览器内部运行基于 ES8 的真实代码(完全不需要构建)就太方便了。

你不需要源映射,不需要热模块替换,只需使用实际代码即可。

这确实节省了我很多时间。

公平地说,对于 neo.mjs 上下文而言,这只能用在 Chrome80+ 中,因为 Firefox 和 Safari 尚无法在 worker 内部支持 JS 模块。

但是,如果你创建自己的应用时只锁定在 main 线程上,那就可以利用新版 Chrome 浏览器的支持实现这个功能了。

9. neo.mjs 的下一步是什么?

如上所述,针对 app 领域的基于 Webpack 的块拆分仍处于发展阶段。对触摸事件的支持(类似于 Hammerjs)是一个很大的主题,我真正期待的是对共享 worker 的 JS 模块支持。

目前来说,我们可以创建基于 neo.mjs 的,可以运行在多个浏览器窗口中的 UI=>多显示支持。

延伸阅读

https://medium.com/swlh/bundling-your-webpack-based-build-processes-performance-improvements-dd7d0ffdd788