diff --git a/src/compiler/codegen.js b/src/compiler/codegen.js
new file mode 100644
index 0000000..0fd9ee0
--- /dev/null
+++ b/src/compiler/codegen.js
@@ -0,0 +1,5 @@
+export function generate(ast) {
+ return `
+ console.log('hello world')
+ `
+}
diff --git a/src/compiler/compile.js b/src/compiler/compile.js
new file mode 100644
index 0000000..587b164
--- /dev/null
+++ b/src/compiler/compile.js
@@ -0,0 +1,7 @@
+import { generate } from './codegen'
+import { baseParse } from './parse'
+
+export function compile(template) {
+ const ast = baseParse(template)
+ return generate(ast)
+}
diff --git a/src/examples/commits.html b/src/examples/commits.html
new file mode 100644
index 0000000..2f597e8
--- /dev/null
+++ b/src/examples/commits.html
@@ -0,0 +1,88 @@
+
+
+
+
Latest MiniVue.js Commits
+
+
+
+
+
leaon4/mini-vue3@{{ currentBranch.value }}
+
+
+
+
+
+
diff --git a/src/examples/grid.html b/src/examples/grid.html
new file mode 100644
index 0000000..4e79939
--- /dev/null
+++ b/src/examples/grid.html
@@ -0,0 +1,188 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/examples/index.html b/src/examples/index.html
new file mode 100644
index 0000000..3460609
--- /dev/null
+++ b/src/examples/index.html
@@ -0,0 +1,22 @@
+
+
+
+
+
+
+ Expamels
+
+
+
+ Expamels
+
+
+
diff --git a/src/examples/markdown.html b/src/examples/markdown.html
new file mode 100644
index 0000000..770efc5
--- /dev/null
+++ b/src/examples/markdown.html
@@ -0,0 +1,71 @@
+
+
+
+
+
+
+
+
+
diff --git a/src/examples/package-lock.json b/src/examples/package-lock.json
new file mode 100644
index 0000000..0e19ce0
--- /dev/null
+++ b/src/examples/package-lock.json
@@ -0,0 +1,28 @@
+{
+ "name": "examples",
+ "version": "1.0.0",
+ "lockfileVersion": 1,
+ "requires": true,
+ "dependencies": {
+ "lodash": {
+ "version": "4.17.21",
+ "resolved": "https://registry.nlark.com/lodash/download/lodash-4.17.21.tgz?cache=0&sync_timestamp=1618910518249&other_urls=https%3A%2F%2Fregistry.nlark.com%2Flodash%2Fdownload%2Flodash-4.17.21.tgz",
+ "integrity": "sha1-Z5WRxWTDv/quhFTPCz3zcMPWkRw="
+ },
+ "marked": {
+ "version": "2.1.3",
+ "resolved": "https://registry.nlark.com/marked/download/marked-2.1.3.tgz",
+ "integrity": "sha1-vQF872Qxck/Usn4GV/XOsUv/N1M="
+ },
+ "monaco-editor": {
+ "version": "0.26.1",
+ "resolved": "https://registry.nlark.com/monaco-editor/download/monaco-editor-0.26.1.tgz",
+ "integrity": "sha1-YrtfZYvJU3n4q7ZLFHYyvRwBnXM="
+ },
+ "prettier": {
+ "version": "2.3.2",
+ "resolved": "https://registry.nlark.com/prettier/download/prettier-2.3.2.tgz?cache=0&sync_timestamp=1624696479455&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fprettier%2Fdownload%2Fprettier-2.3.2.tgz",
+ "integrity": "sha1-7ygKBewlNxLkhiM9tcbyNEHnNC0="
+ }
+ }
+}
diff --git a/src/examples/package.json b/src/examples/package.json
new file mode 100644
index 0000000..9f09cb0
--- /dev/null
+++ b/src/examples/package.json
@@ -0,0 +1,16 @@
+{
+ "name": "examples",
+ "version": "1.0.0",
+ "description": "",
+ "scripts": {
+ "test": "echo \"Error: no test specified\" && exit 1"
+ },
+ "author": "",
+ "license": "ISC",
+ "dependencies": {
+ "lodash": "^4.17.21",
+ "marked": "^2.1.3",
+ "monaco-editor": "^0.26.1",
+ "prettier": "^2.3.2"
+ }
+}
diff --git a/src/examples/template-explorer/index.html b/src/examples/template-explorer/index.html
new file mode 100644
index 0000000..902f59e
--- /dev/null
+++ b/src/examples/template-explorer/index.html
@@ -0,0 +1,46 @@
+
+
+
+
+
+
+ Mini-Vue3 Template Explorer
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/examples/template-explorer/index.js b/src/examples/template-explorer/index.js
new file mode 100644
index 0000000..d1f55b3
--- /dev/null
+++ b/src/examples/template-explorer/index.js
@@ -0,0 +1,208 @@
+// eslint-disable-next-line no-undef
+const { effect, compile } = MiniVue;
+
+const sharedEditorOptions = {
+ fontSize: 14,
+ scrollBeyondLastLine: false,
+ renderWhitespace: 'selection',
+ minimap: {
+ enabled: false,
+ },
+};
+
+window.init = () => {
+ const monaco = window.monaco;
+
+ // eslint-disable-next-line no-undef
+ monaco.editor.defineTheme('my-theme', theme);
+ monaco.editor.setTheme('my-theme');
+
+ const persistedState = JSON.parse(
+ decodeURIComponent(window.location.hash.slice(1)) ||
+ localStorage.getItem('state') ||
+ `{}`
+ );
+
+ let lastSuccessfulCode;
+ let lastSuccessfulMap;
+ function compileCode(source) {
+ console.clear();
+ try {
+ const errors = [];
+ const compileFn = (source) => {
+ // eslint-disable-next-line no-undef
+ return format(compile(source));
+ };
+ const start = performance.now();
+ const code = compileFn(source);
+ console.log(`Compiled in ${(performance.now() - start).toFixed(2)}ms.`);
+ monaco.editor.setModelMarkers(
+ editor.getModel(),
+ `@vue/compiler-dom`,
+ errors.filter((e) => e.loc).map(formatError)
+ );
+ lastSuccessfulCode = code;
+ } catch (e) {
+ lastSuccessfulCode = `/* ERROR: ${e.message} (see console for more info) */`;
+ console.error(e);
+ }
+ return lastSuccessfulCode;
+ }
+
+ function formatError(err) {
+ return {
+ message: `Vue template compilation error: ${err.message}`,
+ code: String(err.code),
+ };
+ }
+
+ function reCompile() {
+ const src = editor.getValue();
+ // every time we re-compile, persist current state
+ const state = JSON.stringify({
+ src,
+ });
+ localStorage.setItem('state', state);
+ window.location.hash = encodeURIComponent(state);
+ const res = compileCode(src);
+ if (res) {
+ output.setValue(res);
+ output.trigger('editor', 'editor.action.formatDocument');
+ }
+ }
+
+ const editor = monaco.editor.create(document.getElementById('source'), {
+ value: persistedState.src || `Hello World!
`,
+ language: 'html',
+ ...sharedEditorOptions,
+ wordWrap: 'bounded',
+ });
+
+ editor.getModel().updateOptions({
+ tabSize: 2,
+ });
+
+ const output = (window.output = monaco.editor.create(
+ document.getElementById('output'),
+ {
+ value: '',
+ language: 'javascript',
+ // readOnly: true,
+ ...sharedEditorOptions,
+ }
+ ));
+ output.getModel().updateOptions({
+ tabSize: 2,
+ });
+
+ // handle resize
+ window.addEventListener('resize', () => {
+ editor.layout();
+ output.layout();
+ });
+
+ // update compile output when input changes
+ editor.onDidChangeModelContent(debounce(reCompile));
+
+ // highlight output code
+ let prevOutputDecos = [];
+ function clearOutputDecos() {
+ prevOutputDecos = output.deltaDecorations(prevOutputDecos, []);
+ }
+
+ editor.onDidChangeCursorPosition(
+ debounce((e) => {
+ clearEditorDecos();
+ if (lastSuccessfulMap) {
+ const pos = lastSuccessfulMap.generatedPositionFor({
+ source: 'ExampleTemplate.vue',
+ line: e.position.lineNumber,
+ column: e.position.column - 1,
+ });
+ if (pos.line != null && pos.column != null) {
+ prevOutputDecos = output.deltaDecorations(prevOutputDecos, [
+ {
+ range: new monaco.Range(
+ pos.line,
+ pos.column + 1,
+ pos.line,
+ pos.lastColumn ? pos.lastColumn + 2 : pos.column + 2
+ ),
+ options: {
+ inlineClassName: `highlight`,
+ },
+ },
+ ]);
+ output.revealPositionInCenter({
+ lineNumber: pos.line,
+ column: pos.column + 1,
+ });
+ } else {
+ clearOutputDecos();
+ }
+ }
+ }, 100)
+ );
+
+ let previousEditorDecos = [];
+ function clearEditorDecos() {
+ previousEditorDecos = editor.deltaDecorations(previousEditorDecos, []);
+ }
+
+ output.onDidChangeCursorPosition(
+ debounce((e) => {
+ clearOutputDecos();
+ if (lastSuccessfulMap) {
+ const pos = lastSuccessfulMap.originalPositionFor({
+ line: e.position.lineNumber,
+ column: e.position.column - 1,
+ });
+ if (
+ pos.line != null &&
+ pos.column != null &&
+ !(
+ // ignore mock location
+ (pos.line === 1 && pos.column === 0)
+ )
+ ) {
+ const translatedPos = {
+ column: pos.column + 1,
+ lineNumber: pos.line,
+ };
+ previousEditorDecos = editor.deltaDecorations(previousEditorDecos, [
+ {
+ range: new monaco.Range(
+ pos.line,
+ pos.column + 1,
+ pos.line,
+ pos.column + 1
+ ),
+ options: {
+ isWholeLine: true,
+ className: `highlight`,
+ },
+ },
+ ]);
+ editor.revealPositionInCenter(translatedPos);
+ } else {
+ clearEditorDecos();
+ }
+ }
+ }, 100)
+ );
+
+ effect(reCompile);
+};
+
+function debounce(fn, delay = 300) {
+ let prevTimer = null;
+ return (...args) => {
+ if (prevTimer) {
+ clearTimeout(prevTimer);
+ }
+ prevTimer = window.setTimeout(() => {
+ fn(...args);
+ prevTimer = null;
+ }, delay);
+ };
+}
diff --git a/src/examples/template-explorer/style.css b/src/examples/template-explorer/style.css
new file mode 100644
index 0000000..888c135
--- /dev/null
+++ b/src/examples/template-explorer/style.css
@@ -0,0 +1,95 @@
+body {
+ margin: 0;
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen,
+ Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
+ --bg: #1d1f21;
+ --border: #333;
+}
+
+#header {
+ position: absolute;
+ top: 0;
+ left: 0;
+ right: 0;
+ height: 60px;
+ box-sizing: border-box;
+ background-color: var(--bg);
+ border-bottom: 1px solid var(--border);
+ padding: 0.3em 1.6em;
+ color: #fff;
+ z-index: 1;
+}
+
+h1 {
+ font-size: 18px;
+ display: inline-block;
+ margin-right: 15px;
+}
+
+#options-wrapper {
+ position: absolute;
+ top: 20px;
+ right: 10px;
+}
+
+#options-wrapper:hover #options {
+ display: block;
+}
+
+#options-label {
+ cursor: pointer;
+ text-align: right;
+ padding-right: 10px;
+ font-weight: bold;
+}
+
+#options {
+ display: none;
+ margin-top: 15px;
+ list-style-type: none;
+ background-color: var(--bg);
+ border: 1px solid var(--border);
+ padding: 15px 30px;
+}
+
+#options li {
+ margin: 8px 0;
+}
+
+#header a {
+ font-weight: 600;
+ color: rgb(101, 163, 221);
+}
+
+#header .label {
+ font-weight: bold;
+}
+
+#header input {
+ margin-right: 6px;
+}
+
+#header label {
+ color: #999;
+}
+
+.editor {
+ position: absolute;
+ top: 60px;
+ bottom: 0;
+ box-sizing: border-box;
+}
+
+#source {
+ left: 0;
+ width: 45%;
+}
+
+#output {
+ left: 45%;
+ width: 55%;
+}
+
+.highlight {
+ background-color: rgba(46, 120, 190, 0.5);
+}
diff --git a/src/examples/template-explorer/theme.js b/src/examples/template-explorer/theme.js
new file mode 100644
index 0000000..2123d85
--- /dev/null
+++ b/src/examples/template-explorer/theme.js
@@ -0,0 +1,244 @@
+window.theme = {
+ base: 'vs-dark',
+ inherit: true,
+ rules: [
+ {
+ foreground: 'de935f',
+ token: 'number',
+ },
+ {
+ foreground: '969896',
+ token: 'comment',
+ },
+ {
+ foreground: 'ced1cf',
+ token: 'keyword.operator.class',
+ },
+ {
+ foreground: 'ced1cf',
+ token: 'constant.other',
+ },
+ {
+ foreground: 'ced1cf',
+ token: 'source.php.embedded.line',
+ },
+ {
+ foreground: 'cc6666',
+ token: 'variable',
+ },
+ {
+ foreground: 'cc6666',
+ token: 'support.other.variable',
+ },
+ {
+ foreground: 'cc6666',
+ token: 'string.other.link',
+ },
+ {
+ foreground: 'cc6666',
+ token: 'string.regexp',
+ },
+ {
+ foreground: 'cc6666',
+ token: 'entity.name.tag',
+ },
+ {
+ foreground: 'cc6666',
+ token: 'entity.other.attribute-name',
+ },
+ {
+ foreground: 'cc6666',
+ token: 'meta.tag',
+ },
+ {
+ foreground: 'cc6666',
+ token: 'declaration.tag',
+ },
+ {
+ foreground: 'cc6666',
+ token: 'markup.deleted.git_gutter',
+ },
+ {
+ foreground: 'de935f',
+ token: 'constant.numeric',
+ },
+ {
+ foreground: 'de935f',
+ token: 'constant.language',
+ },
+ {
+ foreground: 'de935f',
+ token: 'support.constant',
+ },
+ {
+ foreground: 'de935f',
+ token: 'constant.character',
+ },
+ {
+ foreground: 'de935f',
+ token: 'variable.parameter',
+ },
+ {
+ foreground: 'de935f',
+ token: 'punctuation.section.embedded',
+ },
+ {
+ foreground: 'de935f',
+ token: 'keyword.other.unit',
+ },
+ {
+ foreground: 'f0c674',
+ token: 'entity.name.class',
+ },
+ {
+ foreground: 'f0c674',
+ token: 'entity.name.type.class',
+ },
+ {
+ foreground: 'f0c674',
+ token: 'support.type',
+ },
+ {
+ foreground: 'f0c674',
+ token: 'support.class',
+ },
+ {
+ foreground: 'b5bd68',
+ token: 'string',
+ },
+ {
+ foreground: 'b5bd68',
+ token: 'constant.other.symbol',
+ },
+ {
+ foreground: 'b5bd68',
+ token: 'entity.other.inherited-class',
+ },
+ {
+ foreground: 'b5bd68',
+ token: 'markup.heading',
+ },
+ {
+ foreground: 'b5bd68',
+ token: 'markup.inserted.git_gutter',
+ },
+ {
+ foreground: '8abeb7',
+ token: 'keyword.operator',
+ },
+ {
+ foreground: '8abeb7',
+ token: 'constant.other.color',
+ },
+ {
+ foreground: '81a2be',
+ token: 'entity.name.function',
+ },
+ {
+ foreground: '81a2be',
+ token: 'meta.function-call',
+ },
+ {
+ foreground: '81a2be',
+ token: 'support.function',
+ },
+ {
+ foreground: '81a2be',
+ token: 'keyword.other.special-method',
+ },
+ {
+ foreground: '81a2be',
+ token: 'meta.block-level',
+ },
+ {
+ foreground: '81a2be',
+ token: 'markup.changed.git_gutter',
+ },
+ {
+ foreground: 'b294bb',
+ token: 'keyword',
+ },
+ {
+ foreground: 'b294bb',
+ token: 'storage',
+ },
+ {
+ foreground: 'b294bb',
+ token: 'storage.type',
+ },
+ {
+ foreground: 'b294bb',
+ token: 'entity.name.tag.css',
+ },
+ {
+ foreground: 'ced2cf',
+ background: 'df5f5f',
+ token: 'invalid',
+ },
+ {
+ foreground: 'ced2cf',
+ background: '82a3bf',
+ token: 'meta.separator',
+ },
+ {
+ foreground: 'ced2cf',
+ background: 'b798bf',
+ token: 'invalid.deprecated',
+ },
+ {
+ foreground: 'ffffff',
+ token: 'markup.inserted.diff',
+ },
+ {
+ foreground: 'ffffff',
+ token: 'markup.deleted.diff',
+ },
+ {
+ foreground: 'ffffff',
+ token: 'meta.diff.header.to-file',
+ },
+ {
+ foreground: 'ffffff',
+ token: 'meta.diff.header.from-file',
+ },
+ {
+ foreground: '718c00',
+ token: 'markup.inserted.diff',
+ },
+ {
+ foreground: '718c00',
+ token: 'meta.diff.header.to-file',
+ },
+ {
+ foreground: 'c82829',
+ token: 'markup.deleted.diff',
+ },
+ {
+ foreground: 'c82829',
+ token: 'meta.diff.header.from-file',
+ },
+ {
+ foreground: 'ffffff',
+ background: '4271ae',
+ token: 'meta.diff.header.from-file',
+ },
+ {
+ foreground: 'ffffff',
+ background: '4271ae',
+ token: 'meta.diff.header.to-file',
+ },
+ {
+ foreground: '3e999f',
+ fontStyle: 'italic',
+ token: 'meta.diff.range',
+ },
+ ],
+ colors: {
+ 'editor.foreground': '#C5C8C6',
+ 'editor.background': '#1D1F21',
+ 'editor.selectionBackground': '#373B41',
+ 'editor.lineHighlightBackground': '#282A2E',
+ 'editorCursor.foreground': '#AEAFAD',
+ 'editorWhitespace.foreground': '#4B4E55',
+ },
+};
diff --git a/src/examples/todomvc.css b/src/examples/todomvc.css
new file mode 100644
index 0000000..d2442c2
--- /dev/null
+++ b/src/examples/todomvc.css
@@ -0,0 +1,377 @@
+html,
+body {
+ margin: 0;
+ padding: 0;
+}
+
+button {
+ margin: 0;
+ padding: 0;
+ border: 0;
+ background: none;
+ font-size: 100%;
+ vertical-align: baseline;
+ font-family: inherit;
+ font-weight: inherit;
+ color: inherit;
+ -webkit-appearance: none;
+ appearance: none;
+ -webkit-font-smoothing: antialiased;
+ -moz-osx-font-smoothing: grayscale;
+}
+
+body {
+ font: 14px 'Helvetica Neue', Helvetica, Arial, sans-serif;
+ line-height: 1.4em;
+ background: #f5f5f5;
+ color: #111111;
+ min-width: 230px;
+ max-width: 550px;
+ margin: 0 auto;
+ -webkit-font-smoothing: antialiased;
+ -moz-osx-font-smoothing: grayscale;
+ font-weight: 300;
+}
+
+:focus {
+ outline: 0;
+}
+
+.hidden {
+ display: none;
+}
+
+.todoapp {
+ background: #fff;
+ margin: 130px 0 40px 0;
+ position: relative;
+ box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.2), 0 25px 50px 0 rgba(0, 0, 0, 0.1);
+}
+
+.todoapp input::-webkit-input-placeholder {
+ font-style: italic;
+ font-weight: 300;
+ color: rgba(0, 0, 0, 0.4);
+}
+
+.todoapp input::-moz-placeholder {
+ font-style: italic;
+ font-weight: 300;
+ color: rgba(0, 0, 0, 0.4);
+}
+
+.todoapp input::input-placeholder {
+ font-style: italic;
+ font-weight: 300;
+ color: rgba(0, 0, 0, 0.4);
+}
+
+.todoapp h1 {
+ position: absolute;
+ top: -140px;
+ width: 100%;
+ font-size: 80px;
+ font-weight: 200;
+ text-align: center;
+ color: #b83f45;
+ -webkit-text-rendering: optimizeLegibility;
+ -moz-text-rendering: optimizeLegibility;
+ text-rendering: optimizeLegibility;
+}
+
+.new-todo,
+.edit {
+ position: relative;
+ margin: 0;
+ width: 100%;
+ font-size: 24px;
+ font-family: inherit;
+ font-weight: inherit;
+ line-height: 1.4em;
+ color: inherit;
+ padding: 6px;
+ border: 1px solid #999;
+ box-shadow: inset 0 -1px 5px 0 rgba(0, 0, 0, 0.2);
+ box-sizing: border-box;
+ -webkit-font-smoothing: antialiased;
+ -moz-osx-font-smoothing: grayscale;
+}
+
+.new-todo {
+ padding: 16px 16px 16px 60px;
+ border: none;
+ background: rgba(0, 0, 0, 0.003);
+ box-shadow: inset 0 -2px 1px rgba(0, 0, 0, 0.03);
+}
+
+.main {
+ position: relative;
+ z-index: 2;
+ border-top: 1px solid #e6e6e6;
+}
+
+.toggle-all {
+ width: 1px;
+ height: 1px;
+ border: none; /* Mobile Safari */
+ opacity: 0;
+ position: absolute;
+ right: 100%;
+ bottom: 100%;
+}
+
+.toggle-all + label {
+ width: 60px;
+ height: 34px;
+ font-size: 0;
+ position: absolute;
+ top: -52px;
+ left: -13px;
+ -webkit-transform: rotate(90deg);
+ transform: rotate(90deg);
+}
+
+.toggle-all + label:before {
+ content: '❯';
+ font-size: 22px;
+ color: #e6e6e6;
+ padding: 10px 27px 10px 27px;
+}
+
+.toggle-all:checked + label:before {
+ color: #737373;
+}
+
+.todo-list {
+ margin: 0;
+ padding: 0;
+ list-style: none;
+}
+
+.todo-list li {
+ position: relative;
+ font-size: 24px;
+ border-bottom: 1px solid #ededed;
+}
+
+.todo-list li:last-child {
+ border-bottom: none;
+}
+
+.todo-list li.editing {
+ border-bottom: none;
+ padding: 0;
+}
+
+.todo-list li.editing .edit {
+ display: block;
+ width: calc(100% - 43px);
+ padding: 12px 16px;
+ margin: 0 0 0 43px;
+}
+
+.todo-list li.editing .view {
+ display: none;
+}
+
+.todo-list li .toggle {
+ text-align: center;
+ width: 40px;
+ /* auto, since non-WebKit browsers doesn't support input styling */
+ height: auto;
+ position: absolute;
+ top: 0;
+ bottom: 0;
+ margin: auto 0;
+ border: none; /* Mobile Safari */
+ -webkit-appearance: none;
+ appearance: none;
+}
+
+.todo-list li .toggle {
+ opacity: 0;
+}
+
+.todo-list li .toggle + label {
+ /*
+ Firefox requires `#` to be escaped - https://bugzilla.mozilla.org/show_bug.cgi?id=922433
+ IE and Edge requires *everything* to be escaped to render, so we do that instead of just the `#` - https://developer.microsoft.com/en-us/microsoft-edge/platform/issues/7157459/
+ */
+ background-image: url('data:image/svg+xml;utf8,%3Csvg%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%20width%3D%2240%22%20height%3D%2240%22%20viewBox%3D%22-10%20-18%20100%20135%22%3E%3Ccircle%20cx%3D%2250%22%20cy%3D%2250%22%20r%3D%2250%22%20fill%3D%22none%22%20stroke%3D%22%23ededed%22%20stroke-width%3D%223%22/%3E%3C/svg%3E');
+ background-repeat: no-repeat;
+ background-position: center left;
+}
+
+.todo-list li .toggle:checked + label {
+ background-image: url('data:image/svg+xml;utf8,%3Csvg%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%20width%3D%2240%22%20height%3D%2240%22%20viewBox%3D%22-10%20-18%20100%20135%22%3E%3Ccircle%20cx%3D%2250%22%20cy%3D%2250%22%20r%3D%2250%22%20fill%3D%22none%22%20stroke%3D%22%23bddad5%22%20stroke-width%3D%223%22/%3E%3Cpath%20fill%3D%22%235dc2af%22%20d%3D%22M72%2025L42%2071%2027%2056l-4%204%2020%2020%2034-52z%22/%3E%3C/svg%3E');
+}
+
+.todo-list li label {
+ word-break: break-all;
+ padding: 15px 15px 15px 60px;
+ display: block;
+ line-height: 1.2;
+ transition: color 0.4s;
+ font-weight: 400;
+ color: #4d4d4d;
+}
+
+.todo-list li.completed label {
+ color: #cdcdcd;
+ text-decoration: line-through;
+}
+
+.todo-list li .destroy {
+ display: none;
+ position: absolute;
+ top: 0;
+ right: 10px;
+ bottom: 0;
+ width: 40px;
+ height: 40px;
+ margin: auto 0;
+ font-size: 30px;
+ color: #cc9a9a;
+ margin-bottom: 11px;
+ transition: color 0.2s ease-out;
+}
+
+.todo-list li .destroy:hover {
+ color: #af5b5e;
+}
+
+.todo-list li .destroy:after {
+ content: '×';
+}
+
+.todo-list li:hover .destroy {
+ display: block;
+}
+
+.todo-list li .edit {
+ display: none;
+}
+
+.todo-list li.editing:last-child {
+ margin-bottom: -1px;
+}
+
+.footer {
+ padding: 10px 15px;
+ height: 20px;
+ text-align: center;
+ font-size: 15px;
+ border-top: 1px solid #e6e6e6;
+}
+
+.footer:before {
+ content: '';
+ position: absolute;
+ right: 0;
+ bottom: 0;
+ left: 0;
+ height: 50px;
+ overflow: hidden;
+ box-shadow: 0 1px 1px rgba(0, 0, 0, 0.2), 0 8px 0 -3px #f6f6f6,
+ 0 9px 1px -3px rgba(0, 0, 0, 0.2), 0 16px 0 -6px #f6f6f6,
+ 0 17px 2px -6px rgba(0, 0, 0, 0.2);
+}
+
+.todo-count {
+ float: left;
+ text-align: left;
+}
+
+.todo-count strong {
+ font-weight: 300;
+}
+
+.filters {
+ margin: 0;
+ padding: 0;
+ list-style: none;
+ position: absolute;
+ right: 0;
+ left: 0;
+}
+
+.filters li {
+ display: inline;
+}
+
+.filters li a {
+ color: inherit;
+ margin: 3px;
+ padding: 3px 7px;
+ text-decoration: none;
+ border: 1px solid transparent;
+ border-radius: 3px;
+}
+
+.filters li a:hover {
+ border-color: rgba(175, 47, 47, 0.1);
+}
+
+.filters li a.selected {
+ border-color: rgba(175, 47, 47, 0.2);
+}
+
+.clear-completed,
+html .clear-completed:active {
+ float: right;
+ position: relative;
+ line-height: 20px;
+ text-decoration: none;
+ cursor: pointer;
+}
+
+.clear-completed:hover {
+ text-decoration: underline;
+}
+
+.info {
+ margin: 65px auto 0;
+ color: #4d4d4d;
+ font-size: 11px;
+ text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5);
+ text-align: center;
+}
+
+.info p {
+ line-height: 1;
+}
+
+.info a {
+ color: inherit;
+ text-decoration: none;
+ font-weight: 400;
+}
+
+.info a:hover {
+ text-decoration: underline;
+}
+
+/*
+ Hack to remove background from Mobile Safari.
+ Can't use it globally since it destroys checkboxes in Firefox
+*/
+@media screen and (-webkit-min-device-pixel-ratio: 0) {
+ .toggle-all,
+ .todo-list li .toggle {
+ background: none;
+ }
+
+ .todo-list li .toggle {
+ height: 40px;
+ }
+}
+
+@media (max-width: 430px) {
+ .footer {
+ height: 50px;
+ }
+
+ .filters {
+ bottom: 10px;
+ }
+}
diff --git a/src/examples/todomvc.html b/src/examples/todomvc.html
new file mode 100644
index 0000000..568eced
--- /dev/null
+++ b/src/examples/todomvc.html
@@ -0,0 +1,247 @@
+
+
+
+
+
+
diff --git a/src/examples/tree.html b/src/examples/tree.html
new file mode 100644
index 0000000..75ecfb9
--- /dev/null
+++ b/src/examples/tree.html
@@ -0,0 +1,149 @@
+
+
+
+
+
+
+
+(You can double click on an item to turn it into a folder.)
+
+
+
+
+
+
+
diff --git a/src/examples/vModel.html b/src/examples/vModel.html
new file mode 100644
index 0000000..49a70eb
--- /dev/null
+++ b/src/examples/vModel.html
@@ -0,0 +1,83 @@
+
+
+
+
+
+
+ Document
+
+
+
+
+
+
+
+
diff --git a/src/examples/yarn.lock b/src/examples/yarn.lock
new file mode 100644
index 0000000..a3d1256
--- /dev/null
+++ b/src/examples/yarn.lock
@@ -0,0 +1,23 @@
+# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
+# yarn lockfile v1
+
+
+lodash@^4.17.21:
+ version "4.17.21"
+ resolved "https://registry.npmmirror.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c"
+ integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==
+
+marked@^2.1.3:
+ version "2.1.3"
+ resolved "https://registry.npmmirror.com/marked/-/marked-2.1.3.tgz#bd017cef6431724fd4b27e0657f5ceb14bff3753"
+ integrity sha512-/Q+7MGzaETqifOMWYEA7HVMaZb4XbcRfaOzcSsHZEith83KGlvaSG33u0SKu89Mj5h+T8V2hM+8O45Qc5XTgwA==
+
+monaco-editor@^0.26.1:
+ version "0.26.1"
+ resolved "https://registry.npmmirror.com/monaco-editor/-/monaco-editor-0.26.1.tgz#62bb5f658bc95379f8abb64b147632bd1c019d73"
+ integrity sha512-mm45nUrBDk0DgZKgbD7+bhDOtcAFNGPJJRAdS6Su1kTGl6XEgC7U3xOmDUW/0RrLf+jlvCGaqLvD4p2VjwuwwQ==
+
+prettier@^2.3.2:
+ version "2.8.4"
+ resolved "https://registry.npmmirror.com/prettier/-/prettier-2.8.4.tgz#34dd2595629bfbb79d344ac4a91ff948694463c3"
+ integrity sha512-vIS4Rlc2FNh0BySk3Wkd6xmwxB0FpOndW5fisM5H8hsZSxU2VWVB5CWIkIjWvrHjIhxk2g3bfMKM87zNTrZddw==
diff --git a/src/index.js b/src/index.js
index 8532906..b4ffa21 100644
--- a/src/index.js
+++ b/src/index.js
@@ -1,27 +1,18 @@
+import { compile } from './compiler/compile'
+import { createApp, render, h, Text, Fragment, nextTick } from './runtime'
import { reactive, ref, computed, effect } from './reactivity'
-import { h, Text, Fragment } from './runtime/vnode'
-import { createApp } from './runtime/createApp'
-const root = document.createElement('div')
+export const MiniVue = (window.MiniVue = {
+ createApp,
+ render,
+ h,
+ Text,
+ Fragment,
-const Comp = {
- setup() {
- const counter = ref(0)
- const add = () => {
- counter.value++
- }
- return {
- counter,
- add
- }
- },
- render(ctx) {
- return [
- h('div', null, ctx.counter.value),
- h('button', { onClick: ctx.add }, 'add')
- ]
- }
-}
-
-createApp(Comp).mount(root)
-document.body.appendChild(root)
+ nextTick,
+ reactive,
+ ref,
+ computed,
+ effect,
+ compile
+})
diff --git a/src/runtime/index.js b/src/runtime/index.js
new file mode 100644
index 0000000..91d0eb1
--- /dev/null
+++ b/src/runtime/index.js
@@ -0,0 +1,4 @@
+export { h, Text, Fragment } from './vnode'
+export { render } from './render'
+export { createApp, resolveComponent } from './createApp'
+export { nextTick } from './scheduler'
diff --git a/webpack.config.js b/webpack.config.js
index 728ead7..27361ba 100644
--- a/webpack.config.js
+++ b/webpack.config.js
@@ -1,5 +1,4 @@
const path = require('path')
-const HtmlWebpackPlugin = require('html-webpack-plugin')
module.exports = {
mode: 'development',
@@ -11,15 +10,10 @@ module.exports = {
path: path.resolve(__dirname, 'dist'),
clean: true
},
- plugins: [
- // 自动生成html文件,并且引用bundle的文件
- new HtmlWebpackPlugin({
- title: 'mini-vue3'
- })
- ],
+
devServer: {
- // 设置内容的根路径,使用该目录中真实存在的静态资源,而不是虚拟资源
- contentBase: './dist',
+ contentBase: './src/examples',
+ publicPath: '/dist',
watchContentBase: true
}
}