Skip to content

Commit 62d2e66

Browse files
committed
chore: codegen
1 parent 6ce9d67 commit 62d2e66

File tree

3 files changed

+224
-17
lines changed

3 files changed

+224
-17
lines changed

README.md

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,12 @@
88
- [x] ref
99
- [x] computed
1010
- [x] watch
11-
- [ ] 自动脱 ref
11+
- [ ] 自动脱 ref
12+
13+
14+
## 参考
15+
16+
- 《Vue.js 设计与实现》by 霍春阳
17+
- https://github.com/vuejs/core
18+
- https://github.com/cuixiaorui/mini-vue
19+
- https://github.com/tim101010101/beggar-vue

public/misaka.jpg

3.02 MB
Loading

slides.md

Lines changed: 215 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1717,8 +1717,10 @@ function generate(ast) {
17171717

17181718
---
17191719

1720+
<div grid="~ cols-2 gap-2">
1721+
17201722
```js
1721-
// 创建上下文,格式化代码字符串
1723+
// 创建上下文,用于格式化代码字符串
17221724
function createCodegenContext() {
17231725
const context = {
17241726
code: '',
@@ -1728,10 +1730,8 @@ function createCodegenContext() {
17281730
push(code) {
17291731
context.code += code
17301732
},
1731-
// 当前缩进级别,初始值为0,即没有缩进
1732-
currentIndent: 0,
1733-
// 换行
1734-
newLine() {
1733+
currentIndent: 0, // 当前缩进级别,初始值为0,即没有缩进
1734+
newLine() { // 换行
17351735
context.code += '\n' + ' '.repeat(context.currentIndent * 2)
17361736
},
17371737
indent() { // 缩进
@@ -1747,6 +1747,213 @@ function createCodegenContext() {
17471747
}
17481748
```
17491749

1750+
```js
1751+
// 生成渲染函数代码字符串
1752+
function genCode(node, context) {
1753+
const { push, indent, deIndent } = context
1754+
const fnName = 'render'
1755+
const args = ['_ctx', 'config']
1756+
const signature = args.join(', ')
1757+
1758+
push(`return `)
1759+
push(`function ${fnName}(`)
1760+
push(signature)
1761+
push(`) `)
1762+
push(`{`)
1763+
// 缩进
1764+
indent()
1765+
push(`const { h, _toDisplayString } = config`)
1766+
indent()
1767+
push(`return `)
1768+
genNode(node, context)
1769+
// 取消缩进
1770+
deIndent()
1771+
push(`}`)
1772+
}
1773+
```
1774+
1775+
</div>
1776+
1777+
---
1778+
1779+
<div grid="~ cols-2 gap-2">
1780+
1781+
```js
1782+
// 根据节点类型生成对应代码
1783+
function genNode(node, context) {
1784+
switch (node.type) {
1785+
case NodeTypes.INTERPOLATION:
1786+
genInterpolation(node, context)
1787+
break
1788+
case NodeTypes.SIMPLE_EXPRESSION:
1789+
genExpression(node, context)
1790+
break
1791+
case NodeTypes.ELEMENT:
1792+
genElement(node, context)
1793+
break
1794+
case NodeTypes.TEXT:
1795+
genText(node, context)
1796+
break
1797+
}
1798+
}
1799+
```
1800+
1801+
```js
1802+
/**
1803+
example:
1804+
{
1805+
type: 'Interpolation',
1806+
content: {
1807+
type: 'Expression',
1808+
content: '_ctx.msg',
1809+
}
1810+
}
1811+
=>
1812+
'_ctx.msg'
1813+
*/
1814+
function genInterpolation(node, context) {
1815+
const { push, helper } = context
1816+
push(`${helper(TO_DISPLAY_STRING)}(`)
1817+
genNode(node.content, context)
1818+
push(`)`)
1819+
}
1820+
1821+
function genExpression(node, context) {
1822+
context.push(node.content)
1823+
}
1824+
// { type: 'Text', content: 'hello' } => 'hello'
1825+
function genText(node, context) {
1826+
const { push } = context
1827+
push(`'${node.content}'`)
1828+
}
1829+
```
1830+
1831+
</div>
1832+
1833+
---
1834+
1835+
<div grid="~ cols-2 gap-2">
1836+
1837+
```js
1838+
/**
1839+
* 生成调用表达式
1840+
* @example
1841+
* const node = [
1842+
* type: 'Element', tag: 'div', props: { id: 'foo' }
1843+
* children: [ { type: 'Text', content: 'hello' } ]
1844+
* ]
1845+
* => h('div', { id: 'foo' }, 'hello')
1846+
* )
1847+
*/
1848+
function genElement(node, context) {
1849+
const { push, helper } = context
1850+
const { tag, props, children } = node
1851+
push(`h('${tag}', `)
1852+
1853+
if (props) {
1854+
genProps(props, context)
1855+
} else {
1856+
push('null, ')
1857+
}
1858+
if (children) {
1859+
genChildren(children, context)
1860+
} else {
1861+
push('null')
1862+
}
1863+
push(`)`)
1864+
}
1865+
```
1866+
1867+
```js
1868+
// const props = [
1869+
// { type: 'Attribute', name: 'id', value: 'foo' },
1870+
// { type: 'Attribute', name: 'class', value: 'bar' }
1871+
// ]
1872+
// => { id: 'foo', class: 'bar' }
1873+
//
1874+
function genProps(props, context) {
1875+
const { push } = context
1876+
if (!props.length) {
1877+
push('{}, ')
1878+
return
1879+
}
1880+
push('{ ')
1881+
1882+
for (let i = 0; i < props.length; i++) {
1883+
const prop = props[i]
1884+
const key = prop ? prop.name : ''
1885+
const value = prop ? prop.value : prop
1886+
push(JSON.stringify(key))
1887+
push(': ')
1888+
push(prop.isStatic ? JSON.stringify(value) : value)
1889+
if (i < props.length - 1) {
1890+
push(', ')
1891+
}
1892+
}
1893+
push(' }, ')
1894+
}
1895+
```
1896+
1897+
</div>
1898+
1899+
---
1900+
1901+
<div grid="~ cols-2 gap-2">
1902+
1903+
```js
1904+
// 处理子节点
1905+
function genChildren(children, context) {
1906+
genArrayExpression(children, context)
1907+
}
1908+
1909+
/**
1910+
* 生成数组表达式
1911+
* @example
1912+
* const node = [{
1913+
* type: 'Element',
1914+
* tag: 'span',
1915+
* children: [
1916+
* { type: 'Text', text: 'hello' }
1917+
* ]
1918+
* }]
1919+
* =>
1920+
* [h('span', null, 'hello')
1921+
*/
1922+
function genArrayExpression(node, context) {
1923+
const { push } = context
1924+
// 追加方括号
1925+
push('[')
1926+
// 为数组元素生成代码
1927+
genNodeList(node, context)
1928+
push(']')
1929+
}
1930+
```
1931+
1932+
```js
1933+
/**
1934+
* 生成节点列表
1935+
* @param {Array} nodes
1936+
* @param {Object} context
1937+
* @example
1938+
*/
1939+
function genNodeList(nodes, context) {
1940+
const { push } = context
1941+
for (let i = 0; i < nodes.length; i++) {
1942+
const node = nodes[i]
1943+
if (typeof node === 'string') {
1944+
push(`'${node}'`)
1945+
} else {
1946+
genNode(node, context)
1947+
}
1948+
if (i < nodes.length - 1) { // 最后一个参数不需要逗号
1949+
push(', ')
1950+
}
1951+
}
1952+
}
1953+
```
1954+
1955+
</div>
1956+
17501957
---
17511958

17521959
## compile 实现
@@ -1756,8 +1963,6 @@ function createCodegenContext() {
17561963
<div grid="~ cols-2 gap-2">
17571964

17581965
```js
1759-
// demo: 21-compile.html
1760-
17611966
/**
17621967
* 将模板编译为渲染函数字符串
17631968
* @param {String} template 模板
@@ -1781,6 +1986,8 @@ function baseCompile(template) {
17811986
```
17821987

17831988
```js
1989+
// demo: 21-compile.html
1990+
17841991
/**
17851992
* 将模板编译为渲染函数
17861993
* @param {String} template 模板
@@ -1879,6 +2086,7 @@ demo: `22-counter.html`
18792086
<div grid="~ cols-2 gap-2">
18802087

18812088
```html
2089+
<script src="./static/mini-vue.umd.js"></script>
18822090
<div id="app">
18832091
<div class="demo">
18842092
<button @click="minus">-1</button>
@@ -1916,12 +2124,3 @@ layout: center
19162124
---
19172125

19182126
# 感谢观看
1919-
1920-
---
1921-
1922-
## 参考
1923-
1924-
- 《Vue.js 设计与实现》by 霍春阳
1925-
- https://github.com/vuejs/core
1926-
- https://github.com/cuixiaorui/mini-vue
1927-
- https://github.com/tim101010101/beggar-vue

0 commit comments

Comments
 (0)