DolphinScheduler 3.0版本之前使用的是webpack的打包开发部署方式。随着项目功能变多之后,启动项目的耗时将会越长。下面是2.0版本和3.0版本启动项目的耗时对比。可以很明显地看出,2.0版本的启动时间是16.943s,而3.0版本只用了515ms。在这里,启动速度的提升其实主要得益于Dolphinscheduler引入了Vite。Vite为什么能帮助DolphinScheduler提高项目启动的速度呢?接下来我们来说说Vite吧。 Vite是一种新型前端构建工具。它主要解决的是项目启动和开发过程中HMR(模块热更新)缓慢的问题。特别是项目达到一定量级的时候,开启一个项目需要很长时间(甚至需要几分钟),文件修改之后也需要数秒之后才能在浏览器中看出效果。 于此同时,它还提供开箱即用的配置,其插件 API 和 JavaScript API 也带来了高度的可扩展性,并且也有完整的TypeScript支持。 我们见证了webpack、rollup、parcel等工具的变迁,它们极大地改善了前端开发者的开发体验。 然而,随着SPA的兴起,我们开始构建越来越大型应用时,需要处理的JavaScript代码量也呈指数级增长。基于JavaScript开发的工具就会遇到性能瓶颈:启动速度和热更新速度很慢。如此循环往复,迟钝的反馈会极大地影响开发者的开发效率和编码体验。 而Vite旨在利用生态系统中的新进展解决上述问题:浏览器开始原生支持ES模块,越来越多JavaScript工具使用编译型语言编写(例如:esbuild采用go进行编写)。 下面针对上面说的启动缓慢和热更新速度慢,说明下Vite是如何做到提速的。 在启动开发服务的时候,打包器优先抓取构建的整个应用,然后将应用中的模块分为依赖和源码两类进行分别处理。 依赖,大多是在开发时候不会变动的纯JavaScript代码。其中一些大的依赖(例如ds中使用到的eslint和naive-ui)处理起来的成本会比较高,并且依赖通常会存在多种模块化格式(例如echarts采用的是CommonJS的方式,monaco-editor采用的是ESM的方式)。 所以呢,Vite在首次启动时,采用esbuild对依赖进行预构建处理。 在依赖处理方面,在该阶段会处理CommonJS和UMD兼容性,将CommonJS或UMD发布的依赖项转换为ESM,同时还会把许多内部模块的ESM依赖转换为单个模块,以此减少http的请求数量。 在缓存方面,Vite会将预构建的依赖缓存到node_modules/.Vite之中,解析之后的依赖请求也会在HTTP头中加入max-age=31536000,immutable来进行强缓存,用来提高开发时页面重载的性能。 源码,通常会包含一些非直接的JavaScript文件,例如tsx、ts或sass文件,需要转换,时常会被编辑。同时,并不是所有的源码都需要被同时加载。 Vite在浏览器请求源码时进行转换并以原生ESM方式按需提供源码。 一些打包器的开发服务器将构建内容存入内存,这样在文件修改时,它们只需要使模块图的一部分失活,但它也仍需要重新构建并重载页面。这样的代价很高,因为重载页面会清除应用的当前状态。 为了解决这个问题,打包器开始支持动态模块热替换(HMR),允许一个模块“热替换”自己,而不会影响页面的其余部分。这大大改进了开发体验。但是在实际开发中,即使采用了HMR模式,其热更新速度也会随着应用规模的增长而下降。 所以在Vite中,HMR是在原生ESM上执行的。同时利用了HTTP缓存:源码模块的请求会根据304 Not Modfied进行协商缓存,而依赖模块会进行强缓存,来进行提速。 Vite在DolphinScheduler中的应用
上面说明了Vite是什么,解决了什么问题,以及如何解决这些问题。接下来说说Vite在DolphinScheduler UI中的使用,以及DolphinScheduler UI中又用到了Vite的哪些功能。 DolphinScheduler UI全面支持了TypeScript。不过个别功能的TypeScript支持的颗粒度还不够,后续会持续不断的迭代优化。 这里需要注意的是,Vite仅执行.ts文件的转译工作,并不执行任何类型检查。所以在开发DolphinScheduler UI的时候,需要确认你的IDE是否支持类型检查,并且尽量使用仅含类型的导入和导出形式的语法(见示例1-1)用来避免潜在的“仅含类型的导入被不正确打包”的问题。 import type { Name } from './types' export type { N 在打包时,DolphinScheduler UI会在构建脚本前运行tsc --noEmit来进行类型检查。
TSX比传统的模板使用起来更具灵活性(得益于可以在TSX中书写JavaScript)。而且由于TS直接把TSX的推导做进了TS本身。所以在TS支持方面,TSX表现得更好。但是在性能方面传统的模板比TSX表现得更加优秀(用Vue的作者尤雨溪发在知乎上的一句话来说,‘模板在性能这块吊打 TSX’)。 由于DolphinScheduler UI目前并没有遇到性能瓶颈问题,所以DolphinScheduler UI采用了TSX来进行前端组件页面的搭建,并使用Vue官方提供的@Vitejs/plugin-vue-jsx插件进行转译。 DolphinScheduler UI就样式这块,主要是结合了CSS modules和预处理器(Sass)。在项目中表现出来就是单个模块或者页面中有个style.module.scss文件。 至于为什么使用CSS预处理语言,主要还是为了提高开发效率,节约成本。而CSS modules主要有两个原因:一是为了更好的隔离不同样式文件,防止样式污染;二是为了提高运行时性能。 除了上面主要在代码层面的功能之外。在插件方面,DolphinScheduler UI使用了Vite-ui-compression来对超过10240b的文件进行了gzip压缩;在开发服务器配置方面,使用server.proxy进行接口代理。 DolphinScheduler UI根据实际的项目情况运用了Vite中的上述功能。但是,Vite的功能还远远不止这些。 未来我们还可以使用插件对Vite进行扩展,主要是利用Rollup插件的强大生态系统。比如可以使用@Vitejs/plugin-legacy来支持传统浏览器。更多的插件,感兴趣的小伙伴可以查看这里(https://vite-rollup-plugins.patak.dev/)。