- vue3变更:用proxy重写了,性能提升。vite不需要打包直接运行。源码使用ts,使用Monorepr管理项目结构。
- 多个构建版本:prod表示压缩过的生产版本,不带则是没压缩的开发版本。ems是支持module的版本,runtime包含运行时版本,cjs是使用common.js版本。bundler需要搭配打包使用,使用脚手架是用的是vue.runtime.esm-bundler.js,只打包了需要的代码。
- 官网的rfc: https://github.com/vuejs/rfcs 可以了解需求讨论来源。vue3的CompositionAPI设计初衷,同一个功能会被拆分到data/methods/created等选项中,不利于理解和维护。用mixins的话容易命名冲突和数据来源不清晰。用CompositionAPI同一功能放在一个模块,并可以复用。
- vue3性能提升:
- 响应式系统升级,使用prxoy代替了defineProperty:(1)vue2在初始化的时候就遍历所有数据都做了响应式处理,如果子属性也是对象要递归遍历。proxy本身性能比defineProperty好,而且使用proxy代理能拦截setter/getter,只有在用到数据的时候才触发响应式处理,如果是深层属性,只有访问该属性时才会处理下一层属性。(2)能动态监听新增和删除,不需要调用vue.$set等方法。(3)vue2不能监听数组的索引和length变化,而vue3可以。
- 编译优化:vue2通过标记静态根节点,优化了diff过程;而vue3标记和提升所有的静态根节点,diff的时候只对比动态节点内容。主要有(1)可以不需要创建模板根节点,会自动创建fragments作为根节点(需升级vetur插件不然仍会报错);(2)静态节点提升:不包含绑定动态数据的静态文本节点,会被提升到初始化,以后render的时候不再创建;(3)Patch flag标记动态节点绑定数据:给动态绑定的节点打了标记数字,不同数字代表不同意义,记录哪些属性和数据是动态的,这样diff的时候只对比记录的属性和数据,其他静态的不需要对比,节省了时间;(4)缓存事件处理函数:绑定的函数可能是data里面,后续可能被重新赋值为新的函数,所以也被vue2认为是动态的,而vue3对函数做了一个缓存下次直接从缓存中获取,
_cache[1] || (_cache[1] = (..args) => (_ctx.handler(...args)))
,该缓存函数返回值是handler能确保获取到最新的handler但却不需要每次去对比变化。(5)按需引用:不需要的组件不会引入
https://vue-next-template-explorer.netlify.app可以对比勾选查看变化源码。 - 优化了打包体积:(1)vue3移除了一些不常用的api例如inline-template/filter等(filter可以通过计算属性和methods来实现),使得源码体积变小。(2)对tree-shaking的支持更好,tree-shaking依赖es6模块化,通过编译阶段的静态分析找到没有引入的模块,在打包的时候进行过滤从而减小体积。
vue3设计之初就考虑到了tree-shaking,内置组件和指令比如transition、keep-alive和v-model等都是按需引入的,vue3很多api也支持tree-shaking,默认核心模块才会内置。vue3从代码优化、编译优化、打包等提升性能。
- 除了IE之外的浏览器都支持ES module,通过
<script type="module" src="..."></script>
,默认是延迟加载的,相当于加了defer,在文档解析完成即DOM树生成后,触发DOMContentLoaded事件前执行。 - vite(法语的快)就是利用ES module。在开发模式下直接采取ES module这种方式加载代码,不需要经历过打包;而vue-cli需要打包。
- vite会开启测试服务器,拦截请求对浏览器不识别的模块进行处理,比如后缀是.vue时会在服务器上对.vue文件做编译,再把响应的contentType改成
application/javascript
告知浏览器是js脚本。对于模板文件(带参数的.vue?type=template文件)会用complie-SFC模块编译成render函数。 - 好处是快速冷启动、按需编译(需要加载的时候才会被编译)、模块热更新。
- Vite在生产环境下使用Rollup打包,Rollup基于浏览器原生支持的ES Module进行打包,不需要babel把import转成require,所以打包的体积会比webpack的更小。
- 可以基于模板创建项目,可以指定其他框架
npm init vite-app --template react
,也可以直接创建npm init vite-app projectName
。
- compositionAPI里的data必须是函数,createApp是创建Vue实例的方法,接受选项对象。setup有两个参数,第一个是props,不能接受解构,不是响应式的(需要用reactive返回proxy对象);第二个是context,具有attrs、emit、slots三个成员。
- setup的执行时机是在props创建完毕,组件实例被创建之前执行的,所以无法获取this实例。beforeCreate和created之间的代码都可以放在setup中,因为就是setup就在这之间执行,所以setup里也没有create对应钩子。其他钩子要加on,比如onBeforeMount。其中destroy变成了onUnMounted
- 若要让对象变成响应式,需要
const position = reactive({x: 0, y: 0})
,此时会返回代理对象。不能直接使用解构,若要解构需要用const {x, y} = toRefs(position)
,toRefs需要接受一个代理对象作为参数,原理是创建一个新的对象,遍历所有属性,把所有属性值转化成包含value的响应式对象。reactive是把一个对象转成响应式,属性更改是实时的;ref是把传入的内容(不一定是基本数据类型)转成响应式,后面的内容.value更改是实时的;而toRefs是把对象的值转成响应式对象。
// error
let obj2 = reactive({ fruit: 'apple', animal: 'monkey' })
obj2 = { fruit: 'pear', animal: 'snake' }
// recommend
let obj2 = ref({ fruit: 'apple', animal: 'monkey' })
obj2.value = { fruit: 'pear', animal: 'snake' }
- computed()需要传入一个函数
const active = computed(() => {
return
})
- watch有三个参数,第一个是data,第二个是变化后的回调函数,第三个是deep/immediate;返回值是一个函数用来取消监听。ref返回的值是不可变的,返回的值需要.vaue访问。watchEffect接受一个函数作为参数,监听函数内响应式数据的变化;初始会被执行一次,变化的时候回再执行;返回的函数可以用来取消监听。
- vite项目依赖只需要vite和@vue/compiler-sfc。vite支持两个命令,
vite serve
启动服务器,Vite的HMR会更快,因为只需要立即编译当前修改的文件即可;而webpack HMR会以这个文件为入口重新build一次,所涉及依赖也会被加载一遍。vite build
打包,使用webpack主要是旧浏览器不支持ESM导入,而且多个零散的导入会导致http请求过多(http2可以复用链接)。 - vite的好处:快速冷启动;模块热更新;按需编译;开箱即用(ts、less、jsx\web assembly不需要loader和配置直接内置)。
- vite的核心功能:启动静态web服务器;编译单文件组件(拦截浏览器不识别的模块,并处理);HMR。
- vite是用koa启动服务器的,node启动要加
#!/usr/bin/env node
#!/usr/bin/env node
const Koa = require('koa')
const send = require('koa-send')
const app = new Koa()
// 静态文件服务器
app.use(async (ctx, next) => {
// 三个参数,一是上下文,二是请求路径,三是根目录和index页面配置
await send(ctx, ctx.path, { root: process.cwd(), index: 'index.html' })
await next() // 返回的是中间件,要等中间件结束
})
app.listen(3000)
为啥reactive返回的是代理对象还要再toRefs一次?为啥用a实现todo,不会和vue-router冲突吗。 为啥监听hashchange