vite是尤大在更新vue3以后,再次开发的一个新的构建工具。那什么构建工具让尤大在过年都在疯狂更新呢?它到底有什么魔力呢?javascript
在vite开发出来以后,就连webpack团队的核心成员都在感叹css
Vite(法语意思是 “快”,发音为 /vit/,相似 veet)是一种全新的前端构建工具。你能够把它理解为一个开箱即用的开发服务器 + 打包工具的组合,可是更轻更快。Vite 利用浏览器原生的 ES 模块支持和用编译到原生的语言开发的工具(如 esbuild)来提供一个快速且现代的开发体验。html
注意:vite是一个全新的前端构建工具(重点:构建工具),不少小伙伴总在问vite和vue-cli的区别。vue-cli是一个脚手架工具,用于自动生成vue.js+webpack的项目模板。方便咱们快速开发。而vite是一个构建工具,用于咱们对项目进行构建(相似于webpack的功能)。而在将来不排除vue-cli里面会集成vite前端
构建工具:用来让咱们再也不作机械重复的事情,解放咱们的双手的。
在早期开发过程当中。有不少令咱们不爽的地方vue
.......java
因而 前端构建工具应运而生。构建工具能够帮助咱们作如下工做node
...react
在了解vite以前咱们先了解一下其余的构建工具,这样咱们才能更好的对比vite的强大之处。
前端的构建工具备不少。好比 Grunt Gulp FIS3 Webpack Rollup Parcel snowpack vite 接下来我会挑几个构建工具进行简单的介绍webpack
Gulp.js 是一个自动化构建工具,开发者可使用它在项目开发过程当中自动执行常见任务。Gulp.js 是基于 Node.js 构建的,利用 Node.js 流的威力,你能够快速构建项目git
var gulp = require('gulp');
var jshint = require('gulp-jshint');
var concat = require('gulp-concat');
var rename = require('gulp-rename');
var uglify = require('gulp-uglify');
// Lint JS
gulp.task('lint', function() {
return gulp.src('src/*.js')
.pipe(jshint())
.pipe(jshint.reporter('default'));
});
// Concat & Minify JS
gulp.task('minify', function(){
return gulp.src('src/*.js')
.pipe(concat('all.js'))
.pipe(gulp.dest('dist'))
.pipe(rename('all.min.js'))
.pipe(uglify())
.pipe(gulp.dest('dist'));
});
// Watch Our Files
gulp.task('watch', function() {
gulp.watch('src/*.js', ['lint', 'minify']);
});
// Default
gulp.task('default', ['lint', 'minify', 'watch']);
复制代码
gulp的执行是从上倒下的执行一个个任务。而后文件内容经过管道。进行传递。若是你想了解更多gulp的知识,能够去gulp官网
webpack 是一个用于现代 JavaScript 应用程序的 静态模块打包工具。当 webpack 处理应用程序时,它会在内部构建一个 依赖图(dependency graph),此依赖图对应映射到项目所需的每一个模块,并生成一个或多个 bundle。
接下来咱们看看Webpack的工做原理图 从上图咱们能够看出webpack打包分为一下步骤
查找入口文件
从webpack的配置文件中查找entry的配置,从而找到入口文件
分析依赖关系
接到入口文件以后,从入口文件出发,分析入口文件中依赖了哪些文件,而且这些依赖的文件中还可能依赖别的文件,就这么递归的找下去。
模块函数
找到依赖中的全部文件,把这些文件转化成模块的函数,为了方便后面webpack进行调用
打包
打包完毕的文件能够产出到配置文件的output指定路径里,生成一个bundle
启动服务
node建立本地服务器并启动静态页面
这大概是咱们webpack在开发环境打包的主要流程。
熟悉了咱们常见的打包工具的工做流。接下来咱们看看vite是怎么工做的。 看看vite为何被称为下一代开发和构建工具。
在目前的工做中,咱们主要利用webpack+vue(webpack+react)进行项目开发。然而,当咱们构建愈来愈大型的应用的时候,打包工具须要处理的javascript代码量也呈指数级增加。在大型项目中包含几百甚至几千个模块的状况也愈来愈多。咱们开始遇到性能瓶颈,使用javascript的工具一般须要很长的时间,才能启动开发服务器
这是我工做中的一个真实项目, 项目不大,可是启动服务器的时间花了30s。这做为一个讲究效率的程序员确定是没法忍受的
当项目愈来愈大,项目的hrm热更新速度愈来愈慢。有时候甚至改动一个字段,页面几十秒以后才会进行热更新。
其实这和webpack打包的原理有关系,咱们前面其实已经大概了解webpack的主要工做流,这里就不在详细讲解
......
vite的三大特色
固然vite也有必定的问题,
vite的生态还不够完善。
在生产模式下仍然须要打包。尽管原生 ESM 如今获得了普遍支持,但因为嵌套导入会致使额外的网络往返,在生产环境中发布未打包的 ESM 仍然效率低下(即便使用 HTTP/2)。为了在生产环境中得到最佳的加载性能,最好仍是将代码进行 tree-shaking、懒加载和 chunk 分割(以得到更好的缓存)。
经过上面的了解,咱们已经知道了利用vite的不少优点,那么接下来咱们看看vite是怎么实现的。
vite的成功得益于现代浏览器对于基于ECMAScript 标准原生模块系统(ES Modules)实现。 目前主流浏览器(IE11除外)都已经支持。他容许咱们在浏览器使用export、import 的方式导入和导出模块,在 script 标签里设置 type="module"
<script type="module">
import { createApp } from './main.js‘ createApp() </script> 复制代码
浏览器会识别添加type="module"的 <script>
元素,浏览器会把这段内联 script 或者外链 script 认为是 ECMAScript 模块。而后浏览器会被这里面的import引用发起一个http请求,请求获取文件中的内容。 所以咱们对于第三方的模块,能够不用打包合并,而是经过import 这种方式去发起http 请求,获取代码。这也是vite的主要实现思路。 若是你对ES Modules 不够了解。能够去看看ES Modules的规范
首先看一张图
劫持浏览器
劫持浏览器的这些请求,并在后端进行相应的处理,将项目中使用的文件经过简单的分解与整合,而后再返回给浏览器。从上面的分析可知: vite主要作了如下事情
vite整个过程当中没有对文件进行打包编译,至于其余加载的工做就交给了浏览器,因此其运行速度比原始的webpack开发编译速度快出许多。
传统打包器是将项目打包以后的资源存入电脑的内存之中,这样他们只须要在文件更改的时候,将对应的模块进行失活,可是它仍然须要从新构建并重载页面。 因此像webpack这类的打包工具支持了动态模块热重载(HRM),容许一个模块替换本身,而对其他页面没有影响。可是在实践中。咱们发现HRM的速度会随着项目的增大而下降(缘由在 目前打包工具的困境
这一节已经分析过了)
而在vite中HMR 是在原生 ESM 上执行的。当编辑一个文件时,Vite 只须要精确地使已编辑的模块与其最近的 HMR 边界之间的链失效(大多数时候只须要模块自己),使 HMR 更新始终快速,不管应用的大小。
为何说vite才是真正的按需加载呢?难道webpack不是真正的按需加载吗?
若是你想知道,那么你能够看看去看看webpack的原理,这里我简单介绍一下 webpack其实在开始构建打包的时候,仍是对全部的文件进行一次打包构建,只是在webpack遇到 import( * ) 这种语法的时候,会另外生成一个chunk; 只有在合适的时候去加载import中的内容
从上面的分析能够知道。无论咱们这段import的代码什么时候执行,咱们对须要对它进行必定的打包
可是vite不同,只有在你真正的须要加载的时候,浏览器才会发送import请求,去请求文件中的内容,因此才说vite才是真正的按需加载
咱们已经知道了vite的大概工做原理,那么咱们接下来实现一个最基础的vite
webpack编译后的文件
vite编译后的文件
main.js
第一步: 从上图咱们能够看出vite首先也是找到一个入口文件,而后修改一些依赖模块的路径,好比把vue替换成了/@modules/vue.js. 把./App.vue替换成了绝对路径
第二步: 首先去寻找第一个组件App.vue。将App.vue中的js复制给一个常量,而后在App.vue中的html转化为一个render函数,挂载到js的那个常量身上。
首先咱们初始化一个项目
npm init vite-app <project-name>
cd <project-name>
npm i
npm run dev
复制代码
这样咱们就能成功启动一个vite+vue的项目。 接下来咱们不用vite,本身来实现一个咱们本身的vite
新建yj-vite.js文件 从上图咱们对vite分析能够得知,实现vite主要有如下几个步骤
咱们这里主要使用koa来实现
而后执行
node yj-vite.js
能够看到,这样一个静态资源服务器就已经搭建成功了
若是咱们请求的是首页,那么咱们拿到绝对地址,进行拼接,读取文件,并返回,若是不是,咱们就直接读取文件。并返回
这时候咱们看到请求其实已经成功,可是控制台报了一个错误
缘由是浏览器不能识别 import ..form 'vue' 要把vue变成一个绝对路径地址
因此咱们须要对上一步的内容进行改造,当以js结尾的文件中包含import 加载第三方模块的时候,咱们首先将
```
import vue from 'vue'
替换
import vue from '/@modules/vue'
```
复制代码
这样咱们就能够看到main.js中已经成功替换了
那么接下来看看咱们怎么处理 /@module/vue
这样咱们就能正确处理第三方模块了。而且第三方模块也已经成功加载了。
但此时浏览器中会有一个错误 这是由于在vue的源码中,是有process.env这个环境变量,因此在index.html中咱们能够加下如下内容,进行简单处理一下。
<script>
window.process = {
env: {
NODE_ENV: 'dev'
}
}
</script>
复制代码
这样咱们就可以成功执行。
可是在咱们main.js中通常都不会这样写
createApp({
render: () => h('div','3333333')
}).mount('#app')
复制代码
而是经过单文件组件的形式去编写代码
import App from './App.vue'
createApp(App).mount('#app')
复制代码
那么咱们怎么去识别.vue中文件的内容,而且成功获取呢
这里简单说一下接下来的大概思路
export default
替换成 const __script =
__script
下 这样咱们就成功手写了一个vite
其实官方的vite远远比这个复杂。在http请求以前,其实vite作了一个预打包,预打包的目的是为了减小http请求,由于可能一个模块依赖了成百上千个模块,过多的请求增大了浏览器的负担。 若是你想了解vite怎么实现预打包,你能够看看esbuild
固然vite怎么实现按需加载, 热更新 ... 等等功能,你能够关注我,等待后续更新
vite 下一代前端开发与构建工具(二) 主要内容: vite更多功能的实现,以及如何将vue2项目迁移到vite webpack hrm的实现原理 主要内容: 主要讲解webpack中hrm的底层实现 vue2 vue2的原理 主要内容: MVVM的实现 虚拟dom diff算法等等