Skip to content

Commit

Permalink
Merge pull request #179 from ponyoxa/basic-template-compiler
Browse files Browse the repository at this point in the history
fix: 📌 typo
  • Loading branch information
ubugeeei authored Nov 12, 2023
2 parents 2704242 + 1c88546 commit 6994a24
Show file tree
Hide file tree
Showing 10 changed files with 39 additions and 39 deletions.
10 changes: 5 additions & 5 deletions book/online-book/src/50-basic-template-compiler/010-transform.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

さて、ここからはテンプレートのコンパイラをより本格的に実装していきます。
Minimum Example 部門でやったところから少し時間が空いてしまったので、今の実装がどうなっていたか少しおさらいをしておきましょう。
主ななキーワードは Parse, AST, Codegen でした。
主なキーワードは Parse, AST, Codegen でした。

![me_template_compiler_design](https://raw.githubusercontent.com/Ubugeeei/chibivue/main/book/images/me_template_compiler_design.drawio.png)

Expand Down Expand Up @@ -46,7 +46,7 @@ export function baseCompile(

## transform とは?

上記のコードでもなんとなく想像がつく通り、パースによって得られた AST を transform によってなんらかしらの形の変換しています
上記のコードでもなんとなく想像がつく通り、パースによって得られた AST を transform によってなんらかしらの形に変換しています

ここを読んでれば、なんとなく想像がつくかもしれません。
https://github.com/vuejs/core/blob/37a14a5dae9999bbe684c6de400afc63658ffe90/packages/compiler-core/src/ast.ts#L43C1-L51C23
Expand Down Expand Up @@ -115,7 +115,7 @@ type TemplateChildNode = ElementNode | InterpolationNode | TextNode;

このように、Codegen で生成されるコードを AST として表現したものが「生成するコードを表す AST」です。
今はこれをわざわざ分けるほどの利点が感じられないかもしれませんが、これからディレクティブを実装したりしていくにあたっては便利なのです。
input にちゃくもした AST と output に着目した AST に分ける感じで、`input の AST -> output の AST` の変換を行う関数こそが `transform` です。
input に着目した AST と output に着目した AST に分ける感じで、`input の AST -> output の AST` の変換を行う関数こそが `transform` です。

## Codegen Node

Expand All @@ -127,7 +127,7 @@ https://github.com/vuejs/core/blob/37a14a5dae9999bbe684c6de400afc63658ffe90/pack
この、"JS" から始まる Node + VNODE_CALL が output に着目した AST (以下 CodegenNode と呼びます) です。
しかし、CodegenNode の全てがこれらの Node で構成されているというわけではなく、ElementNode や InterpolationNode などを含んで構成されることになります。

今回扱うもの列挙しつつコメントで説明します。多少省略しているものもあるので、正確にはソースコードを参照してください。
今回扱うものを列挙しつつコメントで説明します。多少省略しているものもあるので、正確にはソースコードを参照してください。

```ts
export interface SimpleExpressionNode extends Node {
Expand Down Expand Up @@ -430,7 +430,7 @@ Codegen に入ってくる AST としては主に VNodeClass (とそれらが持

既存の Codegen は非常に簡素な実装になっているので、ここでもう少し形式的にしておきましょう。(結構ハードコードになっているので)
Codegen の方でも Codegen 用の context を持つことにして、生成したコードをそこに push していくような構成にしてみようと思います。
ついでに、context の方に幾つかのヘルパー関数を実装してみます (インデント系とか)
ついでに、context の方に幾つかのヘルパー関数を実装してみます (インデント系とか)

```ts
export interface CodegenContext {
Expand Down
10 changes: 5 additions & 5 deletions book/online-book/src/50-basic-template-compiler/020-v-bind.md
Original file line number Diff line number Diff line change
Expand Up @@ -75,10 +75,10 @@ export interface DirectiveNode extends Node {
name は v-bind や v-on などのディレクティブ名です。on や bind が入ります。
今回は v-bind を実装していくので、bind が入ります。

arg は `:` で指定する引数です。v-bind で言うと、 id や style などが入ります。
arg は `:` で指定する引数です。v-bind でいうと、 id や style などが入ります。
(v-on の場合は click や input などがここに入ってきます。)

exp は右辺です。`v-bind:id="count"` で言うと count が入ります。
exp は右辺です。`v-bind:id="count"` でいうと count が入ります。
exp も arg も、動的に変数を埋め込むことができるので、型は `ExpressionNode` になります。
( `v-bind:[key]="count"` のように arg も動的にできるので)

Expand Down Expand Up @@ -206,9 +206,9 @@ v-bind:id="count"
引用元: https://github.com/vuejs/core/blob/623ba514ec0f5adc897db90c0f986b1b6905e014/packages/compiler-core/src/transforms/vBind.ts#L13C1-L14C16

流れを見てもわかる通り、transformElement では directive の arg をチェックして、存在していなければ transformVBind を実行せず mergeProps と言う関数呼び出しに変換しています
流れを見てもわかる通り、transformElement では directive の arg をチェックして、存在していなければ transformVBind を実行せず mergeProps という関数呼び出しに変換しています

`v-bind="hoge"`の形式で渡された引数と、そほのかの props をマージする関数です。
`v-bind="hoge"`の形式で渡された引数と、そのほかの props をマージする関数です。

```vue
<p v-bind="bindingObject" class="my-class">hello</p>
Expand All @@ -225,7 +225,7 @@ https://vuejs.org/api/built-in-directives.html#v-bind

normalizeClass と normalizeStyle という関数を実装し、それぞれに適用します。

arg が動的な場合は、特定が不可能なため、normalizeProps と言う関数を実装し、それを呼び出すようにします。 (内部で normalizeClass と normalizeStyle を呼び出します)
arg が動的な場合は、特定が不可能なため、normalizeProps という関数を実装し、それを呼び出すようにします。 (内部で normalizeClass と normalizeStyle を呼び出します)

さてここまで実装できたら動作を見てみましょう!

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -196,7 +196,7 @@ export function walkIdentifiers(
}
```

あとは式の AST を生成し、この関すに渡して node を書き換えながら transform を行なっていけばいいです。
あとは式の AST を生成し、この関数に渡して node を書き換えながら transform を行なっていけばいいです。

## transformExpression の実装

Expand Down Expand Up @@ -372,7 +372,7 @@ export function processExpression(node: SimpleExpressionNode): ExpressionNode {

続いて 2 です。ここで新しい AST Node を定義します。`CompoundExpressionNode`というものです。
Compound には「配合」「複合」といった意味が含まれます。
この Node は children をもち、これらは少し特殊な値を撮ります
この Node は children をもち、これらは少し特殊な値をとります
まずは AST の定義をご覧ください。

```ts
Expand Down
20 changes: 10 additions & 10 deletions book/online-book/src/50-basic-template-compiler/025-v-on.md
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ export function createTransformContext(
}
```

あとは、ハードコードしてしまっている部分をこの helper 関数に置き換えて、Preamble では登録された helper をしようするように書き換えます
あとは、ハードコードしてしまっている部分をこの helper 関数に置き換えて、Preamble では登録された helper を使用するように書き換えます

```ts
// 例)
Expand Down Expand Up @@ -349,15 +349,15 @@ app.mount("#app");
```

- 課題 2
その場で関数式をかける
その場で関数式を書ける
この場合には、第 1 引数としてイベントを受け取ることができます。

```html
<button v-on:click="(e) => increment(e)">increment</button>
```

- 課題 3
関数以外の文を書かける
関数以外の文を書ける

```html
<button @click="count = 0">reset</button>
Expand All @@ -372,7 +372,7 @@ app.mount("#app");
```

- 課題 4
課題 3 のような場合には `$event` というという識別子が使える
課題 3 のような場合には `$event` という識別子が使える
こちらはイベントオブジェクトを扱うケースです。

```ts
Expand Down Expand Up @@ -494,7 +494,7 @@ Vue では、単体の Identifier か、単体の MemberExpression, 関数式
それ以外が文です。ソースコード上は inlineStatement という名前で通じているようです。

```ts
// function (※ 便宜セミコロンがついてしまっていますが、これらは関数式だと思ってください。)
// function (※ 便宜上セミコロンがついてしまっていますが、これらは関数式だと思ってください。)
increment;
state.increment;
() => count++;
Expand All @@ -509,11 +509,11 @@ increment($event);

1. まずは関数かどうかを判定する (単体の Identifier or 単体の MemberExpression or 関数式)

2-1. 関数であった場合には特に何も変形せずに `eventName: exp` と言う形式で ObjectProperty を生成する
2-1. 関数であった場合には特に何も変形せずに `eventName: exp` という形式で ObjectProperty を生成する

2-2. 関数でなかった場合 (inlineStatement だった場合) 、 <span v-pre> `$event => { ${exp} }`</span> と言う形式に変換し、ObjectProperty を生成する
2-2. 関数でなかった場合 (inlineStatement だった場合) 、 <span v-pre> `$event => { ${exp} }`</span> という形式に変換し、ObjectProperty を生成する

と言った感じになります
といった感じになります

#### 関数式か、文かの判定

Expand All @@ -534,7 +534,7 @@ const isMemberExp = isMemberExpression(exp.content);
```

この、`isMemberExpression` は結構泥臭く、長々と実装してあります。ちょっと長いので、ここでは省略します。(ぜひコードを読んでみてください。)
MemberExpression と言うと`parent.prop`のような形式を推察しますが、度やらこの関数では `ident` のようなルートレベルのものも true として判定しているようです。
MemberExpression というと`parent.prop`のような形式を推察しますが、どうやらこの関数では `ident` のようなルートレベルのものも true として判定しているようです。

ここまで判定できたら、inlineStatement である条件はこれら以外のものですから、以下のような判定になります。

Expand Down Expand Up @@ -568,7 +568,7 @@ if (isInlineStatement) {
というのも、`dir.exp` 中では setup からバインドされた値を扱うので processExpression を噛ませないといけないのですが、問題は `$event` です。
AST 上は `$event` も Identifier 扱いなので、このままでは `_ctx.` prefix がついてしまいます。

そこで少し工夫をしていみます
そこで少し工夫をしてみます
transformContext に ローカル変数を登録するようにします。そして、walkIdentifiers の方では、ローカル変数がある場合には onIdentifier を実行しないようにします。

```ts
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ app.mount("#app");

テンプレートの新しいシンタックスを追加するわけなので、Parser と AST の変更が必要になります。

ますは AST を見てみましょう。これはとっても簡単で、`DirectiveNode``modifiers` というプロパティ(string の配列)を追加するだけです。
まずは AST を見てみましょう。これはとっても簡単で、`DirectiveNode``modifiers` というプロパティ(string の配列)を追加するだけです。

```ts
export interface DirectiveNode extends Node {
Expand Down Expand Up @@ -109,7 +109,7 @@ function parseAttribute(

![50-027-compiler-architecture](https://raw.githubusercontent.com/Ubugeeei/chibivue/main/book/images/50-027-compiler-architecture.drawio.png)

compiler-core と compiler-dom のそれぞれの役悪を改めて理解してみると
compiler-core と compiler-dom のそれぞれの役割を改めて理解してみると
compiler-core は DOM に依存しないコンパイラの機能を提供するもので、AST の生成や、その変換を行います。

これまでに、v-on ディレクティブなどを compiler-core に実装しましたが、これは`@click="handle"` という記述を `{ onClick: handle }` というオブジェクトに変換しているだけで、
Expand All @@ -136,9 +136,9 @@ export type DirectiveTransform = (
```

augmentor というものを追加してみました。
まぁ、これはただのコールバック関数です。 `DirectiveTransform` の interface としてコールバックを受け取れようにして、transform 関数を拡張可能にしています。
まぁ、これはただのコールバック関数です。 `DirectiveTransform` の interface としてコールバックを受け取れるようにして、transform 関数を拡張可能にしています。

compiler-dom の方では、compiler-core で実装した transformer をラップした transformer の実装をして行くようにします
compiler-dom の方では、compiler-core で実装した transformer をラップした transformer の実装をしていくようにします

```ts
// 実装イメージ
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ return の先がおかしなことになってしまっていますね。今の

## どういうコードを生成すればいいのか

修正していくとはいえ、どう言うコードを生成できるようになれば良いでしょうか
修正していくとはいえ、どういうコードを生成できるようになれば良いでしょうか

結論から言うと以下のようなコードになります。

Expand All @@ -63,7 +63,7 @@ return function render(_ctx) {
};
```

この `Fragment` と言うものは Vue で定義されている symbol です。
この `Fragment` というものは Vue で定義されている symbol です。
つまり、Fragment は FragmentNode のような AST として表現されるものではなく、単に ElementNode の tag として表現されます。

そして、tag が Fragment あった場合の処理を renderer に実装します。
Expand Down Expand Up @@ -253,6 +253,6 @@ const app = createApp(App);
app.mount("#app");
```

ちゃんど動作しているようです
ちゃんと動作しているようです

ここまでのソースコード: [GitHub](https://github.com/Ubugeeei/chibivue/tree/main/book/impls/50_basic_template_compiler/030_fragment)
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ app.mount("#app");

## AST とパーサの実装

コメントアウトどう実装するかですが、一見 パースするときに無視してしまえばいい感じもします。
コメントアウトをどう実装するかですが、一見 パースするときに無視してしまえばいい感じもします。

しかし、Vue のコメントアウトは、template に記述したものがそのまま HTML として出力されるようになっています。

Expand Down Expand Up @@ -214,7 +214,7 @@ const processCommentNode = (
) => {
if (n1 == null) {
hostInsert(
(n2.el = hostCreateComment((n2.children as string) || "")), // hostCreateComment を nodeOps 側に実装しましょう!s
(n2.el = hostCreateComment((n2.children as string) || "")), // hostCreateComment を nodeOps 側に実装しましょう!
container,
anchor
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ angular のドキュメントだと項目として明記されていたりもし

https://angular.jp/guide/structural-directives

v-if や v-for は単にその要素の属性(+イベントに対する振舞い)を変更するだけでなく、要素の存在切り替えたり、リストの数に応じて 要素を生成・削除したりと、要素の構造を変更するディレクティブです。
v-if や v-for は単にその要素の属性(+イベントに対する振舞い)を変更するだけでなく、要素の存在を切り替えたり、リストの数に応じて 要素を生成・削除したりと、要素の構造を変更するディレクティブです。

## 目指す開発者インターフェース

Expand Down Expand Up @@ -96,7 +96,7 @@ function render(_ctx) {

::: warning

現時点での実装では空白などの読み飛ばしの実装を行っていないので実際には間に余計いな文字 Node がはいてってしまうかと思います
現時点での実装では空白などの読み飛ばしの実装を行っていないので実際には間に余計な文字 Node が入ってしまうかと思います

が、 v-if の実装上は特に問題ありませんので(後でわかります)、今回は無視してください。

Expand All @@ -106,7 +106,7 @@ function render(_ctx) {

### 構造にまつわるメソッドを実装する

v-if の実装を行って行く前に、少し準備です。
v-if の実装を行っていく前に、少し準備です。

最初にも v-if や v-for という構造的ディレクティブは AST Node の構造を変更するディレクティブであるということを説明しました。

Expand Down Expand Up @@ -580,7 +580,7 @@ function createIfBranch(node: ElementNode, dir: DirectiveNode): IfBranchNode {
次は v-if 以外の場合を考えてみましょう。

context から parent の children を辿って siblings を取得し、
現在の node (自身) から順にループを回し、自信をもとに IfBranch を生成して branches に push していきます。
現在の node (自身) から順にループを回し、自身をもとに IfBranch を生成して branches に push していきます。
この際、コメントや空のテキストは削除してしまいます。

```ts
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ export default {

## 実装方針

まず、軽くどういうふうにコンパイルしたいののかということを考えてみて、実装する際に難しそうなポイントはどこなのかということについて考えてみましょう。
まず、軽くどういうふうにコンパイルしたいのかということを考えてみて、実装する際に難しそうなポイントはどこなのかということについて考えてみましょう。

まず、目指したいコンパイル結果から見てみましょう。

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,7 @@ function render(_ctx) {

### AST

コンポーネントとして解決すコードを生成するためには、"MyComponent" がコンポーネントであることを知っている必要があります。
コンポーネントとして解決するコードを生成するためには、"MyComponent" がコンポーネントであることを知っている必要があります。
parse の段階で、タグ名をハンドリングして、AST 上は通常の Element と Component で分けるようにします。

まずは AST の定義を考えてみましょう。
Expand Down Expand Up @@ -192,7 +192,7 @@ export interface ComponentNode extends BaseElementNode {

問題は、どうやって Element なのか Component なのかを判断するかです。

基本的な何考え方は単純で、"ネイティブなタグかどうか" を判断するだけです。
基本的な考え方は単純で、"ネイティブなタグかどうか" を判断するだけです。

Expand Down Expand Up @@ -499,7 +499,7 @@ function genAssets(

### runtime-core 側の実装

ここまでくれば目的のコードは生成できているので、あとは runtime-core の実装です。
ここまでくれば目的のコードは生成できているので、あとは runtime-core の実装です。

#### コンポーネントのオプションとして component を追加できるように

Expand Down

0 comments on commit 6994a24

Please sign in to comment.