原文链接: 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
问题11表述有误。准确来说应该是snowpack目前无法很好支持行内require。顶部require通过rollup的commonjs插件解决
1
Immortal 2020-10-21 09:58:49 +08:00
说实话看到下面这么多遇到的问题 还是保持观望
不过涨姿势了 之前只知道 esbuild 才知道还有 Snowpack |
2
love 2020-10-21 10:09:07 +08:00 via Android
上次我也一顿猛操换成这个,碰到一堆问题,后来又退回去了。印象中还有 commonjs 格式导出的模块也是不能用的。感觉还是要等个一年各个模块兼容性上去之后再换比较合适。
|
3
felixin 2020-10-21 10:20:03 +08:00 via Android
这个就没有 typescript 类型检查了吧?
|
4
codermagefox 2020-10-21 10:50:11 +08:00
Webpack 换 Parcel 那一波已经冲过了.结果很失望.
现在碰到所有新东西都先观望观望了. |
5
moonrailgun OP |
6
moonrailgun OP @codermagefox parcel 本质没有太大的变化,反而少了 webpack 的大量配置带来的优势与劣势。
我换 snowpack 目的是为了提升开发体验。我现在按一次保存按钮电脑十几秒不能动 ide 也没有提示。算是比较有目的性的。 生产环境还是会使用 webpack 进行代码的优化与编排。目前尚没有到可以完全替换的地步 |
7
codermagefox 2020-10-21 11:05:30 +08:00
@moonrailgun #6 嗯.我一向认同新工具的优势,但是大部分的成熟程度都没有到支撑大型项目的程度.我个人博客用 Gatsby,但是公司项目我连 TS 都没上.不想挖坑给自己填,所以还是算了
|
8
moonrailgun OP @love 几个月前我也试过。也是一堆问题,改了改源码也没法解决差太多了,就没继续搞。最近重新弄了一下发现还是有点盼头的。虽然遇到一堆问题但是基本上都解决或者找到替代方案。
做大动作前一定要分分支,这样万一搞不成直接扔了就好了 |
9
moonrailgun OP @codermagefox 公司项目还是谨慎一点比较好。毕竟不同人不断迭代下肯定会出现很多奇奇怪怪的 magic,如果是个人项目能够控制全局,我觉得还是可以考虑实际根据情况尝试一下的。
|
10
nnnToTnnn 2020-10-21 13:39:32 +08:00
和 webpack5 比较怎么样?
|
11
zy445566 2020-10-21 13:45:41 +08:00
我也是用从 webpack 换成了 rollup,速度也是快了很多,https://github.com/zy445566/before-server/commit/4d61a3b0c8464eb8d08605178fdaebc703db7599
|
12
hewelzei 2020-10-21 16:20:32 +08:00
有大量库及其依赖库使用 CommonJS 导入导出,这块是最难解决的。就算有一直活跃的库修改为 ESModule, 保不齐上级深层的某个依赖万年不修,依旧用的 CommonJS,那 Snowpack 就没法用了。
|
13
yl14786922106 2020-10-21 16:29:30 +08:00
vue3 的话可以直接 vite 了 不过踩了这么多坑 可以收藏 以后 自己玩的时候 可以来看看
|
14
moonrailgun OP @hewelzei
snowpack 内部通过 rollup 来实现打包。通过 commonjs-plugin 实现对 commonjs 格式的兼容 具体见: https://github.com/snowpackjs/snowpack/blob/d90a1fb8a080bfe32e7283d87063381cd97f48bb/esinstall/src/index.ts#L383-L387 不过实际使用过程中如果依赖使用了行内 require 会无法正常执行。我的实际 case 中遇到了两处。翻阅代码发现已经被修复了因此升级就解决了 |
15
hewelzei 2020-10-22 10:35:06 +08:00
@moonrailgun 我遇到一处行内 require 的问题,查看依赖代码,发现不予解决,那就无解了。有这类问题的肯定不止一个包,,而且这问题看似简单,一旦出现,你的开发环境就起不来了。
https://github.com/antvis/g/pull/598 |
16
moonrailgun OP @hewelzei 这个不是行内 require 的问题,而是在 esmodule 中使用 commonjs 的语法引入了一个 json 内容的问题。
按照标准来说这种行为属于混用,统一使用 esmodule 或者统一使用 commonjs 都不会出现这个问题。 我觉得不支持标准行为属于正常操作。本质上来说内部的 rollup 没有处理这种情况,snowpack 自身也不会去处理,也就 webpack 这种大而全的会考虑方方面面兼容一切 case——这也是 webpack 显得臃肿的原因 |