原文链接: http://moonrailgun.com/posts/74598ef5/
TRPG Engine
经过长久以来的迭代,项目已经显得非常臃肿了。数分钟的全量编译, 每次按下保存都会触发一次10s到1m不等的增量编译让我苦不堪言, 庞大的依赖使其每一次编译都会涉及很多文件和很多包,长时的编译时间大大降低了开发效率与迭代速度。
经过一段时间的考察,我选择了Snowpack
作为解决方案。与Webpack
不同的是,除了第一次的全量编译以外,Snowpack
的增量编译不会涉及到庞大的node_modules
文件夹, 准确来说只会编译变更文件本身。甚至于如果没有对依赖进行变更,下次的全量编译会直接动用之前编译的文件缓存,不需要花时间等待node_modules
的编译。
为什么会这么快?这是由于Snowpack
本身的实现与设计哲学有关的。相比Webpack
, Snowpack
利用了现代浏览器的本身的module
系统,跳过复杂的模型之间的组织编译过程而只关注于变更文件本身的编译,这样当然快了。
拿Snowpack
官方的一张图来说:
snowpack
的最小编译单位是文件,而webpack
的最小编译单位为chunk
, 而chunk
还需要额外的计算, 不论是编译部分还是编译后的组装部分。snowpack 的设计逻辑天生决定了她的速度。
优化前(使用webpack
):
全量编译:
增量编译:
全量请求用时:
优化后(使用snowpack
):
全量编译:
增量编译:
(看不到编译用时,但是体感在 1s 内. 而且该效果在电脑运行其他应用时更加显著)
全量请求用时:
使用 http1
使用 http2
以上测试是保证电脑在空闲时间,且保存与操作内容为同一文件
该用时已经是平时操作的最快时间,为此我的 MBR 重启了一次强制清空了 swap 空间, 实际表现会更加显著
因为文件依赖于浏览器的耗时,而浏览器需要串行请求依赖,因此耗时会更加长
但实际使用中使用 snowpack 会更加优秀。因为其相比 webpack 会大大节约电脑资源。在 webpack 编译时会占用大量的电脑资源,会影响到其他操作
TRPG Engine
算是非常经典的Webpack
应用了, 使用了各种 Loader 。光通用配置就有 250+行,各种优化配置,各种 alias 。等等长时间迭代积攒下来的配置,因此毫不意外的会遇到很多问题与坑。
以下是我遇到的问题与解决方案:
handlebars
文件,而 snowpack 不支持handlebars
文件作为入口snowpack
专用的入口文件。使用handlebars
主要解决的是 dll 的问题,snowpack
不需要处理这部分的优化因此直接跳过snowpack
加载文件策略与 node 不同。有同名文件和文件夹会优先使用文件夹的 index.js 作为路径解析。具体看现象可以参考这个讨论: https://github.com/snowpackjs/snowpack/discussions/1320node
的fs.stat
实现,在大小写敏感的系统下依旧会视为同名TRPG Engine
不但有 web 端,还有react-native
端,而react-native
是无法被正常解析的。我只想要处理 web 端的开发环境使用snowpack
优化开发体验exclude
配置手动过滤@snowpack/plugin-typescript
但是不支持 tspath 。css-loader
来实现的)scripts: {
'mount:font': 'mount src/web/assets/fonts --to /main/fonts',
},
snowpack
不支持这种写法。比如使用externals
实现的配置引入, 比如DefinePlugin实现的process.env
(在 snowpack 中必须使用import.meta.env
), 再比如require
的使用[
'snowpack-plugin-replace',
{
list: [
{
from: /process\.env/g,
to: 'import.meta.env',
},
{
from: `require("../../package.json").version`,
to: '"0.0.0"',
},
{
from: `const resBundle = require("i18next-resource-store-loader!./langs/index.js");`,
to: 'import resBundle from "./langs/zh-CN/translation.json"',
},
{
from: 'import Config from "config";',
to: `const Config = ${JSON.stringify({
sentry: require('config').get('sentry'),
})};`,
},
],
},
],
this
的警告installOptions: {
rollup: {
context: 'window',
},
},
.snowpack
并在 gitignore 中添加该文件夹
devOptions: {
out: '.snowpack',
},
@snowpack/plugin-typescript
内部包对全局变量的声明会出现重复声明的报错tsconfig
的"skipLibCheck": true
@babel/plugin-transform-runtime
提供的helpers
作为全局依赖regenerator
功能,手动安装regenerator-runtime
并在包前引入import 'regenerator-runtime/runtime';
require
作为引入方式, 而snowpack
无法正确处理require
snowpack
的具体实现决定的。snowpack-plugin-replace
将其替换为 css 文件导入作为临时解决方案, 见讨论: GithubSnowpack 虽然作为一个新兴的打包工具,目前尚不是非常完善, 功能也没有 webpack 这样丰富与齐全。但是它的新的打包设计对于有一定规模的前端应用还是非常优秀的。能极大提升开发效率。不失为一种好的解决方案。当然最后输出还是需要使用 webpack 对其进行一定的优化,毕竟原生的 module 支持目前浏览器的支持度还没有达到覆盖一个理想的地步https://caniuse.com/es6-module
最后这是我最后提交的pr
这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。
V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。
V2EX is a community of developers, designers and creative people.