vite 能撼动 webpack 的地位吗?

9,599 阅读6分钟

关注vuejs作者的码农应该都知道,最近尤雨溪有了新宠vite,通过他在视频中分享vite的神情,可以感受到他对vite的钟爱。

vite 是什么呢?

vite 是一个由原生ESM驱动的非打包开发服务器,其作用类似webpack + webpack-dev-server,在github上d的第一次提交在2020年4月21日,但star数已经接近一万。

可以说,这是一个很新的工具,目前还没发布正式版,从近期的提交频率来看,应该很快就发布正式版了。

由于Vite是原生ESM的,因此他爸在视频说谈到,在上线部署时,也实现了类似rollup这个基于ES2015的打包功能,因此vite也是基于ES2015的JS打包工具,比Webpack和Browserify等使用CommonJS模块机制更高效,打包的文件体积更小,还支持相对路径。

为何推出vite?

vue3 beta版本出来了,万众期待尤雨溪快点发布vue3的正式版,他应该马不停蹄的开发vue3及其官方工具才对,为何又像开始vue3之前先整了半年多的 vue-cli 那样,在发布之前,要整了一下开发服务器呢?

在前手淘前端负责人winter采访尤雨溪视频中,他提到,起因是最近需要写大量的vue3相关的文档,使用之前基于 webpack 的vuepress写文档的框架,效率太低,于是他就自己单独搞了一个vite开发工具,且开源了基于vite的vitepress文档开发框架。

同时,基于vite的vue项目,在不使用webpack等打包工具的条件下,可以直接在浏览器运行请求的vue文件,因为面向现代浏览器,使用vite基于原生模块系统直接实现按需编译就可以了,而在webpack则需要将进行的编译放到内存中,打包所有文件。

vue3 的目标就是更快,在脚手架集成了 vite 以后,开发时就不用像webpack-dev-server那样,等很久才能渲染初页面了,而是启动后瞬间就有,再配上rollup 进行打包,基于vue3开发新项目,不仅性能更好,也会大大提升开发效率。

vite vs rollup vs webpack

前两年,大神有传言,库开发推荐用Rollup,应用开发推荐用Webpack,但是现在二者的功能差异小,Rollup也有热更新,Webpack也支持Tree shaking,而且都有强大的插件开发功能,他们更多的区别只是在写法上。

从 vite 的源码中可以看到,虽然Rollup也有热更新插件nollup,但是vite的单独实现了一套基于纯ESM的热更新,所以开发时单独用vite即可,而打包时则是单独使用rollup。

尤雨溪在视频中也提到,一个基于vite的全新脚手架create-vite-app也已经开源了,借助vue的强大生态,vite 必火,所以很有必要深入学习一下。

不过,在github上vitejs下面的项目只有四个,其中还有两个是面向react开发的,基于vite开发vue或react项目,还有很多坑需要填,对应的一些处理插件还没有rollup 和 webpack 丰富和完善。

另外,vite这个项目最后的打包还是用的rollup,或许某一天它会用自己开发自己。

vite的原理

因为我之前在外企工作过,习惯了直接看源码和英文文档,所以再我得知了vite后,马上去其源码仓库github.com/vitejs瞟了一眼,共有四个相关的项目:

  • vite
  • vite-plugin-react-pages
  • vite-plugin-react
  • create-vite-app

其中 vite 是核心库,而 create-vite-app 是开发的脚手架工具,取名很像create-react-app,通过集成vite-plugin-react-pages 和 vite-plugin-react,vite 也能开发react 项目。

