├── .gitignore ├── README.md ├── babel.config.js ├── docs ├── arithmetic.md ├── diff.md ├── effect.md ├── quession.md └── reactive.md ├── drawio ├── diff.drawio ├── reative.drawio └── runtime-core.drawio ├── example ├── apiInjectExample │ ├── App.js │ ├── index.html │ └── index.js ├── helloWord │ ├── App.js │ ├── Foo.js │ ├── index.html │ └── index.js ├── nexttickExample │ ├── App.js │ ├── index.html │ └── index.js ├── patchElementExample │ ├── App.js │ ├── Array2Array.js │ ├── Array2Text.js │ ├── Text2Array.js │ ├── Text2Text.js │ ├── index.html │ └── index.js ├── pixijs │ ├── App.js │ ├── index.html │ └── index.js ├── slotsExample │ ├── App.js │ ├── Foo.js │ ├── index.html │ └── index.js ├── updateElementExample │ ├── App.js │ ├── index.html │ └── index.js ├── updateElementPropsExample │ ├── App.js │ ├── Child.js │ ├── index.html │ └── index.js └── updatePropsExample │ ├── App.js │ ├── index.html │ └── index.js ├── lib ├── mini-vue.cjs.js └── mini-vue.esm.js ├── package.json ├── rollup.config.js ├── src ├── index.ts ├── reactivity │ ├── baseHandlers.ts │ ├── computed.ts │ ├── effect.ts │ ├── index.ts │ ├── reactive.ts │ ├── ref.ts │ └── tests │ │ ├── computed.spec.ts │ │ ├── effect.spec.ts │ │ ├── lis.spec.ts │ │ ├── reactive.spec.ts │ │ ├── readonly.spec.ts │ │ ├── ref.spec.ts │ │ ├── shallowReactive.spec.ts │ │ └── shallowReadonly.spec.ts ├── runtime-core │ ├── apiInject.ts │ ├── component.ts │ ├── componentEmits.ts │ ├── componentProps.ts │ ├── componentPublicInstance.ts │ ├── componentSlots.ts │ ├── componentUpdate.ts │ ├── createApp.ts │ ├── h.ts │ ├── helpers │ │ └── renderSlot.ts │ ├── index.ts │ ├── renderer.ts │ ├── scheduler.ts │ └── vnode.ts ├── runtime-dom │ └── index.ts └── shared │ ├── index.ts │ └── shapeFlags.ts └── tsconfig.json /.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | .vscode 3 | 4 | yarn-error.log 5 | yarn.lock 6 | 7 | /node_modules -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 😀 mini-vue3 2 | 3 | 👴 一步一步学习vue3 源码 4 | 5 | 👵 编写代码节奏:先写测试,再写实现,再写优化 6 | 7 | ![](https://github.com/getActivity/EmojiPackage/blob/master/%E5%AE%89%E6%8E%92/%E5%AE%89%E6%8E%92.png) 8 | 9 | 10 | # 🍁 Project Process 11 | 12 | ## Reactive 13 | 14 | ## Runtime-core 15 | 16 | ## Compiler-core 17 | 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: [ 3 | ['@babel/preset-env', {targets: {node: 'current'}}], 4 | '@babel/preset-typescript' 5 | ] 6 | } -------------------------------------------------------------------------------- /docs/arithmetic.md: -------------------------------------------------------------------------------- 1 | 2 | # 算法 3 | 4 | ## 最长递归子序列(LIS) -------------------------------------------------------------------------------- /docs/diff.md: -------------------------------------------------------------------------------- 1 | 2 | # Diff 3 | 4 | ToBePathed: 新节点需要进行对比的长度 5 | 6 | newIndexToOldIndexMap: 获取新节点需要进行中间对比的index索引 7 | 8 | 0 1 2 3 4 5 9 | a b (e f d) g 10 | a b (d e f) g 11 | 12 | diff 13 | 14 | * 经过左侧对比,index的位置是2 15 | * 经过右侧对比,新节点位置是 e1 = 4, e2 = 4 16 | * index位置大于e1,且 index少于等e2,证明着新节点比旧节点的要多,所以要新增节点 17 | * index位置大于新节点e1,证明新节点少于旧节点,需要减少旧节点上的。 18 | * 两种情况都不是的话,需要进行中间对比 19 | 20 | diff middle 21 | 22 | * 获取`新节点`需要对比的节点长度toBePatched = e2 - s2 + 1 (索引需要加1) 23 | * 获取新节点中需要中间对比的节点的key和索引关系 -> keyToNewIndexMap 24 | * 生成新节点需要映射索引的Array(toBePatched) -> newIndexToOldIndexMap 25 | * 循环需要中间对比的旧节点 26 | * 利用旧节点的key值去keyToNewIndexMap找相对应的key值,获取对应的索引nextIndex 27 | * 如果旧节点是没有这个key值的,就需要在新节点上进行遍历isSomeVNodeType(n1, n2),知道对应的索引nextIndex 28 | * 如果nextIndex为空,证明着新节点里面不需要用到,需要进行删除hostRemove() 29 | * 如果nextIndex不为空,此时需要新旧节点进行patch一下 30 | * 此时也需要把新节点的索引假加入到对应的newIndexToOldIndexMap中。 31 | * 旧节点循环后,此时会得到了newIndexToOldIndexMap 32 | * 利用算法最长子序列算法LIS得到对应的索引列表 33 | 34 | -------------------------------------------------------------------------------- /docs/effect.md: -------------------------------------------------------------------------------- 1 | 2 | # effect 3 | 4 | 功能:收集依赖(观察者 -> 收集依赖),通知收集的依赖(通知观察者 -> 触发依赖) 5 | 6 | 提供三个重要的Function 7 | 8 | effect是将传入的函数转化为reactiveEffect格式的函数 9 | 10 | track主要功能是将reactiveEffect添加为`target[key]`的观察者 11 | 12 | trigger主要功能是通知`target[key]`的观察者(将观察者队列函数一一取出来执行) 13 | -------------------------------------------------------------------------------- /docs/quession.md: -------------------------------------------------------------------------------- 1 | 2 | dep 对应一个 key 这个逻辑需要自己重新来理一下 (未完成) 3 | 4 | 代理对象 $el 需要理解多一次 5 | 6 | props重新看一次 7 | 8 | diff重新看一次 -------------------------------------------------------------------------------- /docs/reactive.md: -------------------------------------------------------------------------------- 1 | 2 | # reactive 3 | 4 | 对象响应 5 | 6 | Vue2 使用 Object.defineProperty() 7 | 8 | Vue3 使用 Proxy代理 9 | 10 | getter 11 | 12 | Vue2: `return target[key]` 13 | 14 | Vue3: `return Reflect.get(target, key)` 15 | 16 | setter 17 | 18 | Vue2: `target[key] = value` 19 | 20 | Vue3: `Reflect.set(target, key, value)` 21 | 22 | 23 | -------------------------------------------------------------------------------- /drawio/diff.drawio: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BenLiang0419/mini-vue3/c87358f857be17ac0e637e9c92de727a4bd165a2/drawio/diff.drawio -------------------------------------------------------------------------------- /drawio/reative.drawio: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BenLiang0419/mini-vue3/c87358f857be17ac0e637e9c92de727a4bd165a2/drawio/reative.drawio -------------------------------------------------------------------------------- /drawio/runtime-core.drawio: -------------------------------------------------------------------------------- 1 | 7V1Lk6M2EP41rkoOkwIE2D7OazepylZtZQ/JHDUgY2UBESGP7fz6CJB4WHjXG9vgsfuyi1oSdH9q+ms98EzQY7L5yHG2/MRCEk8cK9xM0NPEcaaOJf8tBNtK4FpeJYg4DSuR3Qi+0H+JEqp+0YqGJO80FIzFgmZdYcDSlASiI8Ocs3W32YLF3admOCKG4EuAY1P6Jw3FspLOnGkj/5XQaKmfbPvzqibBurGyJF/ikK1bIvQ8QY+cMVFdJZtHEhfYaVyqfh/21NaKcZKKQzq4VYc3HK+UbUovsdXGklDaroqMiyWLWIrj50b6wNkqDUlxR0uWmja/M5ZJoS2FfxMhtmog8UowKVqKJFa1ptbKkJyteKD0UJoJzCOiWqFKVGjY6qYs/UhYQgTfygacxFjQt+7oYeUEUd2uwUleKKj6YXMM2PgqFTQhd4H0dQPCLkDrJRXkS4ZLw9byBTkQjDfCBdl801BVq71rq4uqvG6c1dZtli1H9a3jofHfj0ch06O8sTwKmR5FJAR8dF+y/RGdafZ+nMkznWk6ljN5BmwZFsFydF9C1oi+ZNsGKhfrTFPTmXTuM7w3TXtw82Op1kNI3zr4+f+sisTlIWAx4xN0X2gTvf6EJCdI7eWDLNduLqc/F9cFItYrDr5GJbR3O30dz6t77Fw33RcsFXcLnNB4W/WUquAkKysRckuN0pzFEoXdivqGPV1WnBYB2ErJen+/hKUsL1+ajjZ5Of6FLrabbeq6mKbkTnt2WTtv1ZZv4F11t7I246RBVV5F6v8Sfdku/R78Ut2Z41nhwrxNxllA8vyRJRlLC2dUt5XuUN25+zQpLodbS0cOJa57QChBZwoldfY+aOSQYPHtX6p/WXgpCr94uvi0aVc+bVXpoIijw0sn5DhjhRytDcScC4s5+9C/LDT2WHymQJpIHxL/N4xeZHD1x8zT3tOahI6Qnag5Gy1qmssSEDUhap4pal6lUUdSQcAJFqTmgt/SXOC00OYEnHCRTDH1DmCK+ZmYYm6Eu/ssMyCRloiu3bng7KscpXJEZRMU+q++5xe+S+O4JV8sFk4QSDmOaZRKWSCRkl6IHgqEaIDje1WR0DAseacP8u6gnAB1Z/p91N0e0J1T0LM/7tynme68tOuOmvvMTBY//d5C2fWec7xtNcgYTUXeuvPnQtCMtG35Xmeo9XLshz0dZt9uLy8qFZqxrm05bPhntzH89lhJnI5q1w7wydcWhnm/bGd23hcMvaNl6r6B1WtuI0x/+naLYPoD0x+Y/ty0UUfO6XIiVtlpl/fe0QRvfsBU42wTPGSeirhYLtS81+HC0TZQkDtKFrmhokoip54qvrSqmhyyKOgUsk4961zzhNtavaNy8kM+e1JFpMdfH3NEO+9EpZXqtjO4P5g1woYZ5D6QJoBRt2DUKRK6P8rTlc+LRXE+fOic7iIzPbtO40ZJ9fpOmV1qqtez64v80VI92PUF6gdCAaNuwSig/rNQvzXvbmogd0jq7/tkCAgMCAzCIhh1bUYBgZ2DwGbOiPzl9O3YA38Bf0FUBKOuzagj+YumVHzmLMuBt8rd9Vl3ydUfkrZg3RBoC4IhGHULRgFtnXWrcFDe6jsUBrwFvAXR8KaNgmO+x3zHOR0voCPzO87LPfrR8zNfaLQP/pH5Q19AhUCFwBpg1PUZBTtngxz9cAc9+gGfbAKBQVgEo27BKCCwIY5+DMpf+lkt/qL5p+L3ACUCu8hc4Q8R2RLaDvrO3ETft03wnR8HXxabv4tQfSLZ/HEJ9Pwf -------------------------------------------------------------------------------- /example/apiInjectExample/App.js: -------------------------------------------------------------------------------- 1 | 2 | import { h, provide, inject } from '../../lib/mini-vue.esm.js' 3 | 4 | window.self = null 5 | 6 | const Foo = { 7 | setup() { 8 | provide("foo", "foo"); 9 | provide("bar", "bar"); 10 | return { 11 | msg: 'foo-1' 12 | } 13 | }, 14 | render() { 15 | const compOne = h("h1", {}, this.msg); 16 | const compTwo = h(FooSecond) 17 | 18 | return h("div", {}, [compOne, compTwo]) 19 | } 20 | }; 21 | 22 | const FooSecond = { 23 | setup() { 24 | provide('foo', 'fooTwo') 25 | const foo = inject('foo') 26 | return { 27 | msg: 'foo-2', 28 | foo 29 | } 30 | }, 31 | render() { 32 | const compOne = h("h1", {}, this.msg + '->' + this.foo); 33 | const bar = h(Bar) 34 | return h("div", {}, [compOne, bar]) 35 | } 36 | }; 37 | 38 | const Bar = { 39 | setup() { 40 | const bar = inject('bar') 41 | const foo = inject('foo') 42 | 43 | return { 44 | foo, bar 45 | } 46 | }, 47 | render() { 48 | const app = h("h1", {}, "Bar") 49 | const constom = h('h2', {}, `Bar-provide-inject: foo - ${this.foo}, bar - ${this.bar}`) 50 | 51 | return h('div', {}, [app, constom]) 52 | } 53 | } 54 | 55 | export const App = { 56 | name: 'App', 57 | setup() { 58 | // console.log("current instance", getCurrentInstance()) 59 | return { 60 | username: 'BoLi-luyi' 61 | } 62 | }, 63 | render() { 64 | window.self = this 65 | const app = h("h1", {}, "App") 66 | const foo = h(Foo) 67 | 68 | return h("div", {}, [app, foo]) 69 | } 70 | }; 71 | -------------------------------------------------------------------------------- /example/apiInjectExample/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Document 8 | 9 | 20 | 21 |
22 | 9 | 10 | 21 | 22 |
23 |