从 Webpack 到 Snowpack, 编译速度提升十倍以上——TRPG Engine迁移小记
动机
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
7.jpg使用http2
8.jpg
以上测试是保证电脑在空闲时间,且保存与操作内容为同一文件
该用时已经是平时操作的最快时间,为此我的MBR重启了一次强制清空了swap空间, 实际表现会更加显著
因为文件依赖于浏览器的耗时,而浏览器需要串行请求依赖,因此耗时会更加长
但实际使用中使用snowpack会更加优秀。因为其相比webpack会大大节约电脑资源。在webpack编译时会占用大量的电脑资源,会影响到其他操作
遇到的坑与解决方案
TRPG Engine
算是非常经典的Webpack
应用了, 使用了各种Loader。光通用配置就有250+行,各种优化配置,各种 alias。等等长时间迭代积攒下来的配置,因此毫不意外的会遇到很多问题与坑。
以下是我遇到的问题与解决方案:
- 问题1:
- 入口文件使用的是HtmlwebpackPlugin编译的
handlebars
文件,而snowpack不支持handlebars
文件作为入口 - 解决方案:重写一个
snowpack
专用的入口文件。使用handlebars
主要解决的是dll的问题,snowpack
不需要处理这部分的优化因此直接跳过
- 入口文件使用的是HtmlwebpackPlugin编译的
- 问题2:
snowpack
加载文件策略与node不同。有同名文件和文件夹会优先使用文件夹的index.js作为路径解析。具体看现象可以参考这个讨论: https://github.com/snowpackjs/snowpack/discussions/1320- 解决方案:改名字,让文件夹与文件名不会出现重复。包括同名但是大小写不同的问题,因为底层是
node
的fs.stat
实现,在大小写敏感的系统下依旧会视为同名
- 问题3:
TRPG Engine
不但有web端,还有react-native
端,而react-native
是无法被正常解析的。我只想要处理web端的开发环境使用snowpack
优化开发体验- 解决方案:
exclude
配置手动过滤
- 问题4:
- tspath不支持,虽然有了
@snowpack/plugin-typescript
但是不支持tspath。 - 解决方案: 手动写了一个自动解析的逻辑将其变成对应的alias加到配置上
- tspath不支持,虽然有了
- 问题5:
- 在css中引入了字体文件,但是无法正常加载。因为snowpack无法正确识别url指定的资源并将其打包(webpack是使用
css-loader
来实现的) - 解决方案:
scripts: {
'mount:font': 'mount src/web/assets/fonts --to /main/fonts',
},
- 在css中引入了字体文件,但是无法正常加载。因为snowpack无法正确识别url指定的资源并将其打包(webpack是使用
- 问题6:
- 对于一些特殊的写法我不想影响webpack的实现但是
snowpack
不支持这种写法。比如使用externals
实现的配置引入, 比如DefinePlugin实现的process.env
(在snowpack中必须使用import.meta.env
), 再比如require
的使用 - 解决方案: 我实现了一个snowpack-plugin-replace插件用于将这些东西全部替换成我想要的代码。具体使用如下:
[
'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'),
})};`,
},
],
},
],
- 对于一些特殊的写法我不想影响webpack的实现但是
- 问题7:
- rollup抛出无法解析
this
的警告 - 解决方案: 使用context指向window来移除警告
installOptions: {
rollup: {
context: 'window',
},
},
- rollup抛出无法解析
- 问题8:
- snowpack打包目标路径与原有的build文件夹冲突
- 解决方案: 修改输出目录为
.snowpack
并在gitignore中添加该文件夹devOptions: {
out: '.snowpack',
},
- 问题9:
- 使用
@snowpack/plugin-typescript
内部包对全局变量的声明会出现重复声明的报错 - 解决方案:
tsconfig
的"skipLibCheck": true
- 使用
- 问题10:
- 现有的依赖需要
@babel/plugin-transform-runtime
提供的helpers
作为全局依赖 - 解决方案: 经检查是用到了
regenerator
功能,手动安装regenerator-runtime
并在包前引入import 'regenerator-runtime/runtime';
- 现有的依赖需要
- 问题11:
- 部分依赖在其中部分代码使用了
行内require
作为引入方式, 而snowpack
无法正确处理行内require
- 解决方案: 检查后发现都已经修改。升级依赖到最新版即可
- PS: 顶部require snowpack使用rollup的commonjs插件来解决,具体看代码:https://github.com/snowpackjs/snowpack/blob/d90a1fb8a080bfe32e7283d87063381cd97f48bb/esinstall/src/index.ts#L383-L387
- 部分依赖在其中部分代码使用了
- 问题12:
- 在使用less的import逻辑无法正常运行,这是由于
snowpack
的具体实现决定的。 暂时无法解决,使用使用snowpack-plugin-replace
将其替换为css文件导入作为临时解决方案, 见讨论: Github@snowpack/plugin-run-script
插件将其手动编译后放在公共文件中。可以参考这个commit
- 在使用less的import逻辑无法正常运行,这是由于
总结
Snowpack虽然作为一个新兴的打包工具,目前尚不是非常完善, 功能也没有webpack这样丰富与齐全。但是它的新的打包设计对于有一定规模的前端应用还是非常优秀的。能极大提升开发效率。不失为一种好的解决方案。当然最后输出还是需要使用webpack对其进行一定的优化,毕竟原生的module支持目前浏览器的支持度还没有达到覆盖一个理想的地步https://caniuse.com/es6-module
最后这是我最后提交的pr
从 Webpack 到 Snowpack, 编译速度提升十倍以上——TRPG Engine迁移小记的更多相关文章
- 如何将 iOS 工程打包速度提升十倍以上
如何将 iOS 工程打包速度提升十倍以上 过慢的编译速度有非常明显的副作用.一方面,程序员在等待打包的过程中可能会分心,比如刷刷朋友圈,看条新闻等等.这种认知上下文的切换会带来很多隐形的时间浪费. ...
- Java动态编译优化——提升编译速度(N倍)
一.前言 最近一直在研究Java8 的动态编译, 并且也被ZipFileIndex$Entry 内存泄漏所困扰,在无意中,看到一个第三方插件的动态编译.并且编译速度是原来的2-3倍.原本打算直接用这个 ...
- 使用Apache Spark 对 mysql 调优 查询速度提升10倍以上
在这篇文章中我们将讨论如何利用 Apache Spark 来提升 MySQL 的查询性能. 介绍 在我的前一篇文章Apache Spark with MySQL 中介绍了如何利用 Apache Spa ...
- 阿里云maven仓库地址,速度提升100倍
参照:https://www.cnblogs.com/xxt19970908/p/6685777.html maven仓库用过的人都知道,国内有多么的悲催.还好有比较好用的镜像可以使用,尽快记录下来. ...
- 多伦多大学&NVIDIA最新成果:图像标注速度提升10倍!
图像标注速度提升10倍! 这是多伦多大学与英伟达联合公布的一项最新研究:Curve-GCN的应用结果. Curve-GCN是一种高效交互式图像标注方法,其性能优于Polygon-RNN++.在自动模式 ...
- numba,让python速度提升百倍
python由于它动态解释性语言的特性,跑起代码来相比java.c++要慢很多,尤其在做科学计算的时候,十亿百亿级别的运算,让python的这种劣势更加凸显. 办法永远比困难多,numba就是解决py ...
- iOS进阶--将项目的编译速度提高5倍
前言 作为开发团队的负责人,最近因为在快速迭代开发新功能,项目规模急速增长,单个端业务代码约23万行,私有库约6万行,第三方库代码约15万行,单个客户端的代码行数约60万.现在打包一次耗时需要11~1 ...
- Elasticsearch聚合优化 | 聚合速度提升5倍
https://blog.csdn.net/laoyang360/article/details/79253294 1.聚合为什么慢?大多数时候对单个字段的聚合查询还是非常快的, 但是当需要同时聚合多 ...
- 使用ccache大幅度加速gcc编译速度至少1倍以上(不需要修改任何编译选项)
因为我们整个项目都是使用c++开发的,生成的so足有50M,原来编译一遍要三五分钟,一个针对oracle,一个针对mysql,整个轮回下来这部分就要10来分钟,加上代码上传.翻译,一轮配管打包下来二三 ...
随机推荐
- centos8平台安装gitosis服务
一,git服务器端:准备gitosis需要的各依赖软件 1,确认openssh是否存在?如不存在,以下列命令进行安装 [root@yjweb ~]# yum install openssh opens ...
- 通透,23 个问题 TCP 疑难杂症全解析
每个时代,都不会亏待会学习的人. 在进入今天主题之前我先抛几个问题,这篇文章一共提出 23 个问题. TCP 握手一定是三次?TCP 挥手一定是四次? 为什么要有快速重传,超时重传不够用?为什么要有 ...
- sql server 2008 r2 直接下载地址,可用迅雷下载
sqlserver 2008 r2 直接下载地址,可用迅雷下载 下载sqlserver 2008 r2 ,微软用了一个下载器,经过从下载器上,将他的地址全部用键盘敲了下来.最终的简体中文版地址如下: ...
- Jmeter入门(4)- 注意事项
一.中文乱码问题的解决方法 1. 将HTTP请求的内容编码改成UTF-8 2. 修改配置文件jmeter.properties 将jmeter安装目录的bin目录下的jmeter.properties ...
- 从0实现python批量爬取p站插画
一.本文编写缘由 很久没有写过爬虫,已经忘得差不多了.以爬取p站图片为着手点,进行爬虫复习与实践. 欢迎学习Python的小伙伴可以加我扣群86七06七945,大家一起学习讨论 二.获取网页源码 爬取 ...
- CentOS 环境变量编辑、保存、立即生效的方法
方法一: 该方法只能修改临时配置文件,当每次系统重启后,配置文件将失效 假如我的安装路径如下:/home/oracle/app/oracle/product/11.2.0/dbhome_1/bin 那 ...
- LinkBlockedQueue的c++实现
c++链表实现的阻塞队列 最近从java源码里发现了阻塞队列的实现,觉得非常有趣. 首先,介绍下什么是阻塞队列.阻塞队列代表着一个队列可以线程安全的往该队列中写数据和从该队列中读数据.也就是说,我们可 ...
- Spring笔记(5) - 声明式事务@EnableTransactionManagement注解源码分析
一.背景 前面详解了实现Spring事务的两种方式的不同实现:编程式事务和声明式事务,对于配置都使用到了xml配置,今天介绍Spring事务的注解开发,例如下面例子: 配置类:注册数据源.JDBC模板 ...
- 印度最大在线食品杂货公司Grofers的数据湖建设之路
1. 起源 作为印度最大的在线杂货公司的数据工程师,我们面临的主要挑战之一是让数据在整个组织中的更易用.但当评估这一目标时,我们意识到数据管道频繁出现错误已经导致业务团队对数据失去信心,结果导致他们永 ...
- 【应用服务 App Service】App Service证书导入,使用Key Vault中的证书
问题描述 正常情况下,如果需要为应用服务安装SSL证书,可以在证书准备好的情况,通过门户上传即可,详细步骤可以参考微软官方文档(在 Azure 应用服务中添加 TLS/SSL 证书:https://d ...