由此看出,小右野心不小啊,想让 vite 和 webpack 一较高下的意图很明显。我们再看vite的package.json文件:

 "dependencies": {
    "@babel/parser": "^7.9.4",
    "@rollup/plugin-commonjs": "^14.0.0",
    "@rollup/plugin-json": "^4.0.3",
    "@rollup/plugin-node-resolve": "^8.4.0",
    "@types/koa": "^2.11.3",
    "@types/lru-cache": "^5.1.0",
    "@vue/compiler-dom": "^3.0.0-rc.5",
    "@vue/compiler-sfc": "^3.0.0-rc.5",
    "brotli-size": "^4.0.0",
    "chalk": "^4.0.0",
    "chokidar": "^3.3.1",
    "clean-css": "^4.2.3",
    "debug": "^4.1.1",
    "dotenv": "^8.2.0",
    "dotenv-expand": "^5.1.0",
    "es-module-lexer": "^0.3.18",
    "esbuild": "^0.6.10",
    "etag": "^1.8.1",
    "execa": "^4.0.1",
    "fs-extra": "^9.0.0",
    "hash-sum": "^2.0.0",
    "isbuiltin": "^1.0.0",
    "koa": "^2.11.0",
    "koa-conditional-get": "^2.0.0",
    "koa-etag": "^3.0.0",
    "koa-proxies": "^0.11.0",
    "koa-send": "^5.0.0",
    "koa-static": "^5.0.0",
    "lru-cache": "^5.1.1",
    "magic-string": "^0.25.7",
    "merge-source-map": "^1.1.0",
    "mime-types": "^2.1.27",
    "minimist": "^1.2.5",
    "open": "^7.0.3",
    "ora": "^4.0.4",
    "postcss": "^7.0.28",
    "postcss-discard-comments": "^4.0.2",
    "postcss-import": "^12.0.1",
    "postcss-load-config": "^2.1.0",
    "resolve": "^1.17.0",
    "rollup": "^2.20.0",
    "rollup-plugin-dynamic-import-variables": "^1.0.1",
    "rollup-plugin-terser": "^5.3.0",
    "rollup-plugin-vue": "^6.0.0-beta.10",
    "rollup-plugin-web-worker-loader": "^1.3.0",
    "rollup-pluginutils": "^2.8.2",
    "selfsigned": "^1.10.7",
    "slash": "^3.0.0",
    "vue": "^3.0.0-rc.5",
    "ws": "^7.2.3"
  },

可以看到其核心库主要有:

"vue": "^3.0.0-rc.5",
"rollup": "^2.20.0",
"koa": "^2.11.0",
"koa-proxies": "^0.11.0",
"koa-static": "^5.0.0",

进入项目看其他源码,可以知道,开发时,vite使用Koa构建的服务端,在createServer中主要通过中间件注册相关功能,提供一个web server 去代理 浏览器通过 http 请求的模块。

vue模块安装在node_modules中,浏览器ES Module是无法直接获取到项目下node_modules目录中的文件,其过程如下:

  • 通过 koa 中间件获取请求 body
  • 使用 es-module-lexer 解析资源 ast
  • 获取 import 的内容后,判断资源是否是绝对路径,绝对视为 npm 模块
  • 返回处理后的路径给浏览器,例如:"vue" => "/@modules/vue"

基于vite的项目中,在需要某个模块时动态引入,而不是提前打包,自然更快,不同于webpack等,不管某个模块是否用到,都会把所有的模块都提前打包进bundle中,随着项目越来越大,打包文件也越来越大,自然越来越慢。

前面提到,vite自己实现了一套热更新,其原理为:

  • 在 server 端编译资源,然后推送新资源给 client ;
  • client 收到资源信息,执行框架 rerender 逻辑;
  • server 端 基于 watcher 监听文件改动,根据类型判断是js还是vue reload;
  • 同时 client 端,Websocket监听了一些更新的消息类型,然后分别处理:
  • 通过解析器拿到当前文件,并与缓存里的上一次解析结果进行比较,若有变化则render;

到此为止,我们发现,虽然package.json文件中引入了若干rollup相关的库,在开发时,都没有用到,rollup 只有在打包发布vite这个库时才用到。

通过create-vite-app/template-vue/package.json文件中的scripts 模块,我们看到了打包的命令:

  "scripts": {
    "dev": "vite",
    "build": "vite build"
  },

我们进一步看 vite build 执行的相关源码,发现打包时的各种处理确实都是vite自己实现的,一点也没用到rollup。

小结

随着vue3 正式版即将发布,vite 正式版也会同步跟进,相信很快我们就能基于 vue3 + vite 开发和上线正式的项目了,不过即使正式版还没发布,过两天我也会基于一个webpack4+vue3 的项目,调整为vite+vue 打包上线部署一下,对比一下两者的性能。

回到正题,虽然vite看似很不错,但是webapck5也已经来了,就像yarn和npm一样,在npm感受到了yarn的挑战后,也加快了对新特性的支持,以至npm和yarn 最新版本的功能越来越像,webapck和rollup也一定会在新版本中借鉴vite的一些特性。

所以,之后基于可能出现vite,webpack和rollup三足鼎立的发展趋势。

如果觉得不错,就点个赞,并转发一下哈~,