200行のAngularコンパイラ

こんにちは 私の名前はローマです。私は自転車の発明者ではありません。 私はAngularフレームワークとそれを取り巻くエコシステムが好きで、それを使ってWebアプリケーションを開発しています。 私の観点から見ると、Angularの長期的な主な利点は、HTMLとTypeScriptのコードの分離に基づいています。開発者の1人が詳細に説明しました。why-angular-renders-components-with.html実行時にコンポーネントを動的にコンパイルする複雑さ。 そして、使い慣れたAngularテンプレート構文を使用して、ユーザーがアプリケーションでレターテンプレートをカスタマイズしたり、印刷用のレポートやスプレッドシートを生成したり、xmlファイルのエクスポート形式を設定したりできるようにします! これを行う方法を見つけるには、猫へようこそ!



挑戦する



一般に、ユーザーによるAngularテンプレートの使用は次のようになります。特定のデータセットがあります。



const data = { project: 'MySuperProject', userName: 'Roman', role: 'admin', projectLink: 'https://example.com/my-super-projectproject' }
      
      





プロジェクトの編集後にユーザーに送信されるレターのテキストを設定する機会を与える必要があります。 Angularテンプレートを使用すると、次のようになります。



  <body>  !  {{project}}    <a href="{{projectLink}}">3D   </a> <div *ngIf="role == 'admin'">       <a href="{{projectLink}}?mode=edit"></a> </div> </body>
      
      





ng-templateライブラリ



この問題は、クライアント(またはサーバー側)でAngularコンパイラを使用して解決できますが、非常に時間がかかり、多くのメガバイトのコードをクライアントにドラッグする必要があります。 なぜAngularコンパイラはそんなに大きいのですか? これは、コンポーネントとモジュールを構成するための多様な機能の海をサポートし、独自のHTMLパーサーが含まれているという事実によるものです! そこで、ブラウザーに組み込まれたHTMLパーサーを使用する最小限のAngularテンプレートコンバーターを作成することにしました。 わずか数行のコードで、わずか数時間でこれをたった200で実行できました。 結果をGitHubで公開することにしました



ng-templateライブラリの使用は非常に簡単です。



npmから依存関係をインストールする



 npm install --save @quanterion/ng-template
      
      





または糸を通して



 yarn add @quanterion/ng-template
      
      





そして、次のように使用します。



 import { compileTemplate, htmlToElement } from '@quanterion/ng-template'; async test() { let data = { name: 'Roman' }; let element = htmlToElement(`<div>{{name}}</div>`); await compileTemplate(element, data); alert(element.outerHTML); }
      
      





サポートされている構文



  1. 変数にアクセスして関数を呼び出す機能を備えた式{{expression}}
  2. NGテンプレート
  3. NGコンテナ
  4. 条件* ngIf + * ngIf as
  5. サイクル* ngFor
  6. スタイル[style.xxx] = "value"および[style.xxx.px] = "value"
  7. 条件付きクラス[class.xxx] = "value"
  8. 値への自動サブスクリプションを使用したオブザーバブル{{name $}}(非同期パイプとして)


詳細については、 ng-template.spec.tsテストを参照してください。



Evalを使用する



テンプレート内の式を評価するには、evalを好みと遊女とともに使用します。 実際のところ、Angularテンプレートでは、変数へのアクセスは通常のJavaScriptプレフィックスなしで使用されます。 したがって、eval()を呼び出す必要があります。これには、スコープ内のデータオブジェクトからのすべての変数が含まれます。 私はeval()のようなコードを生成することに成功しませんでした コードを見る



 const data = { a: 1, b: () => 4 }; const expression = 'a+b()'; eval('a =1; b = ??;' + expression);
      
      





関数を渡すことはできません



解決策は、データにオブジェクトのフィールド名を持つパラメーターを持つ関数を作成することで見つかりました。



 const data = { a: 1, b: () => 4 }; let entries = [] for (let property in data ) { entries.push([property, data[property]]) } const params = entries.map(e => e[0]); const fun = new Function('code', ...params, `return eval(code)`); const args = entries.map(e => e[1]); const expression = 'a+b()'; const result = fun.call(undefined, expression , ...args);
      
      





PS:将来、新しいIvyコンパイラのAPIが安定すると、Ivyの一連の演算子を生成し、ダイナミクスで本格的なコンポーネントを作成できるようになることを願っています。



ソースへのリンク



All Articles