diff --git a/example/HelloWorld/App.js b/example/HelloWorld/App.js
new file mode 100644
index 0000000..f8bce19
--- /dev/null
+++ b/example/HelloWorld/App.js
@@ -0,0 +1,12 @@
+import { h } from '../../lib/guide-mini-vue.esm.js'
+
+export const App = {
+ render() {
+ return h('div', 'hi, ' + this.msg)
+ },
+ setup() {
+ return {
+ msg: 'mini-vue'
+ }
+ }
+}
\ No newline at end of file
diff --git a/example/HelloWorld/index.html b/example/HelloWorld/index.html
new file mode 100644
index 0000000..4b94f5f
--- /dev/null
+++ b/example/HelloWorld/index.html
@@ -0,0 +1,16 @@
+
+
+
+
+
+
+
+ Document
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/example/HelloWorld/main.js b/example/HelloWorld/main.js
new file mode 100644
index 0000000..8acf9c1
--- /dev/null
+++ b/example/HelloWorld/main.js
@@ -0,0 +1,6 @@
+
+import { createApp } from '../../lib/guide-mini-vue.esm.js'
+import { App } from './App.js'
+
+const rootContainer = document.querySelector('#app')
+createApp(App).mount(rootContainer)
\ No newline at end of file
diff --git a/lib/guide-mini-vue.cjs.js b/lib/guide-mini-vue.cjs.js
new file mode 100644
index 0000000..0abbb0f
--- /dev/null
+++ b/lib/guide-mini-vue.cjs.js
@@ -0,0 +1,80 @@
+'use strict';
+
+Object.defineProperty(exports, '__esModule', { value: true });
+
+function createComponentInstance(vnode) {
+ const component = {
+ vnode,
+ type: vnode.type,
+ };
+ return component;
+}
+function setupComponent(instance) {
+ // initProps()
+ // initSlots()
+ setupStatefulComponent(instance);
+}
+function setupStatefulComponent(instance) {
+ const Component = instance.type;
+ const { setup } = Component;
+ if (setup) {
+ const setupResult = setup();
+ handleSetupResult(instance, setupResult);
+ }
+}
+function handleSetupResult(instance, setupResult) {
+ if (typeof setupResult === "object") {
+ instance.setupState = setupResult;
+ }
+ finishSetupComponent(instance);
+}
+function finishSetupComponent(instance) {
+ const Component = instance.type;
+ if (Component.render) {
+ instance.render = Component.render;
+ }
+}
+
+function render(vnode, container) {
+ patch(vnode);
+}
+function patch(vnode, container) {
+ processComponent(vnode);
+}
+function processComponent(vnode, container) {
+ mountComponent(vnode);
+}
+function mountComponent(vnode, container) {
+ const instance = createComponentInstance(vnode);
+ setupComponent(instance);
+ setupRenderEffect(instance);
+}
+function setupRenderEffect(instance, container) {
+ const subTree = instance.render();
+ patch(subTree);
+}
+
+function createVNode(type, props, children) {
+ const vnode = {
+ type,
+ props,
+ children,
+ };
+ return vnode;
+}
+
+function createApp(rootComponent) {
+ return {
+ mount(rootContainer) {
+ const vnode = createVNode(rootComponent);
+ render(vnode);
+ },
+ };
+}
+
+function h(type, props, children) {
+ return createVNode(type, props, children);
+}
+
+exports.createApp = createApp;
+exports.h = h;
diff --git a/lib/guide-mini-vue.esm.js b/lib/guide-mini-vue.esm.js
new file mode 100644
index 0000000..68cfe72
--- /dev/null
+++ b/lib/guide-mini-vue.esm.js
@@ -0,0 +1,75 @@
+function createComponentInstance(vnode) {
+ const component = {
+ vnode,
+ type: vnode.type,
+ };
+ return component;
+}
+function setupComponent(instance) {
+ // initProps()
+ // initSlots()
+ setupStatefulComponent(instance);
+}
+function setupStatefulComponent(instance) {
+ const Component = instance.type;
+ const { setup } = Component;
+ if (setup) {
+ const setupResult = setup();
+ handleSetupResult(instance, setupResult);
+ }
+}
+function handleSetupResult(instance, setupResult) {
+ if (typeof setupResult === "object") {
+ instance.setupState = setupResult;
+ }
+ finishSetupComponent(instance);
+}
+function finishSetupComponent(instance) {
+ const Component = instance.type;
+ if (Component.render) {
+ instance.render = Component.render;
+ }
+}
+
+function render(vnode, container) {
+ patch(vnode);
+}
+function patch(vnode, container) {
+ processComponent(vnode);
+}
+function processComponent(vnode, container) {
+ mountComponent(vnode);
+}
+function mountComponent(vnode, container) {
+ const instance = createComponentInstance(vnode);
+ setupComponent(instance);
+ setupRenderEffect(instance);
+}
+function setupRenderEffect(instance, container) {
+ const subTree = instance.render();
+ patch(subTree);
+}
+
+function createVNode(type, props, children) {
+ const vnode = {
+ type,
+ props,
+ children,
+ };
+ return vnode;
+}
+
+function createApp(rootComponent) {
+ return {
+ mount(rootContainer) {
+ const vnode = createVNode(rootComponent);
+ render(vnode);
+ },
+ };
+}
+
+function h(type, props, children) {
+ return createVNode(type, props, children);
+}
+
+export { createApp, h };
diff --git a/package.json b/package.json
index edc495f..3e04c53 100644
--- a/package.json
+++ b/package.json
@@ -1,19 +1,24 @@
{
"name": "guide-mini-vue",
"version": "1.0.0",
- "main": "index.js",
+ "main": "lib/guide-mini-vue.cjs.js",
+ "module": "lib/guide-mini-vue.esm.js",
"license": "MIT",
"scripts": {
- "test": "jest"
+ "test": "jest",
+ "build": "rollup -c rollup.config.js"
},
"devDependencies": {
"@babel/core": "^7.18.0",
"@babel/preset-env": "^7.18.0",
"@babel/preset-typescript": "^7.17.12",
+ "@rollup/plugin-typescript": "^8.3.2",
"@types/jest": "^27.5.1",
"babel-jest": "^28.1.0",
"jest": "^28.1.0",
+ "rollup": "^2.75.5",
"ts-jest": "^28.0.3",
+ "tslib": "^2.4.0",
"typescript": "^4.7.2"
}
}
diff --git a/rollup.config.js b/rollup.config.js
new file mode 100644
index 0000000..4c63bb5
--- /dev/null
+++ b/rollup.config.js
@@ -0,0 +1,19 @@
+import pkg from './package.json'
+import typescript from "@rollup/plugin-typescript"
+
+export default {
+ input: './src/index.ts',
+ output: [
+ // cjs属于commonjs规范
+ // esm属于es规范
+ {
+ format: 'cjs',
+ file: pkg.main
+ },
+ {
+ format: 'es',
+ file: pkg.module
+ }
+ ],
+ plugins: [typescript()]
+}
\ No newline at end of file
diff --git a/src/index.ts b/src/index.ts
new file mode 100644
index 0000000..fad4f92
--- /dev/null
+++ b/src/index.ts
@@ -0,0 +1,3 @@
+// mini-vue的出口
+
+export * from "./runtime-core/index"
diff --git a/src/runtime-core/component.ts b/src/runtime-core/component.ts
new file mode 100644
index 0000000..0ce3610
--- /dev/null
+++ b/src/runtime-core/component.ts
@@ -0,0 +1,35 @@
+export function createComponentInstance(vnode) {
+ const component = {
+ vnode,
+ type: vnode.type,
+ }
+ return component
+}
+
+export function setupComponent(instance) {
+ // initProps()
+ // initSlots()
+ setupStatefulComponent(instance)
+}
+
+function setupStatefulComponent(instance: any) {
+ const Component = instance.type
+
+ const { setup } = Component
+ if (setup) {
+ const setupResult = setup()
+ handleSetupResult(instance, setupResult)
+ }
+}
+function handleSetupResult(instance: any, setupResult: any) {
+ if (typeof setupResult === "object") {
+ instance.setupState = setupResult
+ }
+ finishSetupComponent(instance)
+}
+function finishSetupComponent(instance: any) {
+ const Component = instance.type
+ // if (Component.render) {
+ instance.render = Component.render
+ // }
+}
diff --git a/src/runtime-core/createApp.ts b/src/runtime-core/createApp.ts
new file mode 100644
index 0000000..b647035
--- /dev/null
+++ b/src/runtime-core/createApp.ts
@@ -0,0 +1,11 @@
+import { render } from "./renderer"
+import { createVNode } from "./vnode"
+
+export function createApp(rootComponent) {
+ return {
+ mount(rootContainer) {
+ const vnode = createVNode(rootComponent)
+ render(vnode, rootContainer)
+ },
+ }
+}
diff --git a/src/runtime-core/h.ts b/src/runtime-core/h.ts
new file mode 100644
index 0000000..965a24e
--- /dev/null
+++ b/src/runtime-core/h.ts
@@ -0,0 +1,5 @@
+import { createVNode } from "./vnode"
+
+export function h(type, props?, children?) {
+ return createVNode(type, props, children)
+}
diff --git a/src/runtime-core/index.ts b/src/runtime-core/index.ts
new file mode 100644
index 0000000..ba2da94
--- /dev/null
+++ b/src/runtime-core/index.ts
@@ -0,0 +1,2 @@
+export { createApp } from "./createApp"
+export { h } from "./h"
diff --git a/src/runtime-core/renderer.ts b/src/runtime-core/renderer.ts
new file mode 100644
index 0000000..972bc25
--- /dev/null
+++ b/src/runtime-core/renderer.ts
@@ -0,0 +1,27 @@
+import { createComponentInstance, setupComponent } from "./component"
+
+export function render(vnode, container) {
+ patch(vnode, container)
+}
+
+function patch(vnode, container) {
+ // 需要区分element和component
+ // 如果是function就认为是component?
+ // 如果是object就认为是element?
+ processComponent(vnode, container)
+}
+
+function processComponent(vnode: any, container: any) {
+ mountComponent(vnode, container)
+}
+
+function mountComponent(vnode: any, container) {
+ const instance = createComponentInstance(vnode)
+ setupComponent(instance)
+ setupRenderEffect(instance, container)
+}
+
+function setupRenderEffect(instance: any, container) {
+ const subTree = instance.render()
+ patch(subTree, container)
+}
diff --git a/src/runtime-core/vnode.ts b/src/runtime-core/vnode.ts
new file mode 100644
index 0000000..9f5fc87
--- /dev/null
+++ b/src/runtime-core/vnode.ts
@@ -0,0 +1,8 @@
+export function createVNode(type, props?, children?) {
+ const vnode = {
+ type,
+ props,
+ children,
+ }
+ return vnode
+}
diff --git a/tsconfig.json b/tsconfig.json
index 1d92181..b73f9a3 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -27,7 +27,7 @@
// "useDefineForClassFields": true, /* Emit ECMAScript-standard-compliant class fields. */
/* Modules */
- "module": "commonjs", /* Specify what module code is generated. */
+ "module": "esnext", /* Specify what module code is generated. */
// "rootDir": "./", /* Specify the root folder within your source files. */
// "moduleResolution": "node", /* Specify how TypeScript looks up a file from a given module specifier. */
// "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */