作者:妹红大大
转发链接:https://mp.weixin.qq.com/s/D_PRIMAD6i225Pn-a_lzPA
前言
最容易搭建 vue3 的方式就是使用作者的 vite《ntent="mp" href="https://www.toutiao.com/i6832604684847415811/?group_id=6832604684847415811" rel="noopener noreferrer" target="_blank">一个由 Vue 作者尤雨溪开发的 web 开发工具—vite》
也可以通过 yarn 安装
$ yarn create vite-app <project-name> $ cd <project-name> $ yarn $ yarn dev
异常1:本菜翻阅了 vite 的 issue,然后 google + baidu 一无所获, 最后发现是因为本菜 node 版本为 13.5.0导致的(版本过高),
最后的解决方式是:本菜通过 nvm 将 node 版本切换到 12.12.0,至于 nvm 没使用过的童鞋们可以去尝试下哦。特别好用
vite 原理解析
那么就可以通过通过拦截路由 / 和 .js 结尾的请求。然后通过 node 去加载对应的 .js 文件
const fs = require('fs') const path = require('path') const Koa = require('koa') const app = new Koa() app.use(async ctx=>{ const {request:{url} } = ctx // 首页 if(url=='/'){n ctx.type="text/html" ctx.body = fs.readFileSync('./index.html','utf-8') }else if(url.endsWith('.js')){ // js文件 const p = path.resolve(__dirname,url.slice(1)) ctx.type = 'application/javascript' const content = fs.readFileSync(p,'utf-8') ctx.body = content } }) app.listen(3001, ()=>{ console.log('听我口令,3001端口,起~~') })
但是遇到第三方库以上代码就会找不到 .js 文件的位置了,此时 vite 会用 es-module-lexer 把文件解析成 ast,拿到 import 的地址。
如果是第三方库就去 node_modules 中查找,vite 中通过在第三方库中添加前缀 /@modules/,然后发现了 /@modules/ 后走 第三方库逻辑
if(url.startsWith('/@modules/')){ // 这是一个node_module里的东西 const prefix = path.resolve(__dirname,'node_modules',url.replace('/@modules/','')) const module = require(prefix+'/package.json').module const p = path.resolve(prefix,module) const ret = fs.readFileSync(p,'utf-8') ctx.type = 'application/javascript' ctx.body = rewriteimport(ret) }
首先 xx.vue 返回的格式大概是这样的
const __script = { setup() { ... }}import {render as __render} from "/src/App.vue?type=template&t=1592389791757"__script.render = __renderexport default __script
解析 .css 就更加简单了。通过 document.createElement('style')然后再注入就好了
reactive
作为 vue2 的使用者最想知道的肯定是 vue3 的数据劫持和双向绑定了。在 vue3中,双向绑定和可选项,如果需要使用双向绑定的需要通过 reactive方法进万数据劫持。
现在开始写一个简单的 vue
<template> <div> <div>{{ count }}</div> <button @click="increment">count++</button> </div> </template> <script> import { reactive } from 'vue' export default { setup() { let count = reactive({ num: 0 }) const increment = () => count.num++ return { count, increment } } } </script>
现在开始解读 reactive 源码。
上面的 __v_isReadonly 其实是一个 typescript 的枚举值
export const enum ReactiveFlags { skip = '__v_skip', isReactive = '__v_isReactive', isReadonly = '__v_isReadonly', raw = '__v_raw', reactive = '__v_reactive', readonly = '__v_readonly'}
然后进入 createReactiveObject 在 649 行,意思就是:「创建响应式对象」
function createReactiveObject(target, isReadonly, baseHandlers, collectionHandlers) { // 略... // 如果target已经代理了, 返回target if (target.__v_raw && !(isReadonly && target.__v_isReactive)) { return target; } // target already has corresponding Proxy if (hasOwn(target, isReadonly ? "__v_readonly" : "__v_reactive" )) { return isReadonly ? target.__v_readonly : target.__v_reactive; } if (!canObserve(target)) { return target; } // 重点... // collectionHandlers:对引用类型的劫持, // baseHandlers: 对进行基本类型的劫持 const observed = new Proxy(target, collectionTypes.has(target.constructor) ? collectionHandlers : baseHandlers); def(target, isReadonly ? "__v_readonly" : "__v_reactive" , observed); return observed;}
实现劫持的主要方法是通过 Proxy 方法,(Proxy 使用可以看看阮老师的博客),顺藤摸瓜找到 mutableHandlers 定义的地方。在 338 行
const mutableHandlers = { get, set, deleteProperty, has, ownKeys};// 229行const get = createGetter();// 251 行function createGetter(isReadonly = false, shallow = false) { return function get(target, key, receiver) { // 一些 __v_isReactive、__v_isReadonly、__v_raw的处理 // 略... // 数组操作 const targetIsArray = isArray(target); if (targetIsArray && hasOwn(arrayInstrumentations, key)) { return Reflect.get(arrayInstrumentations, key, receiver); } // 非数组 const res = Reflect.get(target, key, receiver); // 其他 调用 track 返回 res 的情况 // 略... // 如果可写,那么会调用 track !isReadonly && track(target, "get" , key); // 如果是对象呢。那么递归 return isObject(res) ? isReadonly ? // need to lazy access readonly and reactive here to avoid // circular dependency readonly(res) : reactive(res) : res; };}
get 指向了方法 createGetter, 「创建 get 劫持」
那么数组的 arrayInstrumentations 是什么呢?我们来到源码的 第 234 行。
const arrayInstrumentations = {};['includes', 'indexOf', 'lastIndexOf'].forEach(key => { arrayInstrumentations[key] = function (...args) { // const arr = toRaw(this); for (let i = 0, l = this.length; i < l; i++) { track(arr, "get" , i + ''); } // we run the method using the original args first (which may be reactive) // 我们首先 以原始args 运行该方法(可能是反应性的) const res = arr[key](...args); if (res === -1 || res === false) { // if that didn't work, run it again using raw values. // 如果那不起作用,则使用原始值再次运行它。 return arr[key](...args.map(toRaw)); } else { return res; } };});
arrayInstrumentations 中还是调用了 track 方法,那么 track 方法就更加神秘了。来看看它的源码吧?源码在 126 行
function track(target, type, key) { if (!shouldTrack || activeEffect === undefined) { return; } let depsMap = targetMap.get(target); if (!depsMap) { targetMap.set(target, (depsMap = new Map())); } let dep = depsMap.get(key); if (!dep) { depsMap.set(key, (dep = new Set())); } if (!dep.has(activeEffect)) { dep.add(activeEffect); activeEffect.deps.push(dep); if ( activeEffect.options.onTrack) { activeEffect.options.onTrack({ effect: activeEffect, target, type, key }); } }}
在不考虑 activeEffect 的情况下。track 所做的事情就是
- 创建包含自身的 map
- 将 activeEffect 赛道 map 中
- 触发 onTrack
createReactiveEffect 是在 effect 中被调用的
先开始讲述 trigget 相关的代码(核心哦)
function trigger(target, type, key, extraInfo) { const depsMap = targetMap.get(target); // 略... const effects = new Set(); const computedRunners = new Set(); if (type === "clear" ) { // collection being cleared, trigger all effects for target depsMap.forEach(dep => { addRunners(effects, computedRunners, dep); }); } // 略... const run = (effect) => { scheduleRun(effect, target, type, key, extraInfo); }; computedRunners.forEach(run); effects.forEach(run); }
在源码 3900 行中,被 mutableHandlers、readonlyHandlers 等函数中被使用。
所以,这里就成环了。
- 其实 effect 才是响应式的核心,在 mountComponent、doWatch、reactive 中被调用。
- 在 reactive 中 通过 Proxy 实现劫持。
- 在 Proxy 劫持set时调用 trigger。
- 然后在 targger 中清除收集并触发目标的所有 effects
- 最终触发 patch 游戏结束。
推荐Vue学习资料文章:
《ntent="mp" href="https://www.toutiao.com/i6844798155439997448/?group_id=6844798155439997448" rel="noopener noreferrer" target="_blank">细聊Single-Spa + Vue Cli 微前端落地指南「实践」》
《ntent="mp" href="https://www.toutiao.com/i6844774085323391499/?group_id=6844774085323391499" rel="noopener noreferrer" target="_blank">通俗易懂的Vue响应式原理以及依赖收集》
《ntent="mp" href="https://www.toutiao.com/i6844689305885999628/?group_id=6844689305885999628" rel="noopener noreferrer" target="_blank">Vue.js轮播库热门精选》
《ntent="mp" href="https://www.toutiao.com/i6844084369510892040/?group_id=6844084369510892040" rel="noopener noreferrer" target="_blank">Vue+CSS3 实现图片滑块效果》
《ntent="mp" href="https://www.toutiao.com/i6844039600957030923/?group_id=6844039600957030923" rel="noopener noreferrer" target="_blank">教你Vue3 Compiler 优化细节,如何手写高性能渲染函数(下)》
《ntent="mp" href="https://www.toutiao.com/i6843577013324743179/?group_id=6843577013324743179" rel="noopener noreferrer" target="_blank">一用惊人的Vue实践技巧「值得推荐」》
《ntent="mp" href="https://www.toutiao.com/i6843280010338370051/?group_id=6843280010338370051" rel="noopener noreferrer" target="_blank">Vue常见的面试知识点汇总(下)「附答案」》
《ntent="mp" href="https://www.toutiao.com/i6842199418926531083/?group_id=6842199418926531083" rel="noopener noreferrer" target="_blank">为什么我不再用Vue,改用React?》
《ntent="mp" href="https://www.toutiao.com/i6841453662301061639/?group_id=6841453662301061639" rel="noopener noreferrer" target="_blank">20个免费的设计资源 UI套件背景图标CSS框架》
《ntent="mp" href="https://www.toutiao.com/i6841074942197367299/?group_id=6841074942197367299" rel="noopener noreferrer" target="_blank">前端骨架屏都是如何生成的》
《ntent="mp" href="https://www.toutiao.com/i6840670396283355660/?group_id=6840670396283355660" rel="noopener noreferrer" target="_blank">用vue简单写一个音乐播放组件「附源码」》
《ntent="mp" href="https://www.toutiao.com/i6839667518764745228/?group_id=6839667518764745228" rel="noopener noreferrer" target="_blank">「干货」学会这些Vue小技巧,可以早点下班和女神约会》
《ntent="mp" href="https://www.toutiao.com/i6838524135186891278/?group_id=6838524135186891278" rel="noopener noreferrer" target="_blank">细品30张脑图带你从零开始学Vue》
《ntent="mp" href="https://www.toutiao.com/i6839659749596725771/?group_id=6839659749596725771" rel="noopener noreferrer" target="_blank">手把手教你Electron + Vue实战教程(五)》
《ntent="mp" href="https://www.toutiao.com/i6836162531908649483/?group_id=6836162531908649483" rel="noopener noreferrer" target="_blank">手把手教你Electron + Vue实战教程(三)》
《ntent="mp" href="https://www.toutiao.com/i6835960304526950916/?group_id=6835960304526950916" rel="noopener noreferrer" target="_blank">手把手教你Electron + Vue实战教程(一)》
《ntent="mp" href="https://www.toutiao.com/i6833564314566132227/?group_id=6833564314566132227" rel="noopener noreferrer" target="_blank">如何写出优秀后台管理系统?11个经典模版拿去不谢「干货」》
《ntent="mp" href="https://www.toutiao.com/i6833366419619447308/?group_id=6833366419619447308" rel="noopener noreferrer" target="_blank">基于 Vue 和高德地图实现地图组件「实践」》
《ntent="mp" href="https://www.toutiao.com/i6832575653900976644/?group_id=6832575653900976644" rel="noopener noreferrer" target="_blank">是什么让我爱上了Vue.js》
《ntent="mp" href="https://www.toutiao.com/i6832164205668336141/?group_id=6832164205668336141" rel="noopener noreferrer" target="_blank">1.1万字深入细品Vue3.0源码响应式系统笔记「下」》
《ntent="mp" href="https://www.toutiao.com/i6832110835305808387/?group_id=6832110835305808387" rel="noopener noreferrer" target="_blank">尤大大细说Vue3 的诞生之路「译」》
《ntent="mp" href="https://www.toutiao.com/i6831803495805354503/?group_id=6831803495805354503" rel="noopener noreferrer" target="_blank">大厂Code Review总结Vue开发规范经验「值得学习」》
《ntent="mp" href="https://www.toutiao.com/i6831324768256393739/?group_id=6831324768256393739" rel="noopener noreferrer" target="_blank">带你五步学会Vue SSR》
《ntent="mp" href="https://www.toutiao.com/i6829927955137823246/?group_id=6829927955137823246" rel="noopener noreferrer" target="_blank">Vue 3.x 如何有惊无险地快速入门「进阶篇」》
《ntent="mp" href="https://www.toutiao.com/i6829479963222082060/?group_id=6829479963222082060" rel="noopener noreferrer" target="_blank">带你了解 vue-next(Vue 3.0)之 炉火纯青「实践」》
《ntent="mp" href="https://www.toutiao.com/i6829118872772149772/?group_id=6829118872772149772" rel="noopener noreferrer" target="_blank">「干货」Vue+Element前端导入导出Excel》
《ntent="mp" href="https://www.toutiao.com/i6828799889397252612/?group_id=6828799889397252612" rel="noopener noreferrer" target="_blank">细品pdf.js实践解决含水印、电子签章问题「Vue篇」》
《ntent="mp" href="https://www.toutiao.com/i6827805121653506573/?group_id=6827805121653506573" rel="noopener noreferrer" target="_blank">Vue仿蘑菇街商城项目(vue+koa+mongodb)》
《ntent="mp" href="https://www.toutiao.com/i6827742275716514316/?group_id=6827742275716514316" rel="noopener noreferrer" target="_blank">「实践」Vue项目中标配编辑器插件Vue-Quill-Editor》
《ntent="mp" href="https://www.toutiao.com/i6827647187745243651/?group_id=6827647187745243651" rel="noopener noreferrer" target="_blank">消息队列助你成为高薪 Node.js 工程师》
《ntent="mp" href="https://www.toutiao.com/i6828036352286654983/?group_id=6828036352286654983" rel="noopener noreferrer" target="_blank">「干货」Deno TCP Echo Server 是怎么运行的?》
《ntent="mp" href="https://www.toutiao.com/i6827632377976586763/?group_id=6827632377976586763" rel="noopener noreferrer" target="_blank">「干货」通俗易懂的Deno 入门教程》
《ntent="mp" href="https://www.toutiao.com/i6826720047453438478/?group_id=6826720047453438478" rel="noopener noreferrer" target="_blank">「实践」基于Apify+node+react/vue搭建一个有点意思的爬虫平台》
《ntent="mp" href="https://www.toutiao.com/i6826152826318619144/?group_id=6826152826318619144" rel="noopener noreferrer" target="_blank">前端网红框架的插件机制全梳理(axios、koa、redux、vuex)》
《ntent="mp" href="https://www.toutiao.com/i6826138907583709709/?group_id=6826138907583709709" rel="noopener noreferrer" target="_blank">深入学习Vue的data、computed、watch来实现最精简响应式系统》
《ntent="mp" href="https://www.toutiao.com/i6825828475878769166/?group_id=6825828475878769166" rel="noopener noreferrer" target="_blank">10个实例小练习,快速入门熟练 Vue3 核心新特性(二)》
《ntent="mp" href="https://www.toutiao.com/i6825384959620940296/?group_id=6825384959620940296" rel="noopener noreferrer" target="_blank">2020前端就业Vue框架篇「实践」》
《ntent="mp" href="https://www.toutiao.com/i6824798616025039364/?group_id=6824798616025039364" rel="noopener noreferrer" target="_blank">Vue项目部署及性能优化指导篇「实践」》
《ntent="mp" href="https://www.toutiao.com/i6824323319924261383/?group_id=6824323319924261383" rel="noopener noreferrer" target="_blank">尤大大细品VuePress搭建技术网站与个人博客「实践」》
《ntent="mp" href="https://www.toutiao.com/i6823619809029128716/?group_id=6823619809029128716" rel="noopener noreferrer" target="_blank">是什么导致尤大大选择放弃Webpack?【vite 原理解析】》
《ntent="mp" href="https://www.toutiao.com/i6823361775694512653/?group_id=6823361775694512653" rel="noopener noreferrer" target="_blank">带你了解 vue-next(Vue 3.0)之 初入茅庐【实践】》
《ntent="mp" href="https://www.toutiao.com/i6822256635658895884/?group_id=6822256635658895884" rel="noopener noreferrer" target="_blank">一篇文章教你并列比较React.js和Vue.js的语法【实践】》
《ntent="mp" href="https://www.toutiao.com/i6820686462694982158/?group_id=6820686462694982158" rel="noopener noreferrer" target="_blank">深入浅出通过vue-cli3构建一个SSR应用程序【实践】》
《ntent="mp" href="https://www.toutiao.com/i6818344300082889224/?group_id=6818344300082889224" rel="noopener noreferrer" target="_blank">聊聊昨晚尤雨溪现场针对Vue3.0 Beta版本新特性知识点汇总》
《ntent="mp" href="https://www.toutiao.com/i6810954020031562252/?group_id=6810954020031562252" rel="noopener noreferrer" target="_blank">Vue真是太好了 壹万多字的Vue知识点 超详细!》
《ntent="mp" href="https://www.toutiao.com/i6815452062881415683/?group_id=6815452062881415683" rel="noopener noreferrer" target="_blank">深入浅出Vue3 跟着尤雨溪学 Typescript 之 Ref 【实践】》
《ntent="mp" href="https://www.toutiao.com/i6817773725736239628/?group_id=6817773725736239628" rel="noopener noreferrer" target="_blank">Vue 3.0 Beta 和React 开发者分别杠上了》
《ntent="mp" href="https://www.toutiao.com/i6805432820110983688/?group_id=6805432820110983688" rel="noopener noreferrer" target="_blank">Vue3 尝鲜》
《ntent="mp" href="https://www.toutiao.com/i6808329189901468174/?group_id=6808329189901468174" rel="noopener noreferrer" target="_blank">Vue 开源项目 TOP45》
《ntent="mp" href="https://www.toutiao.com/i6806264785508762124/?group_id=6806264785508762124" rel="noopener noreferrer" target="_blank">尤雨溪:Vue 3.0的设计原则》
《ntent="mp" href="https://www.toutiao.com/i6805425165132890635/?group_id=6805425165132890635" rel="noopener noreferrer" target="_blank">实现全栈收银系统(Node+Vue)(上)》
《ntent="mp" href="https://www.toutiao.com/i6809939243440275981/?group_id=6809939243440275981" rel="noopener noreferrer" target="_blank">vue引入原生高德地图》
《ntent="mp" href="https://www.toutiao.com/i6805067432382693902/?group_id=6805067432382693902" rel="noopener noreferrer" target="_blank">多年vue项目实战经验汇总》
《ntent="mp" href="https://www.toutiao.com/i6805729533463888388/?group_id=6805729533463888388" rel="noopener noreferrer" target="_blank">基于 Vue 的两层吸顶踩坑总结》
《ntent="mp" href="https://www.toutiao.com/i6805083839644303876/?group_id=6805083839644303876" rel="noopener noreferrer" target="_blank">Vue 开发必须知道的 36 个技巧【近1W字】》
《ntent="mp" href="https://www.toutiao.com/i6810630570251387406/?group_id=6810630570251387406" rel="noopener noreferrer" target="_blank">深入理解vue中的slot与slot-scope》
《ntent="mp" href="https://www.toutiao.com/i6806116083720782348/?group_id=6806116083720782348" rel="noopener noreferrer" target="_blank">使用vue+node搭建前端异常监控系统》
《ntent="mp" href="https://www.toutiao.com/i6808322447729754632/?group_id=6808322447729754632" rel="noopener noreferrer" target="_blank">基于Vue实现拖拽升级(九宫格拖拽)》
《ntent="mp" href="https://www.toutiao.com/i6805725101749699076/?group_id=6805725101749699076" rel="noopener noreferrer" target="_blank">手摸手,带你用vue撸后台 系列三(实战篇)》
《ntent="mp" href="https://www.toutiao.com/i6811330273926447620/?group_id=6811330273926447620" rel="noopener noreferrer" target="_blank">Vue组件间通信几种方式,你用哪种?【实践】》
《ntent="mp" href="https://www.toutiao.com/i6812984956667560455/?group_id=6812984956667560455" rel="noopener noreferrer" target="_blank">10个Vue开发技巧助力成为更好的工程师》
《ntent="mp" href="https://www.toutiao.com/i6805795810026979847/?group_id=6805795810026979847" rel="noopener noreferrer" target="_blank">1W字长文+多图,带你了解vue的双向数据绑定源码实现》
《ntent="mp" href="https://www.toutiao.com/i6807204223193711116/?group_id=6807204223193711116" rel="noopener noreferrer" target="_blank">干货满满!如何优雅简洁地实现时钟翻牌器(支持JS/Vue/React)》
《ntent="mp" href="https://www.toutiao.com/i6807019844597187079/?group_id=6807019844597187079" rel="noopener noreferrer" target="_blank">手把手教你D3.js 实现数据可视化极速上手到Vue应用》
《ntent="mp" href="https://www.toutiao.com/i6804675576037638663/?group_id=6804675576037638663" rel="noopener noreferrer" target="_blank">吃透 Vue 项目开发实践|16个方面深入前端工程化开发技巧【中】》
《ntent="mp" href="https://www.toutiao.com/i6819081157213159947/?group_id=6819081157213159947" rel="noopener noreferrer" target="_blank">Vue3.0权限管理实现流程【实践】》
《ntent="mp" href="https://www.toutiao.com/i6820294027150098948/?group_id=6820294027150098948" rel="noopener noreferrer" target="_blank">后台管理系统,前端Vue根据角色动态设置菜单栏和路由》
作者:妹红大大
转发链接:https://mp.weixin.qq.com/s/D_PRIMAD6i225Pn-a_lzPA