├── .gitignore
├── README.md
├── babel.config.js
├── example
├── apiProviderInject
│ ├── App.js
│ ├── index.html
│ └── main.js
├── componentEmit
│ ├── App.js
│ ├── index.html
│ └── main.js
├── componentSlot
│ ├── App.js
│ ├── index.html
│ └── main.js
├── currentInstance
│ ├── App.js
│ ├── index.html
│ └── main.js
├── helloworld
│ ├── App.js
│ ├── index.html
│ └── main.js
├── patchChildren
│ ├── App.js
│ ├── index.html
│ └── main.js
└── update
│ ├── App.js
│ ├── index.html
│ └── main.js
├── index.html
├── lib
├── guide-mini-vue3.cjs.js
└── guide-mini-vue3.esm.js
├── package.json
├── packages
├── index.ts
├── reactivity
│ ├── __test__
│ │ ├── computed.spec.ts
│ │ ├── effect.spec.ts
│ │ ├── reactive.spec.ts
│ │ ├── readonly.spec.ts
│ │ └── ref.spec.ts
│ └── src
│ │ ├── baseHandlers.ts
│ │ ├── computed.ts
│ │ ├── effect.ts
│ │ ├── index.ts
│ │ ├── reactive.ts
│ │ └── ref.ts
├── runtime-core
│ └── src
│ │ ├── apiInject.ts
│ │ ├── component.ts
│ │ ├── componentEmit.ts
│ │ ├── componentProps.ts
│ │ ├── componentPublicInstance.ts
│ │ ├── componentSlots.ts
│ │ ├── createApp.ts
│ │ ├── h.ts
│ │ ├── helpers
│ │ └── renderSlots.ts
│ │ ├── index.ts
│ │ ├── renderer.ts
│ │ └── vnode.ts
├── runtime-dom
│ └── index.ts
└── shared
│ ├── index.ts
│ └── shapeFlags.ts
├── rollup.config.js
└── tsconfig.json
/.gitignore:
--------------------------------------------------------------------------------
1 | /node_modules
2 | /yarn.lock
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # mini-vue3
2 |
3 | > 实现一个简易的 Vue3 用来学习源码
4 |
5 |
--------------------------------------------------------------------------------
/babel.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | presets: [
3 | ["@babel/preset-env", { targets: { node: "current" } }],
4 | "@babel/preset-typescript",
5 | ],
6 | }
7 |
--------------------------------------------------------------------------------
/example/apiProviderInject/App.js:
--------------------------------------------------------------------------------
1 | import { h, provide, inject } from "../../lib/guide-mini-vue3.esm.js"
2 |
3 | const Child = {
4 | name: "Child",
5 | setup() {
6 | const foo = inject("foo")
7 | return { foo }
8 | },
9 | render() {
10 | return h("div", {}, "value =>" + this.foo)
11 | },
12 | }
13 |
14 | const App = {
15 | name: "App",
16 | render() {
17 | return h("div", { id: "aaaaa" }, [h(Child)])
18 | },
19 | setup() {
20 | provide("foo", "foo-value")
21 |
22 | return {
23 | msg: "hello mini-vue3!!!",
24 | }
25 | },
26 | }
27 |
28 | export default App
29 |
--------------------------------------------------------------------------------
/example/apiProviderInject/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Document
8 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/example/apiProviderInject/main.js:
--------------------------------------------------------------------------------
1 | import App from "./App.js"
2 | import { createApp } from "../../lib/guide-mini-vue3.esm.js"
3 | const rootContainer = document.querySelector("#app")
4 | createApp(App).mount(rootContainer)
5 |
--------------------------------------------------------------------------------
/example/componentEmit/App.js:
--------------------------------------------------------------------------------
1 | import { h, renderSlots } from "../../lib/guide-mini-vue3.esm.js"
2 |
3 | const Foo = {
4 | setup(props, { emit }) {
5 | return {
6 | emitAdd() {
7 | emit("add")
8 | },
9 | }
10 | },
11 | render() {
12 | const btn = h("button", { onClick: this.emitAdd }, "emitAdd")
13 | const foo = h("div", {}, "foo")
14 | return h("div", {}, [foo, btn])
15 | },
16 | }
17 |
18 | const app = h("div", {}, [
19 | h(Foo, {
20 | onAdd() {
21 | console.log("onAdd")
22 | },
23 | }),
24 | ])
25 |
26 | const App = {
27 | render() {
28 | return app
29 | },
30 | setup() {
31 | return {}
32 | },
33 | }
34 |
35 | export default App
36 |
--------------------------------------------------------------------------------
/example/componentEmit/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Document
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/example/componentEmit/main.js:
--------------------------------------------------------------------------------
1 | import App from "./App.js"
2 | import { createApp } from "../../lib/guide-mini-vue3.esm.js"
3 | const rootContainer = document.querySelector("#app")
4 | createApp(App).mount(rootContainer)
5 |
--------------------------------------------------------------------------------
/example/componentSlot/App.js:
--------------------------------------------------------------------------------
1 | import {
2 | h,
3 | renderSlots,
4 | createTextVnode,
5 | } from "../../lib/guide-mini-vue3.esm.js"
6 |
7 | const Foo = {
8 | setup(props) {},
9 | render() {
10 | const foo = h("p", {}, "foo")
11 | return h("div", {}, [
12 | renderSlots(this.$slots, "header", { a: 1 }),
13 | foo,
14 | renderSlots(this.$slots, "footer"),
15 | ])
16 | },
17 | }
18 |
19 | const foo = h(
20 | Foo,
21 | {},
22 | {
23 | header: ({ a }) => h("p", {}, "header slot" + a),
24 | footer: () => [
25 | h("p", {}, "footer slot"),
26 | h("p", {}, "footer slot"),
27 | createTextVnode("hello"),
28 | ],
29 | }
30 | )
31 |
32 | const app = h("div", { id: "app" }, ["App", foo])
33 |
34 | const App = {
35 | render() {
36 | return app
37 | },
38 | setup() {
39 | return {}
40 | },
41 | }
42 |
43 | export default App
44 |
--------------------------------------------------------------------------------
/example/componentSlot/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Document
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/example/componentSlot/main.js:
--------------------------------------------------------------------------------
1 | import App from "./App.js"
2 | import { createApp } from "../../lib/guide-mini-vue3.esm.js"
3 | const rootContainer = document.querySelector("#app")
4 | createApp(App).mount(rootContainer)
5 |
--------------------------------------------------------------------------------
/example/currentInstance/App.js:
--------------------------------------------------------------------------------
1 | import { h, getCurrentInstance } from "../../lib/guide-mini-vue3.esm.js"
2 |
3 | const Foo = {
4 | name: "Foo",
5 | setup() {
6 | const instance = getCurrentInstance()
7 | console.log(instance)
8 | },
9 | render() {
10 | return h("p", {}, "foo")
11 | },
12 | }
13 |
14 | const App = {
15 | name: "App",
16 | render() {
17 | return h("div", {}, [h(Foo), "currentInstance Demo"])
18 | },
19 | setup() {
20 | const instance = getCurrentInstance()
21 |
22 | console.log(instance)
23 | },
24 | }
25 |
26 | export default App
27 |
--------------------------------------------------------------------------------
/example/currentInstance/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Document
8 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/example/currentInstance/main.js:
--------------------------------------------------------------------------------
1 | import App from "./App.js"
2 | import { createApp } from "../../lib/guide-mini-vue3.esm.js"
3 | const rootContainer = document.querySelector("#app")
4 | createApp(App).mount(rootContainer)
5 |
--------------------------------------------------------------------------------
/example/helloworld/App.js:
--------------------------------------------------------------------------------
1 | import { h } from "../../lib/guide-mini-vue3.esm.js"
2 |
3 | const Title = {
4 | setup(props) {
5 | props.count++
6 | },
7 | render() {
8 | return h("div", {}, this.count)
9 | },
10 | }
11 |
12 | const App = {
13 | render() {
14 | return h("div", { id: "aaaaa" }, [
15 | h(
16 | "h1",
17 | {
18 | id: "red",
19 | onClick() {
20 | console.log("click")
21 | },
22 | onMouseDown() {
23 | console.log("mousedown")
24 | },
25 | },
26 | "Hello Vue3!!!"
27 | ),
28 | h("h2", {}, this.msg),
29 | h(Title, { count: 1 }),
30 | ])
31 | },
32 | setup() {
33 | return {
34 | msg: "hello mini-vue3!!!",
35 | }
36 | },
37 | }
38 |
39 | export default App
40 |
--------------------------------------------------------------------------------
/example/helloworld/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Document
8 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/example/helloworld/main.js:
--------------------------------------------------------------------------------
1 | import App from "./App.js"
2 | import { createApp } from "../../lib/guide-mini-vue3.esm.js"
3 | const rootContainer = document.querySelector("#app")
4 | createApp(App).mount(rootContainer)
5 |
--------------------------------------------------------------------------------
/example/patchChildren/App.js:
--------------------------------------------------------------------------------
1 | import { createTextVnode, h, ref } from "../../lib/guide-mini-vue3.esm.js"
2 |
3 | const App = {
4 | render() {
5 | const textToArray = h(
6 | "div",
7 | {},
8 | !this.isChange ? "text children" : [h("div", {}, "A"), h("div", {}, "B")]
9 | )
10 |
11 | const textToText = h(
12 | "div",
13 | {},
14 | !this.isChange ? "text children" : "new text children"
15 | )
16 |
17 | const ArrayToText = h(
18 | "div",
19 | {},
20 | !this.isChange ? [h("div", {}, "A"), h("div", {}, "B")] : "text children"
21 | )
22 | return ArrayToText
23 | },
24 | setup() {
25 | const isChange = ref(false)
26 |
27 | window.isChange = isChange
28 | return {
29 | isChange,
30 | }
31 | },
32 | }
33 |
34 | export default App
35 |
--------------------------------------------------------------------------------
/example/patchChildren/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Document
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/example/patchChildren/main.js:
--------------------------------------------------------------------------------
1 | import App from "./App.js"
2 | import { createApp } from "../../lib/guide-mini-vue3.esm.js"
3 | const rootContainer = document.querySelector("#app")
4 | createApp(App).mount(rootContainer)
5 |
--------------------------------------------------------------------------------
/example/update/App.js:
--------------------------------------------------------------------------------
1 | import { createTextVnode, h, ref } from "../../lib/guide-mini-vue3.esm.js"
2 |
3 | const App = {
4 | render() {
5 | return h("div", { ...this.props }, [
6 | h("h1", {}, createTextVnode(this.count)),
7 | h("button", { onClick: this.changePropsDemo }, "add Count"),
8 | h("button", { onClick: this.changePropsDemo1 }, "修改props"),
9 | h(
10 | "button",
11 | { onClick: this.changePropsDemo2 },
12 | "修改props为undefind,删除prop"
13 | ),
14 | h(
15 | "button",
16 | { onClick: this.changePropsDemo3 },
17 | "新的props中不存在某个属性,则删除该属性"
18 | ),
19 | ])
20 | },
21 | setup() {
22 | const props = ref({
23 | foo: "foo",
24 | bar: "bar",
25 | })
26 |
27 | const count = ref(0)
28 |
29 | const changePropsDemo = () => {
30 | count.value++
31 | }
32 |
33 | // 修改props
34 | const changePropsDemo1 = () => {
35 | props.value.foo = "new-foo"
36 | }
37 |
38 | // 设置 props 为undefined 删除prop
39 | const changePropsDemo2 = () => {
40 | props.value.foo = undefined
41 | }
42 |
43 | // 新的props中不存在某个属性,则删除该属性
44 | const changePropsDemo3 = () => {
45 | props.value = {
46 | foo: "foo",
47 | }
48 | }
49 |
50 | return {
51 | count,
52 | props,
53 | changePropsDemo,
54 | changePropsDemo1,
55 | changePropsDemo2,
56 | changePropsDemo3,
57 | }
58 | },
59 | }
60 |
61 | export default App
62 |
--------------------------------------------------------------------------------
/example/update/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Document
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/example/update/main.js:
--------------------------------------------------------------------------------
1 | import App from "./App.js"
2 | import { createApp } from "../../lib/guide-mini-vue3.esm.js"
3 | const rootContainer = document.querySelector("#app")
4 | createApp(App).mount(rootContainer)
5 |
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Document
8 |
9 |
10 |
11 |
12 |
154 |
155 |
--------------------------------------------------------------------------------
/lib/guide-mini-vue3.cjs.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | Object.defineProperty(exports, '__esModule', { value: true });
4 |
5 | var extend = Object.assign;
6 | var EMPTY_OBJ = {};
7 | var isObject = function (target) { return typeof target === "object"; };
8 | var hasChanged = function (value, newValue) { return !Object.is(value, newValue); };
9 | var hasOwn = function (value, key) {
10 | return Object.prototype.hasOwnProperty.call(value, key);
11 | };
12 | var camelize = function (str) {
13 | return str.replace(/-(\w)/g, function (_, c) { return (c ? c.toUpperCase() : ""); });
14 | };
15 | var capitalize = function (str) { return str.charAt(0).toUpperCase() + str.slice(1); };
16 | var toHandlerKey = function (str) { return (str ? "on" + capitalize(str) : ""); };
17 |
18 | exports.activeEffect = void 0;
19 | var targetMap = new WeakMap();
20 | function track(target, key) {
21 | if (!exports.activeEffect) {
22 | return;
23 | }
24 | var depsMap = targetMap.get(target);
25 | if (!depsMap) {
26 | depsMap = new Map();
27 | targetMap.set(target, depsMap);
28 | }
29 | var dep = depsMap.get(key);
30 | if (!dep) {
31 | dep = new Set();
32 | depsMap.set(key, dep);
33 | }
34 | trackEffects(dep);
35 | }
36 | function trackEffects(dep) {
37 | dep.add(exports.activeEffect);
38 | exports.activeEffect.deps.push(dep);
39 | }
40 | function trigger(target, key) {
41 | var depsMap = targetMap.get(target);
42 | if (!depsMap) {
43 | return;
44 | }
45 | var dep = depsMap.get(key);
46 | if (!dep) {
47 | return;
48 | }
49 | triggerEffects(dep);
50 | }
51 | function triggerEffects(dep) {
52 | dep.forEach(function (effect) {
53 | if (effect.scheduler) {
54 | effect.scheduler();
55 | }
56 | else {
57 | effect.run();
58 | }
59 | });
60 | }
61 | var ReactiveEffect = /** @class */ (function () {
62 | function ReactiveEffect(_fn, scheduler) {
63 | this._fn = _fn;
64 | this.scheduler = scheduler;
65 | this.deps = [];
66 | this.active = true;
67 | exports.activeEffect = this;
68 | }
69 | ReactiveEffect.prototype.run = function () {
70 | return this._fn();
71 | };
72 | ReactiveEffect.prototype.stop = function () {
73 | if (this.active) {
74 | cleanupEffect(this);
75 | if (this.onStop) {
76 | this.onStop();
77 | }
78 | this.active = false;
79 | }
80 | };
81 | return ReactiveEffect;
82 | }());
83 | function cleanupEffect(effect) {
84 | effect.deps.forEach(function (dep) {
85 | dep.delete(effect);
86 | });
87 | effect.deps.length = 0;
88 | }
89 | function effect(fn, options) {
90 | var _effect = new ReactiveEffect(fn);
91 | if (options) {
92 | extend(_effect, options);
93 | }
94 | _effect.run();
95 | exports.activeEffect = null;
96 | var runner = _effect.run.bind(_effect);
97 | runner.effect = _effect;
98 | return runner;
99 | }
100 | function stop(runner) {
101 | runner.effect.stop();
102 | }
103 |
104 | var get = createGetter();
105 | var set = createSetter();
106 | var readonlyGet = createGetter(true);
107 | var shallowReactiveGet = createGetter(false, true);
108 | var shallowReadonlyGet = createGetter(true, true);
109 | function createGetter(isReadonly, isShallow) {
110 | if (isReadonly === void 0) { isReadonly = false; }
111 | if (isShallow === void 0) { isShallow = false; }
112 | return function (target, key) {
113 | if (key === "__v_isReactive" /* ReactiveFlags.IS_REACTIVE */) {
114 | return !isReadonly;
115 | }
116 | if (key === "__v_isReadonly" /* ReactiveFlags.IS_READONLY */) {
117 | return isReadonly;
118 | }
119 | var value = Reflect.get(target, key);
120 | if (isObject(value) && !isShallow) {
121 | return isReadonly ? readonly(value) : reactive(value);
122 | }
123 | if (!isReadonly) {
124 | track(target, key);
125 | }
126 | return value;
127 | };
128 | }
129 | function createSetter() {
130 | return function set(target, key, value) {
131 | var oldValue = Reflect.get(target, key);
132 | if (hasChanged(oldValue, value)) {
133 | var result = Reflect.set(target, key, value);
134 | trigger(target, key);
135 | return result;
136 | }
137 | return oldValue;
138 | };
139 | }
140 | var mutableHandlers = {
141 | get: get,
142 | set: set,
143 | };
144 | var shallowMutableHandlers = extend({}, shallowReactiveGet, {
145 | get: shallowReadonlyGet,
146 | });
147 | var readonlyHandlers = {
148 | get: readonlyGet,
149 | set: function (target, key, value) {
150 | console.warn("key: ".concat(key, " set \u5931\u8D25 \u56E0\u4E3A target \u662F readonly"), key);
151 | return true;
152 | },
153 | };
154 | var shallowReadonlyHandlers = extend({}, readonlyHandlers, {
155 | get: shallowReadonlyGet,
156 | });
157 |
158 | function reactive(raw) {
159 | return createActiveObject(raw, mutableHandlers);
160 | }
161 | function readonly(raw) {
162 | return createActiveObject(raw, readonlyHandlers);
163 | }
164 | function shallowReactive(raw) {
165 | return createActiveObject(raw, shallowMutableHandlers);
166 | }
167 | function shallowReadonly(raw) {
168 | return createActiveObject(raw, shallowReadonlyHandlers);
169 | }
170 | function createActiveObject(raw, baseHandlers) {
171 | if (!isObject(raw)) {
172 | console.log("target ".concat(raw, " \u5FC5\u987B\u662F\u4E00\u4E2A\u5BF9\u8C61"));
173 | return raw;
174 | }
175 | return new Proxy(raw, baseHandlers);
176 | }
177 | function isReadonly(value) {
178 | return !!value["__v_isReadonly" /* ReactiveFlags.IS_READONLY */];
179 | }
180 | function isReactive(value) {
181 | return !!value["__v_isReactive" /* ReactiveFlags.IS_REACTIVE */];
182 | }
183 | function isProxy(value) {
184 | return isReactive(value) || isReadonly(value);
185 | }
186 |
187 | var ComputedRefImpl = /** @class */ (function () {
188 | function ComputedRefImpl(getter) {
189 | var _this = this;
190 | this._dirty = true;
191 | this._getter = getter;
192 | this._effect = new ReactiveEffect(getter, function () {
193 | if (!_this._dirty) {
194 | _this._dirty = true;
195 | }
196 | });
197 | }
198 | Object.defineProperty(ComputedRefImpl.prototype, "value", {
199 | get: function () {
200 | if (this._dirty) {
201 | this._dirty = false;
202 | this._value = this._effect.run();
203 | }
204 | return this._value;
205 | },
206 | enumerable: false,
207 | configurable: true
208 | });
209 | return ComputedRefImpl;
210 | }());
211 | function computed(getter) {
212 | return new ComputedRefImpl(getter);
213 | }
214 |
215 | var refImpl = /** @class */ (function () {
216 | function refImpl(value) {
217 | this.__v_ref = true;
218 | this._rawValue = value;
219 | this._value = convert(value);
220 | this.dep = new Set();
221 | }
222 | Object.defineProperty(refImpl.prototype, "value", {
223 | get: function () {
224 | if (exports.activeEffect) {
225 | trackEffects(this.dep);
226 | }
227 | return this._value;
228 | },
229 | set: function (value) {
230 | if (hasChanged(value, this._rawValue)) {
231 | this._rawValue = value;
232 | this._value = convert(value);
233 | triggerEffects(this.dep);
234 | }
235 | },
236 | enumerable: false,
237 | configurable: true
238 | });
239 | return refImpl;
240 | }());
241 | function convert(value) {
242 | return isObject(value) ? reactive(value) : value;
243 | }
244 | function ref(value) {
245 | return new refImpl(value);
246 | }
247 | function isRef(ref) {
248 | return !!ref.__v_ref;
249 | }
250 | function unRef(ref) {
251 | return isRef(ref) ? ref.value : ref;
252 | }
253 | function proxyRefs(objectwithRefs) {
254 | if (objectwithRefs === void 0) { objectwithRefs = {}; }
255 | return new Proxy(objectwithRefs, {
256 | get: function (target, key) {
257 | return unRef(Reflect.get(target, key));
258 | },
259 | set: function (target, key, value) {
260 | if (isRef(target[key]) && !isRef(value)) {
261 | return (target[key].value = value);
262 | }
263 | else {
264 | return Reflect.set(target, key, value);
265 | }
266 | },
267 | });
268 | }
269 |
270 | function emit(instance, event) {
271 | var props = instance.props;
272 | var handlerName = toHandlerKey(camelize(event));
273 | var handler = props[handlerName];
274 | handler && handler();
275 | }
276 |
277 | function initProps(instance, rawProps) {
278 | instance.props = rawProps || {};
279 | }
280 |
281 | var publicPropertiesMap = {
282 | $el: function (i) { return i.vnode.el; },
283 | $slots: function (i) { return i.slots; },
284 | };
285 | var publicInstanceProxyHandlers = {
286 | get: function (_a, key) {
287 | var instance = _a._;
288 | var setupState = instance.setupState, props = instance.props;
289 | if (hasOwn(setupState, key)) {
290 | return setupState[key];
291 | }
292 | if (hasOwn(props, key)) {
293 | return props[key];
294 | }
295 | var publicGetter = publicPropertiesMap[key];
296 | if (publicGetter) {
297 | return publicGetter(instance);
298 | }
299 | },
300 | };
301 |
302 | function initSlots(instance, children) {
303 | instance.slots = children;
304 | }
305 |
306 | var currentInstance = null;
307 | function createComponentInstance(vnode, parentComponent) {
308 | var component = {
309 | vnode: vnode,
310 | type: vnode.type,
311 | setupState: {},
312 | props: {},
313 | slots: {},
314 | provides: {},
315 | isMounted: false,
316 | subTree: {},
317 | parent: parentComponent,
318 | emit: function (instance, event) { },
319 | };
320 | component.emit = emit.bind(null, component);
321 | return component;
322 | }
323 | function setupComponent(instance) {
324 | initProps(instance, instance.vnode.props);
325 | initSlots(instance, instance.vnode.children);
326 | setupStatefulComponent(instance);
327 | }
328 | function setupStatefulComponent(instance) {
329 | var Component = instance.type;
330 | instance.proxy = new Proxy({ _: instance }, publicInstanceProxyHandlers);
331 | var setup = Component.setup;
332 | if (setup) {
333 | setCurrentInstance(instance);
334 | var setupResult = setup(shallowReadonly(instance.props), {
335 | emit: instance.emit,
336 | });
337 | setCurrentInstance(null);
338 | handleSetupResult(instance, proxyRefs(setupResult));
339 | }
340 | }
341 | function handleSetupResult(instance, setupResult) {
342 | if (typeof setupResult === "object") {
343 | // 如果是object那么返回的就是context
344 | instance.setupState = setupResult;
345 | }
346 | finishCompoentSetup(instance);
347 | }
348 | function finishCompoentSetup(instance) {
349 | var Component = instance.type;
350 | instance.render = Component.render;
351 | }
352 | function getCurrentInstance() {
353 | return currentInstance;
354 | }
355 | function setCurrentInstance(instance) {
356 | currentInstance = instance;
357 | }
358 |
359 | var Fragment = Symbol("Fragment");
360 | var Text = Symbol("Text");
361 | function createVNode(type, props, children) {
362 | var vnode = {
363 | type: type,
364 | props: props,
365 | children: children,
366 | shapeFlag: getShapeFlag(type, children),
367 | el: null,
368 | };
369 | return vnode;
370 | }
371 | function createTextVnode(text) {
372 | return createVNode(Text, {}, String(text));
373 | }
374 | function getShapeFlag(type, children) {
375 | var flag = 0;
376 | // 处理 element 和 component 的flag
377 | if (typeof type === "string") {
378 | flag |= 1 /* ShapeFlags.ELEMENT */;
379 | }
380 | else if (type === Text) {
381 | flag |= 4 /* ShapeFlags.TEXT_CHILDREN */;
382 | }
383 | else {
384 | flag |= 2 /* ShapeFlags.STATEFUL_COMPONENT */;
385 | }
386 | // 处理 children 的flag
387 | if (Array.isArray(children)) {
388 | flag |= 8 /* ShapeFlags.ARRAY_CHILDREN */;
389 | }
390 | else if (typeof children === "string") {
391 | flag |= 4 /* ShapeFlags.TEXT_CHILDREN */;
392 | }
393 | return flag;
394 | }
395 |
396 | function createAppApi(render) {
397 | return function createApp(rootComponent) {
398 | return {
399 | mount: function (rootContainer) {
400 | var vnode = createVNode(rootComponent);
401 | render(vnode, rootContainer);
402 | },
403 | };
404 | };
405 | }
406 |
407 | function createRender(options) {
408 | var createTextNode = options.createTextNode, insert = options.insert, createElement = options.createElement, hostPatchProps = options.hostPatchProps, setElementInnerContext = options.setElementInnerContext, removeAllChildren = options.removeAllChildren;
409 | function render(vnode, rootContainer) {
410 | patch(null, vnode, rootContainer, null);
411 | }
412 | function patch(n1, n2, container, parentComponent) {
413 | var type = n2.type, shapeFlag = n2.shapeFlag;
414 | switch (type) {
415 | case Fragment:
416 | processFragment(n1, n2, container);
417 | break;
418 | case Text:
419 | processText(n1, n2, container);
420 | break;
421 | default:
422 | if (shapeFlag & 2 /* ShapeFlags.STATEFUL_COMPONENT */) {
423 | // vnode 是一个component
424 | // h(App,{},[])
425 | processComponent(n1, n2, container, parentComponent);
426 | }
427 | else if (shapeFlag & 1 /* ShapeFlags.ELEMENT */) {
428 | // vnode 是一个element
429 | // h('div',{class:'red'},null)
430 | processElement(n1, n2, container, parentComponent);
431 | }
432 | else {
433 | // vnode 不是component 和 element 那就可能是一个文本节点
434 | // h('div',{},[h('p',{},null),'222',this.msg])
435 | insert(createTextNode(n2), container);
436 | }
437 | }
438 | }
439 | function processText(n1, n2, container) {
440 | var children = n2.children;
441 | var textNode = (n2.el = createTextNode(children));
442 | insert(textNode, container);
443 | }
444 | function processFragment(n1, n2, container) {
445 | mountChildren(n2.children, container, null);
446 | }
447 | function processElement(n1, n2, container, parentComponent) {
448 | if (!n1) {
449 | mountElement(n2, container, parentComponent);
450 | }
451 | else {
452 | updateElement(n1, n2);
453 | }
454 | }
455 | function updateElement(n1, n2, container) {
456 | var oldProps = n1.props || EMPTY_OBJ;
457 | var newProps = n2.props || EMPTY_OBJ;
458 | var el = (n2.el = n1.el);
459 | // 对比props
460 | patchProps(el, oldProps, newProps);
461 | // 对比children
462 | patchChildren(n1, n2, el);
463 | }
464 | function patchChildren(n1, n2, container) {
465 | // n1 children 是文本节点
466 | if (!!(n1.shapeFlag & 4 /* ShapeFlags.TEXT_CHILDREN */)) {
467 | if (!!(n2.shapeFlag & 8 /* ShapeFlags.ARRAY_CHILDREN */)) {
468 | // text children => array children
469 | removeAllChildren(container);
470 | mountChildren(n2.children, container, null);
471 | }
472 | else {
473 | // text children => text children
474 | if (n1.children !== n2.children) {
475 | setElementInnerContext(container, n2.children);
476 | }
477 | }
478 | }
479 | else {
480 | // n1 children 是一个数组
481 | if (!!(n2.shapeFlag & 8 /* ShapeFlags.ARRAY_CHILDREN */)) ;
482 | else {
483 | // array children => text children
484 | removeAllChildren(container);
485 | setElementInnerContext(container, n2.children);
486 | }
487 | }
488 | }
489 | function patchProps(el, oldProps, newProps) {
490 | if (oldProps !== newProps) {
491 | for (var key in newProps) {
492 | var prevProp = oldProps[key];
493 | var nextProp = newProps[key];
494 | if (prevProp !== nextProp) {
495 | hostPatchProps(el, key, prevProp, nextProp);
496 | }
497 | }
498 | if (oldProps !== EMPTY_OBJ) {
499 | for (var key in oldProps) {
500 | if (!(key in newProps)) {
501 | hostPatchProps(el, key, oldProps[key], null);
502 | }
503 | }
504 | }
505 | }
506 | }
507 | function mountElement(vnode, container, parentComponent) {
508 | var type = vnode.type, children = vnode.children, props = vnode.props, shapeFlag = vnode.shapeFlag;
509 | var el = (vnode.el = createElement(type));
510 | //children
511 | if (shapeFlag & 8 /* ShapeFlags.ARRAY_CHILDREN */) {
512 | mountChildren(children, el, parentComponent);
513 | }
514 | else if (!!(children.shapeFlag & 4 /* ShapeFlags.TEXT_CHILDREN */)) {
515 | var vlaue = children.children;
516 | insert(createTextNode(vlaue), el);
517 | }
518 | else {
519 | setElementInnerContext(el, children);
520 | }
521 | // props
522 | for (var key in props) {
523 | var val = props[key];
524 | hostPatchProps(el, key, null, val);
525 | }
526 | insert(el, container);
527 | }
528 | function mountChildren(children, container, parentComponent) {
529 | children.forEach(function (child) {
530 | patch(null, child, container, parentComponent);
531 | });
532 | }
533 | function processComponent(n1, n2, container, parentComponent) {
534 | mountComponent(n2, container, parentComponent);
535 | }
536 | function mountComponent(initinalVNode, container, parentComponent) {
537 | var instance = createComponentInstance(initinalVNode, parentComponent);
538 | setupComponent(instance);
539 | setupRenderEffect(instance, container);
540 | }
541 | function setupRenderEffect(instance, container) {
542 | effect(function () {
543 | var proxy = instance.proxy;
544 | if (!instance.isMounted) {
545 | console.log("init");
546 | var subTree = (instance.subTree = instance.render.call(proxy));
547 | patch(null, subTree, container, instance);
548 | instance.vnode.el = subTree.el;
549 | instance.isMounted = true;
550 | }
551 | else {
552 | console.log("update");
553 | var subTree = instance.render.call(proxy);
554 | var preSubTree = instance.subTree;
555 | instance.vnode.el = subTree.el;
556 | patch(preSubTree, subTree, container, instance);
557 | }
558 | });
559 | }
560 | return {
561 | createApp: createAppApi(render),
562 | };
563 | }
564 |
565 | function h(type, props, children) {
566 | return createVNode(type, props, children);
567 | }
568 |
569 | function renderSlots(slots, name, props) {
570 | var slot = slots[name];
571 | if (slot) {
572 | if (typeof slot === "function") {
573 | return createVNode(Fragment, {}, handleSlotChilren(slot(props)));
574 | }
575 | }
576 | }
577 | function handleSlotChilren(slot) {
578 | return Array.isArray(slot) ? slot : [slot];
579 | }
580 |
581 | function provide(key, value) {
582 | var instance = getCurrentInstance();
583 | if (instance) {
584 | var provides = instance.provides;
585 | provides[key] = value;
586 | }
587 | }
588 | function inject(key) {
589 | var instance = getCurrentInstance();
590 | if (instance) {
591 | var value = null;
592 | while (value === null) {
593 | var parent_1 = instance.parent;
594 | if (parent_1) {
595 | if (parent_1.provides[key]) {
596 | return parent_1.provides[key];
597 | }
598 | }
599 | }
600 | }
601 | }
602 |
603 | function createTextNode(text) {
604 | return document.createTextNode(text);
605 | }
606 | function insert(child, container) {
607 | container.appendChild(child);
608 | }
609 | function createElement(type) {
610 | return document.createElement(type);
611 | }
612 | function patchProps(el, key, prevVal, nextVal) {
613 | var isOn = function (key) { return /^on[A-Z]*/.test(key); };
614 | // event
615 | if (isOn(key)) {
616 | var event_1 = key.slice(2).toLocaleLowerCase();
617 | el.addEventListener(event_1, nextVal);
618 | }
619 | else {
620 | // attribute
621 | if (nextVal === undefined || nextVal === null) {
622 | el.removeAttribute(key);
623 | }
624 | else {
625 | el.setAttribute(key, nextVal);
626 | }
627 | }
628 | }
629 | function setElementInnerContext(el, context) {
630 | el.textContent = context;
631 | }
632 | function removeAllChildren(el) {
633 | el.innerHTML = "";
634 | }
635 | var renderer = createRender({
636 | createTextNode: createTextNode,
637 | insert: insert,
638 | createElement: createElement,
639 | hostPatchProps: patchProps,
640 | setElementInnerContext: setElementInnerContext,
641 | removeAllChildren: removeAllChildren,
642 | });
643 | function createApp(rootComponent) {
644 | return renderer.createApp(rootComponent);
645 | }
646 |
647 | exports.ReactiveEffect = ReactiveEffect;
648 | exports.cleanupEffect = cleanupEffect;
649 | exports.computed = computed;
650 | exports.createApp = createApp;
651 | exports.createTextVnode = createTextVnode;
652 | exports.effect = effect;
653 | exports.getCurrentInstance = getCurrentInstance;
654 | exports.h = h;
655 | exports.inject = inject;
656 | exports.isProxy = isProxy;
657 | exports.isReactive = isReactive;
658 | exports.isReadonly = isReadonly;
659 | exports.isRef = isRef;
660 | exports.provide = provide;
661 | exports.proxyRefs = proxyRefs;
662 | exports.reactive = reactive;
663 | exports.readonly = readonly;
664 | exports.ref = ref;
665 | exports.renderSlots = renderSlots;
666 | exports.shallowReactive = shallowReactive;
667 | exports.shallowReadonly = shallowReadonly;
668 | exports.stop = stop;
669 | exports.track = track;
670 | exports.trackEffects = trackEffects;
671 | exports.trigger = trigger;
672 | exports.triggerEffects = triggerEffects;
673 | exports.unRef = unRef;
674 |
--------------------------------------------------------------------------------
/lib/guide-mini-vue3.esm.js:
--------------------------------------------------------------------------------
1 | var extend = Object.assign;
2 | var EMPTY_OBJ = {};
3 | var isObject = function (target) { return typeof target === "object"; };
4 | var hasChanged = function (value, newValue) { return !Object.is(value, newValue); };
5 | var hasOwn = function (value, key) {
6 | return Object.prototype.hasOwnProperty.call(value, key);
7 | };
8 | var camelize = function (str) {
9 | return str.replace(/-(\w)/g, function (_, c) { return (c ? c.toUpperCase() : ""); });
10 | };
11 | var capitalize = function (str) { return str.charAt(0).toUpperCase() + str.slice(1); };
12 | var toHandlerKey = function (str) { return (str ? "on" + capitalize(str) : ""); };
13 |
14 | var activeEffect;
15 | var targetMap = new WeakMap();
16 | function track(target, key) {
17 | if (!activeEffect) {
18 | return;
19 | }
20 | var depsMap = targetMap.get(target);
21 | if (!depsMap) {
22 | depsMap = new Map();
23 | targetMap.set(target, depsMap);
24 | }
25 | var dep = depsMap.get(key);
26 | if (!dep) {
27 | dep = new Set();
28 | depsMap.set(key, dep);
29 | }
30 | trackEffects(dep);
31 | }
32 | function trackEffects(dep) {
33 | dep.add(activeEffect);
34 | activeEffect.deps.push(dep);
35 | }
36 | function trigger(target, key) {
37 | var depsMap = targetMap.get(target);
38 | if (!depsMap) {
39 | return;
40 | }
41 | var dep = depsMap.get(key);
42 | if (!dep) {
43 | return;
44 | }
45 | triggerEffects(dep);
46 | }
47 | function triggerEffects(dep) {
48 | dep.forEach(function (effect) {
49 | if (effect.scheduler) {
50 | effect.scheduler();
51 | }
52 | else {
53 | effect.run();
54 | }
55 | });
56 | }
57 | var ReactiveEffect = /** @class */ (function () {
58 | function ReactiveEffect(_fn, scheduler) {
59 | this._fn = _fn;
60 | this.scheduler = scheduler;
61 | this.deps = [];
62 | this.active = true;
63 | activeEffect = this;
64 | }
65 | ReactiveEffect.prototype.run = function () {
66 | return this._fn();
67 | };
68 | ReactiveEffect.prototype.stop = function () {
69 | if (this.active) {
70 | cleanupEffect(this);
71 | if (this.onStop) {
72 | this.onStop();
73 | }
74 | this.active = false;
75 | }
76 | };
77 | return ReactiveEffect;
78 | }());
79 | function cleanupEffect(effect) {
80 | effect.deps.forEach(function (dep) {
81 | dep.delete(effect);
82 | });
83 | effect.deps.length = 0;
84 | }
85 | function effect(fn, options) {
86 | var _effect = new ReactiveEffect(fn);
87 | if (options) {
88 | extend(_effect, options);
89 | }
90 | _effect.run();
91 | activeEffect = null;
92 | var runner = _effect.run.bind(_effect);
93 | runner.effect = _effect;
94 | return runner;
95 | }
96 | function stop(runner) {
97 | runner.effect.stop();
98 | }
99 |
100 | var get = createGetter();
101 | var set = createSetter();
102 | var readonlyGet = createGetter(true);
103 | var shallowReactiveGet = createGetter(false, true);
104 | var shallowReadonlyGet = createGetter(true, true);
105 | function createGetter(isReadonly, isShallow) {
106 | if (isReadonly === void 0) { isReadonly = false; }
107 | if (isShallow === void 0) { isShallow = false; }
108 | return function (target, key) {
109 | if (key === "__v_isReactive" /* ReactiveFlags.IS_REACTIVE */) {
110 | return !isReadonly;
111 | }
112 | if (key === "__v_isReadonly" /* ReactiveFlags.IS_READONLY */) {
113 | return isReadonly;
114 | }
115 | var value = Reflect.get(target, key);
116 | if (isObject(value) && !isShallow) {
117 | return isReadonly ? readonly(value) : reactive(value);
118 | }
119 | if (!isReadonly) {
120 | track(target, key);
121 | }
122 | return value;
123 | };
124 | }
125 | function createSetter() {
126 | return function set(target, key, value) {
127 | var oldValue = Reflect.get(target, key);
128 | if (hasChanged(oldValue, value)) {
129 | var result = Reflect.set(target, key, value);
130 | trigger(target, key);
131 | return result;
132 | }
133 | return oldValue;
134 | };
135 | }
136 | var mutableHandlers = {
137 | get: get,
138 | set: set,
139 | };
140 | var shallowMutableHandlers = extend({}, shallowReactiveGet, {
141 | get: shallowReadonlyGet,
142 | });
143 | var readonlyHandlers = {
144 | get: readonlyGet,
145 | set: function (target, key, value) {
146 | console.warn("key: ".concat(key, " set \u5931\u8D25 \u56E0\u4E3A target \u662F readonly"), key);
147 | return true;
148 | },
149 | };
150 | var shallowReadonlyHandlers = extend({}, readonlyHandlers, {
151 | get: shallowReadonlyGet,
152 | });
153 |
154 | function reactive(raw) {
155 | return createActiveObject(raw, mutableHandlers);
156 | }
157 | function readonly(raw) {
158 | return createActiveObject(raw, readonlyHandlers);
159 | }
160 | function shallowReactive(raw) {
161 | return createActiveObject(raw, shallowMutableHandlers);
162 | }
163 | function shallowReadonly(raw) {
164 | return createActiveObject(raw, shallowReadonlyHandlers);
165 | }
166 | function createActiveObject(raw, baseHandlers) {
167 | if (!isObject(raw)) {
168 | console.log("target ".concat(raw, " \u5FC5\u987B\u662F\u4E00\u4E2A\u5BF9\u8C61"));
169 | return raw;
170 | }
171 | return new Proxy(raw, baseHandlers);
172 | }
173 | function isReadonly(value) {
174 | return !!value["__v_isReadonly" /* ReactiveFlags.IS_READONLY */];
175 | }
176 | function isReactive(value) {
177 | return !!value["__v_isReactive" /* ReactiveFlags.IS_REACTIVE */];
178 | }
179 | function isProxy(value) {
180 | return isReactive(value) || isReadonly(value);
181 | }
182 |
183 | var ComputedRefImpl = /** @class */ (function () {
184 | function ComputedRefImpl(getter) {
185 | var _this = this;
186 | this._dirty = true;
187 | this._getter = getter;
188 | this._effect = new ReactiveEffect(getter, function () {
189 | if (!_this._dirty) {
190 | _this._dirty = true;
191 | }
192 | });
193 | }
194 | Object.defineProperty(ComputedRefImpl.prototype, "value", {
195 | get: function () {
196 | if (this._dirty) {
197 | this._dirty = false;
198 | this._value = this._effect.run();
199 | }
200 | return this._value;
201 | },
202 | enumerable: false,
203 | configurable: true
204 | });
205 | return ComputedRefImpl;
206 | }());
207 | function computed(getter) {
208 | return new ComputedRefImpl(getter);
209 | }
210 |
211 | var refImpl = /** @class */ (function () {
212 | function refImpl(value) {
213 | this.__v_ref = true;
214 | this._rawValue = value;
215 | this._value = convert(value);
216 | this.dep = new Set();
217 | }
218 | Object.defineProperty(refImpl.prototype, "value", {
219 | get: function () {
220 | if (activeEffect) {
221 | trackEffects(this.dep);
222 | }
223 | return this._value;
224 | },
225 | set: function (value) {
226 | if (hasChanged(value, this._rawValue)) {
227 | this._rawValue = value;
228 | this._value = convert(value);
229 | triggerEffects(this.dep);
230 | }
231 | },
232 | enumerable: false,
233 | configurable: true
234 | });
235 | return refImpl;
236 | }());
237 | function convert(value) {
238 | return isObject(value) ? reactive(value) : value;
239 | }
240 | function ref(value) {
241 | return new refImpl(value);
242 | }
243 | function isRef(ref) {
244 | return !!ref.__v_ref;
245 | }
246 | function unRef(ref) {
247 | return isRef(ref) ? ref.value : ref;
248 | }
249 | function proxyRefs(objectwithRefs) {
250 | if (objectwithRefs === void 0) { objectwithRefs = {}; }
251 | return new Proxy(objectwithRefs, {
252 | get: function (target, key) {
253 | return unRef(Reflect.get(target, key));
254 | },
255 | set: function (target, key, value) {
256 | if (isRef(target[key]) && !isRef(value)) {
257 | return (target[key].value = value);
258 | }
259 | else {
260 | return Reflect.set(target, key, value);
261 | }
262 | },
263 | });
264 | }
265 |
266 | function emit(instance, event) {
267 | var props = instance.props;
268 | var handlerName = toHandlerKey(camelize(event));
269 | var handler = props[handlerName];
270 | handler && handler();
271 | }
272 |
273 | function initProps(instance, rawProps) {
274 | instance.props = rawProps || {};
275 | }
276 |
277 | var publicPropertiesMap = {
278 | $el: function (i) { return i.vnode.el; },
279 | $slots: function (i) { return i.slots; },
280 | };
281 | var publicInstanceProxyHandlers = {
282 | get: function (_a, key) {
283 | var instance = _a._;
284 | var setupState = instance.setupState, props = instance.props;
285 | if (hasOwn(setupState, key)) {
286 | return setupState[key];
287 | }
288 | if (hasOwn(props, key)) {
289 | return props[key];
290 | }
291 | var publicGetter = publicPropertiesMap[key];
292 | if (publicGetter) {
293 | return publicGetter(instance);
294 | }
295 | },
296 | };
297 |
298 | function initSlots(instance, children) {
299 | instance.slots = children;
300 | }
301 |
302 | var currentInstance = null;
303 | function createComponentInstance(vnode, parentComponent) {
304 | var component = {
305 | vnode: vnode,
306 | type: vnode.type,
307 | setupState: {},
308 | props: {},
309 | slots: {},
310 | provides: {},
311 | isMounted: false,
312 | subTree: {},
313 | parent: parentComponent,
314 | emit: function (instance, event) { },
315 | };
316 | component.emit = emit.bind(null, component);
317 | return component;
318 | }
319 | function setupComponent(instance) {
320 | initProps(instance, instance.vnode.props);
321 | initSlots(instance, instance.vnode.children);
322 | setupStatefulComponent(instance);
323 | }
324 | function setupStatefulComponent(instance) {
325 | var Component = instance.type;
326 | instance.proxy = new Proxy({ _: instance }, publicInstanceProxyHandlers);
327 | var setup = Component.setup;
328 | if (setup) {
329 | setCurrentInstance(instance);
330 | var setupResult = setup(shallowReadonly(instance.props), {
331 | emit: instance.emit,
332 | });
333 | setCurrentInstance(null);
334 | handleSetupResult(instance, proxyRefs(setupResult));
335 | }
336 | }
337 | function handleSetupResult(instance, setupResult) {
338 | if (typeof setupResult === "object") {
339 | // 如果是object那么返回的就是context
340 | instance.setupState = setupResult;
341 | }
342 | finishCompoentSetup(instance);
343 | }
344 | function finishCompoentSetup(instance) {
345 | var Component = instance.type;
346 | instance.render = Component.render;
347 | }
348 | function getCurrentInstance() {
349 | return currentInstance;
350 | }
351 | function setCurrentInstance(instance) {
352 | currentInstance = instance;
353 | }
354 |
355 | var Fragment = Symbol("Fragment");
356 | var Text = Symbol("Text");
357 | function createVNode(type, props, children) {
358 | var vnode = {
359 | type: type,
360 | props: props,
361 | children: children,
362 | shapeFlag: getShapeFlag(type, children),
363 | el: null,
364 | };
365 | return vnode;
366 | }
367 | function createTextVnode(text) {
368 | return createVNode(Text, {}, String(text));
369 | }
370 | function getShapeFlag(type, children) {
371 | var flag = 0;
372 | // 处理 element 和 component 的flag
373 | if (typeof type === "string") {
374 | flag |= 1 /* ShapeFlags.ELEMENT */;
375 | }
376 | else if (type === Text) {
377 | flag |= 4 /* ShapeFlags.TEXT_CHILDREN */;
378 | }
379 | else {
380 | flag |= 2 /* ShapeFlags.STATEFUL_COMPONENT */;
381 | }
382 | // 处理 children 的flag
383 | if (Array.isArray(children)) {
384 | flag |= 8 /* ShapeFlags.ARRAY_CHILDREN */;
385 | }
386 | else if (typeof children === "string") {
387 | flag |= 4 /* ShapeFlags.TEXT_CHILDREN */;
388 | }
389 | return flag;
390 | }
391 |
392 | function createAppApi(render) {
393 | return function createApp(rootComponent) {
394 | return {
395 | mount: function (rootContainer) {
396 | var vnode = createVNode(rootComponent);
397 | render(vnode, rootContainer);
398 | },
399 | };
400 | };
401 | }
402 |
403 | function createRender(options) {
404 | var createTextNode = options.createTextNode, insert = options.insert, createElement = options.createElement, hostPatchProps = options.hostPatchProps, setElementInnerContext = options.setElementInnerContext, removeAllChildren = options.removeAllChildren;
405 | function render(vnode, rootContainer) {
406 | patch(null, vnode, rootContainer, null);
407 | }
408 | function patch(n1, n2, container, parentComponent) {
409 | var type = n2.type, shapeFlag = n2.shapeFlag;
410 | switch (type) {
411 | case Fragment:
412 | processFragment(n1, n2, container);
413 | break;
414 | case Text:
415 | processText(n1, n2, container);
416 | break;
417 | default:
418 | if (shapeFlag & 2 /* ShapeFlags.STATEFUL_COMPONENT */) {
419 | // vnode 是一个component
420 | // h(App,{},[])
421 | processComponent(n1, n2, container, parentComponent);
422 | }
423 | else if (shapeFlag & 1 /* ShapeFlags.ELEMENT */) {
424 | // vnode 是一个element
425 | // h('div',{class:'red'},null)
426 | processElement(n1, n2, container, parentComponent);
427 | }
428 | else {
429 | // vnode 不是component 和 element 那就可能是一个文本节点
430 | // h('div',{},[h('p',{},null),'222',this.msg])
431 | insert(createTextNode(n2), container);
432 | }
433 | }
434 | }
435 | function processText(n1, n2, container) {
436 | var children = n2.children;
437 | var textNode = (n2.el = createTextNode(children));
438 | insert(textNode, container);
439 | }
440 | function processFragment(n1, n2, container) {
441 | mountChildren(n2.children, container, null);
442 | }
443 | function processElement(n1, n2, container, parentComponent) {
444 | if (!n1) {
445 | mountElement(n2, container, parentComponent);
446 | }
447 | else {
448 | updateElement(n1, n2);
449 | }
450 | }
451 | function updateElement(n1, n2, container) {
452 | var oldProps = n1.props || EMPTY_OBJ;
453 | var newProps = n2.props || EMPTY_OBJ;
454 | var el = (n2.el = n1.el);
455 | // 对比props
456 | patchProps(el, oldProps, newProps);
457 | // 对比children
458 | patchChildren(n1, n2, el);
459 | }
460 | function patchChildren(n1, n2, container) {
461 | // n1 children 是文本节点
462 | if (!!(n1.shapeFlag & 4 /* ShapeFlags.TEXT_CHILDREN */)) {
463 | if (!!(n2.shapeFlag & 8 /* ShapeFlags.ARRAY_CHILDREN */)) {
464 | // text children => array children
465 | removeAllChildren(container);
466 | mountChildren(n2.children, container, null);
467 | }
468 | else {
469 | // text children => text children
470 | if (n1.children !== n2.children) {
471 | setElementInnerContext(container, n2.children);
472 | }
473 | }
474 | }
475 | else {
476 | // n1 children 是一个数组
477 | if (!!(n2.shapeFlag & 8 /* ShapeFlags.ARRAY_CHILDREN */)) ;
478 | else {
479 | // array children => text children
480 | removeAllChildren(container);
481 | setElementInnerContext(container, n2.children);
482 | }
483 | }
484 | }
485 | function patchProps(el, oldProps, newProps) {
486 | if (oldProps !== newProps) {
487 | for (var key in newProps) {
488 | var prevProp = oldProps[key];
489 | var nextProp = newProps[key];
490 | if (prevProp !== nextProp) {
491 | hostPatchProps(el, key, prevProp, nextProp);
492 | }
493 | }
494 | if (oldProps !== EMPTY_OBJ) {
495 | for (var key in oldProps) {
496 | if (!(key in newProps)) {
497 | hostPatchProps(el, key, oldProps[key], null);
498 | }
499 | }
500 | }
501 | }
502 | }
503 | function mountElement(vnode, container, parentComponent) {
504 | var type = vnode.type, children = vnode.children, props = vnode.props, shapeFlag = vnode.shapeFlag;
505 | var el = (vnode.el = createElement(type));
506 | //children
507 | if (shapeFlag & 8 /* ShapeFlags.ARRAY_CHILDREN */) {
508 | mountChildren(children, el, parentComponent);
509 | }
510 | else if (!!(children.shapeFlag & 4 /* ShapeFlags.TEXT_CHILDREN */)) {
511 | var vlaue = children.children;
512 | insert(createTextNode(vlaue), el);
513 | }
514 | else {
515 | setElementInnerContext(el, children);
516 | }
517 | // props
518 | for (var key in props) {
519 | var val = props[key];
520 | hostPatchProps(el, key, null, val);
521 | }
522 | insert(el, container);
523 | }
524 | function mountChildren(children, container, parentComponent) {
525 | children.forEach(function (child) {
526 | patch(null, child, container, parentComponent);
527 | });
528 | }
529 | function processComponent(n1, n2, container, parentComponent) {
530 | mountComponent(n2, container, parentComponent);
531 | }
532 | function mountComponent(initinalVNode, container, parentComponent) {
533 | var instance = createComponentInstance(initinalVNode, parentComponent);
534 | setupComponent(instance);
535 | setupRenderEffect(instance, container);
536 | }
537 | function setupRenderEffect(instance, container) {
538 | effect(function () {
539 | var proxy = instance.proxy;
540 | if (!instance.isMounted) {
541 | console.log("init");
542 | var subTree = (instance.subTree = instance.render.call(proxy));
543 | patch(null, subTree, container, instance);
544 | instance.vnode.el = subTree.el;
545 | instance.isMounted = true;
546 | }
547 | else {
548 | console.log("update");
549 | var subTree = instance.render.call(proxy);
550 | var preSubTree = instance.subTree;
551 | instance.vnode.el = subTree.el;
552 | patch(preSubTree, subTree, container, instance);
553 | }
554 | });
555 | }
556 | return {
557 | createApp: createAppApi(render),
558 | };
559 | }
560 |
561 | function h(type, props, children) {
562 | return createVNode(type, props, children);
563 | }
564 |
565 | function renderSlots(slots, name, props) {
566 | var slot = slots[name];
567 | if (slot) {
568 | if (typeof slot === "function") {
569 | return createVNode(Fragment, {}, handleSlotChilren(slot(props)));
570 | }
571 | }
572 | }
573 | function handleSlotChilren(slot) {
574 | return Array.isArray(slot) ? slot : [slot];
575 | }
576 |
577 | function provide(key, value) {
578 | var instance = getCurrentInstance();
579 | if (instance) {
580 | var provides = instance.provides;
581 | provides[key] = value;
582 | }
583 | }
584 | function inject(key) {
585 | var instance = getCurrentInstance();
586 | if (instance) {
587 | var value = null;
588 | while (value === null) {
589 | var parent_1 = instance.parent;
590 | if (parent_1) {
591 | if (parent_1.provides[key]) {
592 | return parent_1.provides[key];
593 | }
594 | }
595 | }
596 | }
597 | }
598 |
599 | function createTextNode(text) {
600 | return document.createTextNode(text);
601 | }
602 | function insert(child, container) {
603 | container.appendChild(child);
604 | }
605 | function createElement(type) {
606 | return document.createElement(type);
607 | }
608 | function patchProps(el, key, prevVal, nextVal) {
609 | var isOn = function (key) { return /^on[A-Z]*/.test(key); };
610 | // event
611 | if (isOn(key)) {
612 | var event_1 = key.slice(2).toLocaleLowerCase();
613 | el.addEventListener(event_1, nextVal);
614 | }
615 | else {
616 | // attribute
617 | if (nextVal === undefined || nextVal === null) {
618 | el.removeAttribute(key);
619 | }
620 | else {
621 | el.setAttribute(key, nextVal);
622 | }
623 | }
624 | }
625 | function setElementInnerContext(el, context) {
626 | el.textContent = context;
627 | }
628 | function removeAllChildren(el) {
629 | el.innerHTML = "";
630 | }
631 | var renderer = createRender({
632 | createTextNode: createTextNode,
633 | insert: insert,
634 | createElement: createElement,
635 | hostPatchProps: patchProps,
636 | setElementInnerContext: setElementInnerContext,
637 | removeAllChildren: removeAllChildren,
638 | });
639 | function createApp(rootComponent) {
640 | return renderer.createApp(rootComponent);
641 | }
642 |
643 | export { ReactiveEffect, activeEffect, cleanupEffect, computed, createApp, createTextVnode, effect, getCurrentInstance, h, inject, isProxy, isReactive, isReadonly, isRef, provide, proxyRefs, reactive, readonly, ref, renderSlots, shallowReactive, shallowReadonly, stop, track, trackEffects, trigger, triggerEffects, unRef };
644 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "mini-vue3",
3 | "version": "1.0.0",
4 | "description": "",
5 | "main": "lib/guide-mini-vue3.cjs.js",
6 | "module": "lib/guide-mini-vue3.esm.js",
7 | "scripts": {
8 | "test": "jest",
9 | "build": "rollup -c rollup.config.js"
10 | },
11 | "keywords": [],
12 | "author": "",
13 | "license": "ISC",
14 | "dependencies": {
15 | "@rollup/plugin-node-resolve": "^13.1.3",
16 | "@rollup/plugin-typescript": "^8.3.0"
17 | },
18 | "devDependencies": {
19 | "@babel/core": "^7.17.5",
20 | "@babel/preset-env": "^7.16.11",
21 | "@babel/preset-typescript": "^7.16.7",
22 | "@types/jest": "^27.4.0",
23 | "babel-jest": "^27.5.1",
24 | "jest": "^27.5.1",
25 | "rollup": "^2.68.0",
26 | "tslib": "^2.3.1",
27 | "typescript": "^4.5.5"
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/packages/index.ts:
--------------------------------------------------------------------------------
1 | export * from "./reactivity/src"
2 | export * from "./runtime-dom"
3 |
--------------------------------------------------------------------------------
/packages/reactivity/__test__/computed.spec.ts:
--------------------------------------------------------------------------------
1 | import { computed } from "../src/computed"
2 | import { reactive } from "../src/reactive"
3 | describe("reactivity/computed", () => {
4 | it("should when get", () => {
5 | const state: any = reactive({ count: 1 })
6 | const double = computed(() => state.count * 2)
7 | expect(double.value).toBe(2)
8 | })
9 |
10 | it("should compute lazily", () => {
11 | const value: any = reactive({
12 | foo: 1,
13 | })
14 | const getter = jest.fn(() => value.foo)
15 | const cValue = computed(getter)
16 |
17 | // lazy
18 | expect(getter).not.toHaveBeenCalled()
19 |
20 | expect(cValue.value).toBe(1)
21 | expect(getter).toHaveBeenCalledTimes(1)
22 |
23 | // should not compute again
24 | cValue.value
25 | expect(getter).toHaveBeenCalledTimes(1)
26 |
27 | // // should not compute until needed
28 | value.foo = 2
29 | expect(getter).toHaveBeenCalledTimes(1)
30 |
31 | // now it should compute
32 | expect(cValue.value).toBe(2)
33 | expect(getter).toHaveBeenCalledTimes(2)
34 |
35 | // should not compute again
36 | cValue.value
37 | expect(getter).toHaveBeenCalledTimes(2)
38 | })
39 | })
40 |
--------------------------------------------------------------------------------
/packages/reactivity/__test__/effect.spec.ts:
--------------------------------------------------------------------------------
1 | import { reactive } from "../src/reactive"
2 | import { effect, stop } from "../src/effect"
3 |
4 | describe("reactivity/effect", () => {
5 | it("should observe basic properties", () => {
6 | const counter: any = reactive({ num: 1 })
7 | let dummy
8 |
9 | effect(function () {
10 | dummy = counter.num
11 | })
12 |
13 | expect(dummy).toBe(1)
14 |
15 | // update
16 | counter.num++
17 | expect(dummy).toBe(2)
18 | })
19 |
20 | it("should return runner when call effect", () => {
21 | let foo = 10
22 | const runner = effect(() => {
23 | foo++
24 | return "foo"
25 | })
26 | expect(foo).toBe(11)
27 | const r = runner()
28 | expect(foo).toBe(12)
29 | expect(r).toBe("foo")
30 | })
31 |
32 | it("scheduler", () => {
33 | let dummy
34 | let run: any
35 | const scheduler = jest.fn(() => {
36 | run = runner
37 | })
38 | const obj: any = reactive({ foo: 1 })
39 | const runner = effect(
40 | () => {
41 | dummy = obj.foo
42 | },
43 | { scheduler }
44 | )
45 | expect(scheduler).not.toHaveBeenCalled()
46 | expect(dummy).toBe(1)
47 | // should be called on first trigger
48 | obj.foo++
49 | expect(scheduler).toHaveBeenCalledTimes(1)
50 | // should not run yet
51 | expect(dummy).toBe(1)
52 | // manually run
53 | run()
54 | // should have run
55 | expect(dummy).toBe(2)
56 | })
57 |
58 | it("stop", () => {
59 | let dummy
60 | let a
61 | const obj: any = reactive({ prop: 1, a: 1 })
62 | const runner = effect(() => {
63 | dummy = obj.prop
64 | })
65 | obj.prop = 2
66 | expect(dummy).toBe(2)
67 | stop(runner)
68 | obj.prop++
69 | expect(dummy).toBe(2)
70 |
71 | // stopped effect should still be manually callable
72 | runner()
73 | expect(dummy).toBe(3)
74 | })
75 |
76 | it("events: onStop", () => {
77 | const onStop = jest.fn()
78 | const runner = effect(() => {}, {
79 | onStop,
80 | })
81 |
82 | stop(runner)
83 | expect(onStop).toBeCalledTimes(1)
84 | })
85 | })
86 |
--------------------------------------------------------------------------------
/packages/reactivity/__test__/reactive.spec.ts:
--------------------------------------------------------------------------------
1 | import { isReactive, shallowReactive, isProxy, reactive } from "../src"
2 |
3 | describe("reactivity/reactive", () => {
4 | test("Object", () => {
5 | const original = { foo: 1 }
6 | const observed: any = reactive(original)
7 | expect(observed).not.toBe(original)
8 |
9 | // get
10 | expect(observed.foo).toBe(1)
11 |
12 | // set
13 | observed.foo = 2
14 | expect(original.foo).toBe(2)
15 | })
16 |
17 | it("should make nested values reactive", () => {
18 | const obj = {
19 | foo: {
20 | bar: 1,
21 | },
22 | }
23 | const wrapped: any = reactive(obj)
24 | expect(isReactive(obj)).toBe(false)
25 | expect(isReactive(wrapped)).toBe(true)
26 | expect(isReactive(obj.foo)).toBe(false)
27 | expect(isReactive(wrapped.foo)).toBe(true)
28 | expect(isProxy(obj)).toBe(false)
29 | expect(isProxy(obj.foo)).toBe(false)
30 | expect(isProxy(wrapped)).toBe(true)
31 | expect(isProxy(wrapped.foo)).toBe(true)
32 | })
33 |
34 | it("should make shallow values reactive", () => {
35 | const obj = {
36 | foo: {
37 | bar: 1,
38 | },
39 | }
40 | const wrapped: any = shallowReactive(obj)
41 | expect(isReactive(wrapped.foo)).toBe(false)
42 | })
43 | })
44 |
--------------------------------------------------------------------------------
/packages/reactivity/__test__/readonly.spec.ts:
--------------------------------------------------------------------------------
1 | import { readonly, isReadonly, shallowReadonly, isProxy } from "../src"
2 | describe("reactivity/readonly", () => {
3 | it("should when get", () => {
4 | const original = { foo: 1, bar: { baz: 2 } }
5 | const wrapped: any = readonly(original)
6 | expect(wrapped).not.toBe(original)
7 | expect(wrapped.foo).toBe(1)
8 | })
9 | it("should not set when set", () => {
10 | console.warn = jest.fn()
11 |
12 | const user: any = readonly({
13 | age: 10,
14 | })
15 |
16 | user.age = 11
17 |
18 | expect(console.warn).toBeCalled()
19 | })
20 |
21 | it("should make nested values readonly", () => {
22 | const obj = {
23 | foo: {
24 | bar: 1,
25 | },
26 | }
27 | const wrapped: any = readonly(obj)
28 | expect(isReadonly(obj)).toBe(false)
29 | expect(isReadonly(wrapped)).toBe(true)
30 | expect(isReadonly(obj.foo)).toBe(false)
31 | expect(isReadonly(wrapped.foo)).toBe(true)
32 | expect(isProxy(obj)).toBe(false)
33 | expect(isProxy(obj.foo)).toBe(false)
34 | expect(isProxy(wrapped)).toBe(true)
35 | expect(isProxy(wrapped.foo)).toBe(true)
36 | })
37 |
38 | it("should make shallow values readonly", () => {
39 | const obj = {
40 | foo: {
41 | bar: 1,
42 | },
43 | }
44 | const wrapped: any = shallowReadonly(obj)
45 | expect(isReadonly(wrapped.foo)).toBe(false)
46 | })
47 | })
48 |
--------------------------------------------------------------------------------
/packages/reactivity/__test__/ref.spec.ts:
--------------------------------------------------------------------------------
1 | import { ref, effect, isRef, unRef, proxyRefs } from "../src"
2 | describe("ractivity/ref", () => {
3 | it("should hold a value", () => {
4 | const a = ref(1)
5 | expect(a.value).toBe(1)
6 | a.value = 2
7 | expect(a.value).toBe(2)
8 | })
9 |
10 | it("should be reactive", () => {
11 | const a = ref(1)
12 | let dummy
13 | let calls = 0
14 | effect(() => {
15 | calls++
16 | dummy = a.value
17 | })
18 | expect(calls).toBe(1)
19 | expect(dummy).toBe(1)
20 | a.value = 2
21 | expect(calls).toBe(2)
22 | expect(dummy).toBe(2)
23 | // same value should not trigger
24 | a.value = 2
25 | expect(calls).toBe(2)
26 | })
27 |
28 | it("should make nested properties reactive", () => {
29 | const a = ref({
30 | count: 1,
31 | })
32 | let dummy
33 | effect(() => {
34 | dummy = a.value.count
35 | })
36 | expect(dummy).toBe(1)
37 | a.value.count = 2
38 | expect(dummy).toBe(2)
39 | a.value = {
40 | count: 10,
41 | }
42 | expect(dummy).toBe(10)
43 | })
44 |
45 | it("isRef", () => {
46 | const a = ref(0)
47 | expect(isRef(a)).toBe(true)
48 | expect(isRef(1)).toBe(false)
49 | })
50 |
51 | it("unRef", () => {
52 | const a = ref(1)
53 | expect(unRef(a)).toBe(1)
54 | expect(unRef(1)).toBe(1)
55 | })
56 |
57 | it("proxyRefs", () => {
58 | const user = {
59 | age: ref(18),
60 | name: "lisi",
61 | }
62 | const proxyUser = proxyRefs(user)
63 | expect(user.age.value).toBe(18)
64 | expect(proxyUser.age).toBe(18)
65 | expect(proxyUser.name).toBe("lisi")
66 | proxyUser.age = 20
67 | expect(proxyUser.age).toBe(20)
68 | expect(user.age.value).toBe(20)
69 | proxyUser.age = ref(10)
70 | expect(proxyUser.age).toBe(10)
71 | expect(user.age.value).toBe(10)
72 | })
73 | })
74 |
--------------------------------------------------------------------------------
/packages/reactivity/src/baseHandlers.ts:
--------------------------------------------------------------------------------
1 | import { track, trigger } from "./effect"
2 | import { ReactiveFlags, readonly, reactive } from "./reactive"
3 | import { isObject, extend, hasChanged } from "../../shared"
4 |
5 | const get = createGetter()
6 | const set = createSetter()
7 | const readonlyGet = createGetter(true)
8 | const shallowReactiveGet = createGetter(false, true)
9 | const shallowReadonlyGet = createGetter(true, true)
10 |
11 | export function createGetter(isReadonly = false, isShallow = false) {
12 | return function (target: object, key: string) {
13 | if (key === ReactiveFlags.IS_REACTIVE) {
14 | return !isReadonly
15 | }
16 | if (key === ReactiveFlags.IS_READONLY) {
17 | return isReadonly
18 | }
19 |
20 | const value = Reflect.get(target, key)
21 |
22 | if (isObject(value) && !isShallow) {
23 | return isReadonly ? readonly(value) : reactive(value)
24 | }
25 |
26 | if (!isReadonly) {
27 | track(target, key)
28 | }
29 | return value
30 | }
31 | }
32 |
33 | export function createSetter() {
34 | return function set(target: object, key: string, value: any) {
35 | const oldValue = Reflect.get(target, key)
36 | if (hasChanged(oldValue, value)) {
37 | const result = Reflect.set(target, key, value)
38 | trigger(target, key)
39 | return result
40 | }
41 | return oldValue
42 | }
43 | }
44 |
45 | export const mutableHandlers = {
46 | get,
47 | set,
48 | }
49 |
50 | export const shallowMutableHandlers = extend({}, shallowReactiveGet, {
51 | get: shallowReadonlyGet,
52 | })
53 |
54 | export const readonlyHandlers = {
55 | get: readonlyGet,
56 | set(target, key, value) {
57 | console.warn(`key: ${key} set 失败 因为 target 是 readonly`, key)
58 | return true
59 | },
60 | }
61 |
62 | export const shallowReadonlyHandlers = extend({}, readonlyHandlers, {
63 | get: shallowReadonlyGet,
64 | })
65 |
--------------------------------------------------------------------------------
/packages/reactivity/src/computed.ts:
--------------------------------------------------------------------------------
1 | import { ReactiveEffect } from "./effect"
2 |
3 | class ComputedRefImpl {
4 | _getter: any
5 | _dirty: boolean = true
6 | private _value: any
7 | private _effect: ReactiveEffect
8 | constructor(getter) {
9 | this._getter = getter
10 | this._effect = new ReactiveEffect(getter, () => {
11 | if (!this._dirty) {
12 | this._dirty = true
13 | }
14 | })
15 | }
16 | get value() {
17 | if (this._dirty) {
18 | this._dirty = false
19 | this._value = this._effect.run()
20 | }
21 | return this._value
22 | }
23 | }
24 |
25 | export function computed(getter) {
26 | return new ComputedRefImpl(getter)
27 | }
28 |
--------------------------------------------------------------------------------
/packages/reactivity/src/effect.ts:
--------------------------------------------------------------------------------
1 | import { extend } from "../../shared"
2 |
3 | export let activeEffect: any
4 | const targetMap = new WeakMap()
5 |
6 | export function track(target: Object, key: string) {
7 | if (!activeEffect) {
8 | return
9 | }
10 |
11 | let depsMap = targetMap.get(target)
12 | if (!depsMap) {
13 | depsMap = new Map()
14 | targetMap.set(target, depsMap)
15 | }
16 |
17 | let dep = depsMap.get(key)
18 | if (!dep) {
19 | dep = new Set()
20 | depsMap.set(key, dep)
21 | }
22 |
23 | trackEffects(dep)
24 | }
25 |
26 | export function trackEffects(dep: any) {
27 | dep.add(activeEffect)
28 | activeEffect.deps.push(dep)
29 | }
30 |
31 | export function trigger(target: Object, key: string) {
32 | let depsMap = targetMap.get(target)
33 | if (!depsMap) {
34 | return
35 | }
36 |
37 | let dep = depsMap.get(key)
38 | if (!dep) {
39 | return
40 | }
41 | triggerEffects(dep)
42 | }
43 |
44 | export function triggerEffects(dep: any) {
45 | dep.forEach((effect) => {
46 | if (effect.scheduler) {
47 | effect.scheduler()
48 | } else {
49 | effect.run()
50 | }
51 | })
52 | }
53 |
54 | export class ReactiveEffect {
55 | deps: any = []
56 | active = true
57 | onStop: (() => void) | undefined
58 | constructor(public _fn: Function, public scheduler?: () => any) {
59 | activeEffect = this
60 | }
61 | run() {
62 | return this._fn()
63 | }
64 | stop() {
65 | if (this.active) {
66 | cleanupEffect(this)
67 | if (this.onStop) {
68 | this.onStop()
69 | }
70 | this.active = false
71 | }
72 | }
73 | }
74 |
75 | export function cleanupEffect(effect) {
76 | effect.deps.forEach((dep: any) => {
77 | dep.delete(effect)
78 | })
79 | effect.deps.length = 0
80 | }
81 |
82 | export function effect(fn: Function, options?) {
83 | const _effect = new ReactiveEffect(fn)
84 |
85 | if (options) {
86 | extend(_effect, options)
87 | }
88 |
89 | _effect.run()
90 | activeEffect = null
91 | const runner: any = _effect.run.bind(_effect)
92 | runner.effect = _effect
93 | return runner
94 | }
95 |
96 | export function stop(runner) {
97 | runner.effect.stop()
98 | }
99 |
--------------------------------------------------------------------------------
/packages/reactivity/src/index.ts:
--------------------------------------------------------------------------------
1 | export * from "./reactive"
2 | export * from "./computed"
3 | export * from "./effect"
4 | export * from "./ref"
5 |
--------------------------------------------------------------------------------
/packages/reactivity/src/reactive.ts:
--------------------------------------------------------------------------------
1 | import { isObject } from "../../shared"
2 | import {
3 | mutableHandlers,
4 | readonlyHandlers,
5 | shallowMutableHandlers,
6 | shallowReadonlyHandlers,
7 | } from "./baseHandlers"
8 |
9 | export const enum ReactiveFlags {
10 | IS_REACTIVE = "__v_isReactive",
11 | IS_READONLY = "__v_isReadonly",
12 | }
13 |
14 | export function reactive(raw: object) {
15 | return createActiveObject(raw, mutableHandlers)
16 | }
17 |
18 | export function readonly(raw: object) {
19 | return createActiveObject(raw, readonlyHandlers)
20 | }
21 |
22 | export function shallowReactive(raw) {
23 | return createActiveObject(raw, shallowMutableHandlers)
24 | }
25 | export function shallowReadonly(raw) {
26 | return createActiveObject(raw, shallowReadonlyHandlers)
27 | }
28 |
29 | function createActiveObject(raw: object, baseHandlers: object) {
30 | if (!isObject(raw)) {
31 | console.log(`target ${raw} 必须是一个对象`)
32 | return raw
33 | }
34 | return new Proxy(raw, baseHandlers)
35 | }
36 |
37 | export function isReadonly(value: any): boolean {
38 | return !!value[ReactiveFlags.IS_READONLY]
39 | }
40 |
41 | export function isReactive(value: any): boolean {
42 | return !!value[ReactiveFlags.IS_REACTIVE]
43 | }
44 |
45 | export function isProxy(value: any): boolean {
46 | return isReactive(value) || isReadonly(value)
47 | }
48 |
--------------------------------------------------------------------------------
/packages/reactivity/src/ref.ts:
--------------------------------------------------------------------------------
1 | import { trackEffects, triggerEffects, activeEffect } from "./effect"
2 | import { hasChanged, isObject } from "../../shared"
3 | import { reactive } from "./reactive"
4 |
5 | class refImpl {
6 | private _value: any
7 | public _rawValue: any
8 | public __v_ref: boolean = true
9 | public dep
10 | constructor(value) {
11 | this._rawValue = value
12 | this._value = convert(value)
13 | this.dep = new Set()
14 | }
15 |
16 | get value() {
17 | if (activeEffect) {
18 | trackEffects(this.dep)
19 | }
20 | return this._value
21 | }
22 |
23 | set value(value) {
24 | if (hasChanged(value, this._rawValue)) {
25 | this._rawValue = value
26 | this._value = convert(value)
27 | triggerEffects(this.dep)
28 | }
29 | }
30 | }
31 |
32 | function convert(value) {
33 | return isObject(value) ? reactive(value) : value
34 | }
35 |
36 | export function ref(value) {
37 | return new refImpl(value)
38 | }
39 |
40 | export function isRef(ref) {
41 | return !!ref.__v_ref
42 | }
43 |
44 | export function unRef(ref) {
45 | return isRef(ref) ? ref.value : ref
46 | }
47 |
48 | export function proxyRefs(objectwithRefs = {}) {
49 | return new Proxy(objectwithRefs, {
50 | get(target, key) {
51 | return unRef(Reflect.get(target, key))
52 | },
53 | set(target, key, value) {
54 | if (isRef(target[key]) && !isRef(value)) {
55 | return (target[key].value = value)
56 | } else {
57 | return Reflect.set(target, key, value)
58 | }
59 | },
60 | })
61 | }
62 |
--------------------------------------------------------------------------------
/packages/runtime-core/src/apiInject.ts:
--------------------------------------------------------------------------------
1 | import { getCurrentInstance } from "./component"
2 |
3 | export function provide(key, value) {
4 | const instance = getCurrentInstance()
5 |
6 | if (instance) {
7 | const { provides } = instance
8 | provides[key] = value
9 | }
10 | }
11 |
12 | export function inject(key) {
13 | const instance = getCurrentInstance()
14 |
15 | if (instance) {
16 | let value = null
17 | while (value === null) {
18 | const { parent } = instance
19 | if (parent) {
20 | if (parent.provides[key]) {
21 | return parent.provides[key]
22 | }
23 | }
24 | }
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/packages/runtime-core/src/component.ts:
--------------------------------------------------------------------------------
1 | import { proxyRefs } from "../../reactivity/src"
2 | import { shallowReadonly } from "../../reactivity/src/reactive"
3 | import { emit } from "./componentEmit"
4 | import { initProps } from "./componentProps"
5 | import { publicInstanceProxyHandlers } from "./componentPublicInstance"
6 | import { initSlots } from "./componentSlots"
7 |
8 | let currentInstance: any = null
9 |
10 | export function createComponentInstance(vnode, parentComponent) {
11 | const component = {
12 | vnode,
13 | type: vnode.type,
14 | setupState: {},
15 | props: {},
16 | slots: {},
17 | provides: {},
18 | isMounted: false,
19 | subTree: {},
20 | parent: parentComponent,
21 | emit: (instance, event) => {},
22 | }
23 |
24 | component.emit = emit.bind(null, component)
25 |
26 | return component
27 | }
28 |
29 | export function setupComponent(instance) {
30 | initProps(instance, instance.vnode.props)
31 | initSlots(instance, instance.vnode.children)
32 | setupStatefulComponent(instance)
33 | }
34 |
35 | function setupStatefulComponent(instance) {
36 | const Component = instance.type
37 |
38 | instance.proxy = new Proxy({ _: instance }, publicInstanceProxyHandlers)
39 |
40 | const { setup } = Component
41 | if (setup) {
42 | setCurrentInstance(instance)
43 | const setupResult = setup(shallowReadonly(instance.props), {
44 | emit: instance.emit,
45 | })
46 | setCurrentInstance(null)
47 | handleSetupResult(instance, proxyRefs(setupResult))
48 | }
49 | }
50 |
51 | function handleSetupResult(instance, setupResult) {
52 | if (typeof setupResult === "object") {
53 | // 如果是object那么返回的就是context
54 | instance.setupState = setupResult
55 | } else if (typeof setupResult === "function") {
56 | // 如果是function那么返回的是render函数
57 | }
58 | finishCompoentSetup(instance)
59 | }
60 |
61 | function finishCompoentSetup(instance) {
62 | const Component = instance.type
63 | instance.render = Component.render
64 | }
65 |
66 | export function getCurrentInstance() {
67 | return currentInstance
68 | }
69 |
70 | function setCurrentInstance(instance) {
71 | currentInstance = instance
72 | }
73 |
--------------------------------------------------------------------------------
/packages/runtime-core/src/componentEmit.ts:
--------------------------------------------------------------------------------
1 | import { camelize, toHandlerKey } from "../../shared"
2 |
3 | export function emit(instance, event) {
4 | const { props } = instance
5 |
6 | const handlerName = toHandlerKey(camelize(event))
7 | const handler = props[handlerName]
8 | handler && handler()
9 | }
10 |
--------------------------------------------------------------------------------
/packages/runtime-core/src/componentProps.ts:
--------------------------------------------------------------------------------
1 | export function initProps(instance, rawProps) {
2 | instance.props = rawProps || {}
3 | }
4 |
--------------------------------------------------------------------------------
/packages/runtime-core/src/componentPublicInstance.ts:
--------------------------------------------------------------------------------
1 | import { hasOwn } from "../../shared"
2 |
3 | const publicPropertiesMap = {
4 | $el: (i) => i.vnode.el,
5 | $slots: (i) => i.slots,
6 | }
7 |
8 | export const publicInstanceProxyHandlers = {
9 | get({ _: instance }, key) {
10 | const { setupState, props } = instance
11 | if (hasOwn(setupState, key)) {
12 | return setupState[key]
13 | }
14 |
15 | if (hasOwn(props, key)) {
16 | return props[key]
17 | }
18 |
19 | const publicGetter = publicPropertiesMap[key]
20 | if (publicGetter) {
21 | return publicGetter(instance)
22 | }
23 | },
24 | }
25 |
--------------------------------------------------------------------------------
/packages/runtime-core/src/componentSlots.ts:
--------------------------------------------------------------------------------
1 | export function initSlots(instance, children) {
2 | instance.slots = children
3 | }
4 |
--------------------------------------------------------------------------------
/packages/runtime-core/src/createApp.ts:
--------------------------------------------------------------------------------
1 | import { createVNode } from "./vnode"
2 |
3 | export function createAppApi(render) {
4 | return function createApp(rootComponent: any) {
5 | return {
6 | mount(rootContainer) {
7 | const vnode = createVNode(rootComponent)
8 |
9 | render(vnode, rootContainer)
10 | },
11 | }
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/packages/runtime-core/src/h.ts:
--------------------------------------------------------------------------------
1 | import { createVNode } from "./vnode"
2 |
3 | export function h(type, props?, children?) {
4 | return createVNode(type, props, children)
5 | }
6 |
--------------------------------------------------------------------------------
/packages/runtime-core/src/helpers/renderSlots.ts:
--------------------------------------------------------------------------------
1 | import { createVNode, Fragment } from "../vnode"
2 |
3 | export function renderSlots(slots, name, props) {
4 | const slot = slots[name]
5 | if (slot) {
6 | if (typeof slot === "function") {
7 | return createVNode(Fragment, {}, handleSlotChilren(slot(props)))
8 | }
9 | }
10 | }
11 |
12 | function handleSlotChilren(slot) {
13 | return Array.isArray(slot) ? slot : [slot]
14 | }
15 |
--------------------------------------------------------------------------------
/packages/runtime-core/src/index.ts:
--------------------------------------------------------------------------------
1 | export { h } from "./h"
2 | export { createTextVnode } from "./vnode"
3 | export { getCurrentInstance } from "./component"
4 | export { renderSlots } from "./helpers/renderSlots"
5 | export { provide, inject } from "./apiInject"
6 |
--------------------------------------------------------------------------------
/packages/runtime-core/src/renderer.ts:
--------------------------------------------------------------------------------
1 | import { effect } from "../../reactivity/src"
2 | import { EMPTY_OBJ } from "../../shared"
3 | import { ShapeFlags } from "../../shared/shapeFlags"
4 | import { createComponentInstance, setupComponent } from "./component"
5 | import { createAppApi } from "./createApp"
6 | import { Fragment, Text } from "./vnode"
7 |
8 | export function createRender(options) {
9 | const {
10 | createTextNode,
11 | insert,
12 | createElement,
13 | hostPatchProps,
14 | setElementInnerContext,
15 | removeAllChildren,
16 | } = options
17 | function render(vnode, rootContainer) {
18 | patch(null, vnode, rootContainer, null)
19 | }
20 |
21 | function patch(n1, n2, container, parentComponent) {
22 | const { type, shapeFlag } = n2
23 |
24 | switch (type) {
25 | case Fragment:
26 | processFragment(n1, n2, container)
27 | break
28 | case Text:
29 | processText(n1, n2, container)
30 | break
31 | default:
32 | if (shapeFlag & ShapeFlags.STATEFUL_COMPONENT) {
33 | // vnode 是一个component
34 | // h(App,{},[])
35 | processComponent(n1, n2, container, parentComponent)
36 | } else if (shapeFlag & ShapeFlags.ELEMENT) {
37 | // vnode 是一个element
38 | // h('div',{class:'red'},null)
39 | processElement(n1, n2, container, parentComponent)
40 | } else {
41 | // vnode 不是component 和 element 那就可能是一个文本节点
42 | // h('div',{},[h('p',{},null),'222',this.msg])
43 | insert(createTextNode(n2), container)
44 | }
45 | }
46 | }
47 |
48 | function processText(n1, n2, container) {
49 | const { children } = n2
50 | const textNode = (n2.el = createTextNode(children))
51 | insert(textNode, container)
52 | }
53 |
54 | function processFragment(n1, n2, container) {
55 | mountChildren(n2.children, container, null)
56 | }
57 |
58 | function processElement(n1, n2, container, parentComponent) {
59 | if (!n1) {
60 | mountElement(n2, container, parentComponent)
61 | } else {
62 | updateElement(n1, n2, container)
63 | }
64 | }
65 |
66 | function updateElement(n1, n2, container) {
67 | const oldProps = n1.props || EMPTY_OBJ
68 | const newProps = n2.props || EMPTY_OBJ
69 |
70 | const el = (n2.el = n1.el)
71 |
72 | // 对比props
73 | patchProps(el, oldProps, newProps)
74 |
75 | // 对比children
76 | patchChildren(n1, n2, el)
77 | }
78 |
79 | function patchChildren(n1, n2, container) {
80 | // n1 children 是文本节点
81 | if (!!(n1.shapeFlag & ShapeFlags.TEXT_CHILDREN)) {
82 | if (!!(n2.shapeFlag & ShapeFlags.ARRAY_CHILDREN)) {
83 | // text children => array children
84 | removeAllChildren(container)
85 | mountChildren(n2.children, container, null)
86 | } else {
87 | // text children => text children
88 | if (n1.children !== n2.children) {
89 | setElementInnerContext(container, n2.children)
90 | }
91 | }
92 | } else {
93 | // n1 children 是一个数组
94 | if (!!(n2.shapeFlag & ShapeFlags.ARRAY_CHILDREN)) {
95 | // array children => array children
96 | } else {
97 | // array children => text children
98 | removeAllChildren(container)
99 | setElementInnerContext(container, n2.children)
100 | }
101 | }
102 | }
103 |
104 | function patchProps(el, oldProps, newProps) {
105 | if (oldProps !== newProps) {
106 | for (const key in newProps) {
107 | const prevProp = oldProps[key]
108 | const nextProp = newProps[key]
109 |
110 | if (prevProp !== nextProp) {
111 | hostPatchProps(el, key, prevProp, nextProp)
112 | }
113 | }
114 |
115 | if (oldProps !== EMPTY_OBJ) {
116 | for (const key in oldProps) {
117 | if (!(key in newProps)) {
118 | hostPatchProps(el, key, oldProps[key], null)
119 | }
120 | }
121 | }
122 | }
123 | }
124 |
125 | function mountElement(vnode, container, parentComponent) {
126 | const { type, children, props, shapeFlag } = vnode
127 | const el = (vnode.el = createElement(type))
128 |
129 | //children
130 | if (shapeFlag & ShapeFlags.ARRAY_CHILDREN) {
131 | mountChildren(children, el, parentComponent)
132 | } else if (!!(children.shapeFlag & ShapeFlags.TEXT_CHILDREN)) {
133 | const vlaue = children.children
134 | insert(createTextNode(vlaue), el)
135 | } else {
136 | setElementInnerContext(el, children)
137 | }
138 |
139 | // props
140 | for (const key in props) {
141 | const val = props[key]
142 | hostPatchProps(el, key, null, val)
143 | }
144 |
145 | insert(el, container)
146 | }
147 |
148 | function mountChildren(children, container, parentComponent) {
149 | children.forEach((child) => {
150 | patch(null, child, container, parentComponent)
151 | })
152 | }
153 |
154 | function processComponent(n1, n2, container, parentComponent) {
155 | mountComponent(n2, container, parentComponent)
156 | }
157 |
158 | function mountComponent(initinalVNode, container, parentComponent) {
159 | const instance = createComponentInstance(initinalVNode, parentComponent)
160 | setupComponent(instance)
161 | setupRenderEffect(instance, container)
162 | }
163 |
164 | function setupRenderEffect(instance, container) {
165 | effect(() => {
166 | const { proxy } = instance
167 | if (!instance.isMounted) {
168 | console.log("init")
169 | const subTree = (instance.subTree = instance.render.call(proxy))
170 | patch(null, subTree, container, instance)
171 | instance.vnode.el = subTree.el
172 | instance.isMounted = true
173 | } else {
174 | console.log("update")
175 | const subTree = instance.render.call(proxy)
176 | const preSubTree = instance.subTree
177 | instance.vnode.el = subTree.el
178 | patch(preSubTree, subTree, container, instance)
179 | }
180 | })
181 | }
182 |
183 | return {
184 | createApp: createAppApi(render),
185 | }
186 | }
187 |
--------------------------------------------------------------------------------
/packages/runtime-core/src/vnode.ts:
--------------------------------------------------------------------------------
1 | import { ShapeFlags } from "../../shared/shapeFlags"
2 |
3 | export const Fragment = Symbol("Fragment")
4 | export const Text = Symbol("Text")
5 |
6 | export function createVNode(type, props?, children?) {
7 | const vnode = {
8 | type,
9 | props,
10 | children,
11 | shapeFlag: getShapeFlag(type, children),
12 | el: null,
13 | }
14 | return vnode
15 | }
16 |
17 | export function createTextVnode(text) {
18 | return createVNode(Text, {}, String(text))
19 | }
20 |
21 | function getShapeFlag(type, children) {
22 | let flag = 0
23 | // 处理 element 和 component 的flag
24 | if (typeof type === "string") {
25 | flag |= ShapeFlags.ELEMENT
26 | } else if (type === Text) {
27 | flag |= ShapeFlags.TEXT_CHILDREN
28 | } else {
29 | flag |= ShapeFlags.STATEFUL_COMPONENT
30 | }
31 |
32 | // 处理 children 的flag
33 | if (Array.isArray(children)) {
34 | flag |= ShapeFlags.ARRAY_CHILDREN
35 | } else if (typeof children === "string") {
36 | flag |= ShapeFlags.TEXT_CHILDREN
37 | }
38 |
39 | return flag
40 | }
41 |
--------------------------------------------------------------------------------
/packages/runtime-dom/index.ts:
--------------------------------------------------------------------------------
1 | import { createAppApi } from "../runtime-core/src/createApp"
2 | import { createRender } from "../runtime-core/src/renderer"
3 |
4 | function createTextNode(text) {
5 | return document.createTextNode(text)
6 | }
7 | function insert(child, container) {
8 | container.appendChild(child)
9 | }
10 | function createElement(type) {
11 | return document.createElement(type)
12 | }
13 | function patchProps(el, key, prevVal, nextVal) {
14 | const isOn = (key: string) => /^on[A-Z]*/.test(key)
15 | // event
16 | if (isOn(key)) {
17 | const event = key.slice(2).toLocaleLowerCase()
18 | el.addEventListener(event, nextVal)
19 | } else {
20 | // attribute
21 | if (nextVal === undefined || nextVal === null) {
22 | el.removeAttribute(key)
23 | } else {
24 | el.setAttribute(key, nextVal)
25 | }
26 | }
27 | }
28 |
29 | function setElementInnerContext(el, context) {
30 | el.textContent = context
31 | }
32 |
33 | function removeAllChildren(el) {
34 | el.innerHTML = ""
35 | }
36 |
37 | const renderer = createRender({
38 | createTextNode,
39 | insert,
40 | createElement,
41 | hostPatchProps: patchProps,
42 | setElementInnerContext,
43 | removeAllChildren,
44 | })
45 |
46 | export function createApp(rootComponent) {
47 | return renderer.createApp(rootComponent)
48 | }
49 |
50 | export * from "../runtime-core/src"
51 |
--------------------------------------------------------------------------------
/packages/shared/index.ts:
--------------------------------------------------------------------------------
1 | export const extend = Object.assign
2 |
3 | export const EMPTY_OBJ = {}
4 |
5 | export const isObject = (target) => typeof target === "object"
6 |
7 | export const hasChanged = (value, newValue) => !Object.is(value, newValue)
8 |
9 | export const hasOwn = (value, key) =>
10 | Object.prototype.hasOwnProperty.call(value, key)
11 |
12 | export const camelize = (str) =>
13 | str.replace(/-(\w)/g, (_, c) => (c ? c.toUpperCase() : ""))
14 |
15 | const capitalize = (str) => str.charAt(0).toUpperCase() + str.slice(1)
16 |
17 | export const toHandlerKey = (str) => (str ? "on" + capitalize(str) : "")
18 |
--------------------------------------------------------------------------------
/packages/shared/shapeFlags.ts:
--------------------------------------------------------------------------------
1 | export const enum ShapeFlags {
2 | ELEMENT = 1,
3 | STATEFUL_COMPONENT = 1 << 1,
4 | TEXT_CHILDREN = 1 << 2,
5 | ARRAY_CHILDREN = 1 << 3,
6 | }
7 |
--------------------------------------------------------------------------------
/rollup.config.js:
--------------------------------------------------------------------------------
1 | import pkg from "./package.json"
2 | import typescript from "@rollup/plugin-typescript"
3 | import resolve from "@rollup/plugin-node-resolve"
4 |
5 | export default {
6 | input: "./packages/index.ts",
7 | output: [
8 | {
9 | format: "cjs",
10 | file: pkg.main,
11 | },
12 | ,
13 | {
14 | format: "es",
15 | file: pkg.module,
16 | },
17 | ],
18 | plugins: [typescript(), resolve],
19 | }
20 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | /* Visit https://aka.ms/tsconfig.json to read more about this file */
4 | /* Projects */
5 | // "incremental": true, /* Enable incremental compilation */
6 | // "composite": true, /* Enable constraints that allow a TypeScript project to be used with project references. */
7 | // "tsBuildInfoFile": "./", /* Specify the folder for .tsbuildinfo incremental compilation files. */
8 | // "disableSourceOfProjectReferenceRedirect": true, /* Disable preferring source files instead of declaration files when referencing composite projects */
9 | // "disableSolutionSearching": true, /* Opt a project out of multi-project reference checking when editing. */
10 | // "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */
11 | /* Language and Environment */
12 | "target": "ES5", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */
13 | "lib": [
14 | "DOM",
15 | "ES6"
16 | ], /* Specify a set of bundled library declaration files that describe the target runtime environment. */
17 | // "jsx": "preserve", /* Specify what JSX code is generated. */
18 | // "experimentalDecorators": true, /* Enable experimental support for TC39 stage 2 draft decorators. */
19 | // "emitDecoratorMetadata": true, /* Emit design-type metadata for decorated declarations in source files. */
20 | // "jsxFactory": "", /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h' */
21 | // "jsxFragmentFactory": "", /* Specify the JSX Fragment reference used for fragments when targeting React JSX emit e.g. 'React.Fragment' or 'Fragment'. */
22 | // "jsxImportSource": "", /* Specify module specifier used to import the JSX factory functions when using `jsx: react-jsx*`.` */
23 | // "reactNamespace": "", /* Specify the object invoked for `createElement`. This only applies when targeting `react` JSX emit. */
24 | // "noLib": true, /* Disable including any library files, including the default lib.d.ts. */
25 | // "useDefineForClassFields": true, /* Emit ECMAScript-standard-compliant class fields. */
26 | /* Modules */
27 | "module": "esnext", /* Specify what module code is generated. */
28 | // "rootDir": "./", /* Specify the root folder within your source files. */
29 | "moduleResolution": "node", /* Specify how TypeScript looks up a file from a given module specifier. */
30 | // "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */
31 | // "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */
32 | // "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */
33 | // "typeRoots": [], /* Specify multiple folders that act like `./node_modules/@types`. */
34 | "types": [
35 | "jest"
36 | ], /* Specify type package names to be included without being referenced in a source file. */
37 | // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */
38 | // "resolveJsonModule": true, /* Enable importing .json files */
39 | // "noResolve": true, /* Disallow `import`s, `require`s or ``s from expanding the number of files TypeScript should add to a project. */
40 | /* JavaScript Support */
41 | // "allowJs": true, /* Allow JavaScript files to be a part of your program. Use the `checkJS` option to get errors from these files. */
42 | // "checkJs": true, /* Enable error reporting in type-checked JavaScript files. */
43 | // "maxNodeModuleJsDepth": 1, /* Specify the maximum folder depth used for checking JavaScript files from `node_modules`. Only applicable with `allowJs`. */
44 | /* Emit */
45 | // "declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */
46 | // "declarationMap": true, /* Create sourcemaps for d.ts files. */
47 | // "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */
48 | // "sourceMap": true, /* Create source map files for emitted JavaScript files. */
49 | // "outFile": "./", /* Specify a file that bundles all outputs into one JavaScript file. If `declaration` is true, also designates a file that bundles all .d.ts output. */
50 | // "outDir": "./", /* Specify an output folder for all emitted files. */
51 | // "removeComments": true, /* Disable emitting comments. */
52 | // "noEmit": true, /* Disable emitting files from a compilation. */
53 | // "importHelpers": true, /* Allow importing helper functions from tslib once per project, instead of including them per-file. */
54 | // "importsNotUsedAsValues": "remove", /* Specify emit/checking behavior for imports that are only used for types */
55 | // "downlevelIteration": true, /* Emit more compliant, but verbose and less performant JavaScript for iteration. */
56 | // "sourceRoot": "", /* Specify the root path for debuggers to find the reference source code. */
57 | // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */
58 | // "inlineSourceMap": true, /* Include sourcemap files inside the emitted JavaScript. */
59 | // "inlineSources": true, /* Include source code in the sourcemaps inside the emitted JavaScript. */
60 | // "emitBOM": true, /* Emit a UTF-8 Byte Order Mark (BOM) in the beginning of output files. */
61 | // "newLine": "crlf", /* Set the newline character for emitting files. */
62 | // "stripInternal": true, /* Disable emitting declarations that have `@internal` in their JSDoc comments. */
63 | // "noEmitHelpers": true, /* Disable generating custom helper functions like `__extends` in compiled output. */
64 | // "noEmitOnError": true, /* Disable emitting files if any type checking errors are reported. */
65 | // "preserveConstEnums": true, /* Disable erasing `const enum` declarations in generated code. */
66 | // "declarationDir": "./", /* Specify the output directory for generated declaration files. */
67 | // "preserveValueImports": true, /* Preserve unused imported values in the JavaScript output that would otherwise be removed. */
68 | /* Interop Constraints */
69 | // "isolatedModules": true, /* Ensure that each file can be safely transpiled without relying on other imports. */
70 | // "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */
71 | "esModuleInterop": true, /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables `allowSyntheticDefaultImports` for type compatibility. */
72 | // "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */
73 | "forceConsistentCasingInFileNames": true, /* Ensure that casing is correct in imports. */
74 | /* Type Checking */
75 | "strict": true, /* Enable all strict type-checking options. */
76 | "noImplicitAny": false, /* Enable error reporting for expressions and declarations with an implied `any` type.. */
77 | // "strictNullChecks": true, /* When type checking, take into account `null` and `undefined`. */
78 | // "strictFunctionTypes": true, /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */
79 | // "strictBindCallApply": true, /* Check that the arguments for `bind`, `call`, and `apply` methods match the original function. */
80 | // "strictPropertyInitialization": true, /* Check for class properties that are declared but not set in the constructor. */
81 | // "noImplicitThis": true, /* Enable error reporting when `this` is given the type `any`. */
82 | // "useUnknownInCatchVariables": true, /* Type catch clause variables as 'unknown' instead of 'any'. */
83 | // "alwaysStrict": true, /* Ensure 'use strict' is always emitted. */
84 | // "noUnusedLocals": true, /* Enable error reporting when a local variables aren't read. */
85 | // "noUnusedParameters": true, /* Raise an error when a function parameter isn't read */
86 | // "exactOptionalPropertyTypes": true, /* Interpret optional property types as written, rather than adding 'undefined'. */
87 | // "noImplicitReturns": true, /* Enable error reporting for codepaths that do not explicitly return in a function. */
88 | // "noFallthroughCasesInSwitch": true, /* Enable error reporting for fallthrough cases in switch statements. */
89 | // "noUncheckedIndexedAccess": true, /* Include 'undefined' in index signature results */
90 | // "noImplicitOverride": true, /* Ensure overriding members in derived classes are marked with an override modifier. */
91 | // "noPropertyAccessFromIndexSignature": true, /* Enforces using indexed accessors for keys declared using an indexed type */
92 | // "allowUnusedLabels": true, /* Disable error reporting for unused labels. */
93 | // "allowUnreachableCode": true, /* Disable error reporting for unreachable code. */
94 | /* Completeness */
95 | // "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */
96 | "skipLibCheck": true /* Skip type checking all .d.ts files. */
97 | }
98 | }
--------------------------------------------------------------------------------