JUST-JavaScriptテンプレートエンジン

以前の 2つの記事で説明したNode.JSでの実験的なWEBプロジェクトの開発中に、テンプレートエンジンを選択する問題に遭遇しました。 既製のソリューションがかなりあるにもかかわらず、100%満足できるソリューションは見つかりませんでした。 それでJUSTが生まれました。



競合他社



ヒスイ
github.com/visionmedia/jade



このテンプレートエンジンはNode.JS開発者の間で非常に人気があります。 機能と速度は優れていますが、議論の余地のある点も含まれています。

  1. 実際にそれらが発明された場所でタグを使用することの拒否。 このアプローチでは、控えめに言っても同意しません。 もちろん、これは非常に主観的ですが、通常のタグのない種類のページレイアウトは脳を爆発させます。 標準化の新しい技術とはほど遠いタイプセッターは、そのようなコードを変更しなければならない場合、感謝を表明しません。 また、レイアウトをテンプレートに転送するときに追加の作業が必要になり、開発プロセスが遅くなります。
  2. 機能がオーバーロードされています。 すべての開発者は自分の製品を可能な限り多目的にしようとしますが、時間通りに停止できる必要がある場合があります。 私の意見では、ジェイドはすでにその境界線を越えています。
Ejs
github.com/visionmedia/ejs



小さく、高速で、かなり便利なテンプレートエンジン。 シンプルで理解しやすいものですが、残念ながら、大規模なプロジェクトの場合、その機能は十分ではありません。 箱から出してすぐに、彼は部品からページを組み立てる方法を知りませんが、これはExpressで行われるような小さな追加によって部分的に解決されます。 しかし、松葉杖は私たちの方法ではありません。



Twigjs
github.com/fadrizul/twigjs



名前が示すように、これはかなり人気のあるJavaScript PHPテンプレートエンジンの移植版です。 このテンプレートエンジンはバランスが取れていますが、理想とは言えません。 ロジックを実装するために、開発者は開発を容易にする独自の構文を追加しました。 このアイデアは成功していないようです。 これにより、開発への参入のしきい値が高くなります。 PHPであろうとJavaScriptであろうと、レイアウトデザイナーやプログラマーは、別の構文の学習に時間を費やし、そのロジックを掘り下げ、その変化を監視する必要があります。 この瞬間は非常に物議を醸しています。 多くの開発者は、この構文糖質に満足しています。 しません。



シンプル、高速、便利



これら3つの特性がJUSTの基礎を形成しました。 テンプレートエンジンは、あらゆるWEBプロジェクトの最も重要な詳細の1つです。 完全にキャッシュされたページを除き、すべてのリクエストで機能します。 テンプレートを使用した作業がプロジェクトの開発のどの段階でも喜びをもたらすためには、テンプレートエンジンは最初はなめたいようなものでなければなりません。



それだけ

要点をつかむ



JUSTテンプレートの簡単な例:



page.html

<%! layout %> <p>Page content</p>
      
      





layout.html

 <html> <head> <title><%= title %></title> </head> <body><%*%></body> </html>
      
      





これらのテンプレートと転送されたデータから最終的なHTMLを生成するコードは次のようになります。



 var JUST = require('just'); var just = new JUST({ root : __dirname + '/view' }); just.render('page', { title: 'Hello, World!' }, function(error, html) { console.log(error); console.log(html); });
      
      





より完全な例はGutHubリポジトリにあります。

クライアントでは、すべてが同じように機能します。 まず、JUSTをページに接続する必要があります。



 <script src="https://raw.github.com/baryshev/just/master/just.min.js" type="text/javascript"></script>
      
      





これで、JUSTはNode.JSとまったく同じ方法で使用できます。



 var just = new JUST({ root : '/view' }); just.render('page', { title: 'Hello, World!' }, function(error, html) { console.log(error); console.log(html); });
      
      





なぜなら クライアントバージョンでは、テンプレートはAJAXを使用してロードされ、スクリプトを含むページと同じドメインに存在する必要があります。



JUSTはJavaScriptオブジェクトをルートとして使用できます。 この機能は便利な場合があります。



 var just = new JUST({ root : { layout: '<html><head><title><%= title %></title></head><body><%*%></body></html>', page: '<%! layout %><p>Page content</p>' } });
      
      





仕組み



テンプレートは、単純なアルゴリズムによってパーツに分解され、文字列の連結を実行する関数に変換され、データをパラメーターとして受け入れて結果を形成します。 この関数はキャッシュされ、さらに機能するだけです。 再解析は、アプリケーションが再起動されたとき、またはテンプレートファイルが変更されたときにのみ行われます(watchForChangesオプションがtrueに設定されている場合)。 このアプローチは、優れたパフォーマンスを提供します。 「 何をする? »解析テンプレートを含むページは20〜60ミリ秒で生成されました。 テンプレートを(キャッシュされた関数から)1〜2ミリ秒解析しません。 解析はテンプレートごとに1回だけ発生し、アプリケーションは長期間存続することを考慮すると、テンプレートの解析時間は無視できます。



テンプレートエンジンに送信されたデータは、ページの構築に関係するすべてのテンプレートに対して「スルー」で表示されます。 これにより、親または子テンプレートに手動で転送する必要がなくなりますが、手動でデータを転送する可能性があります。



JUSTにできること



データ出力


テンプレートへのデータ出力は、シンプルなデザインを使用して実行されます。



 <%= varName %>
      
      





データはそのままテンプレートに挿入されます。 テンプレートエンジンでの前処理は行われません。



Javascriptロジック


テンプレートでは、本格的なJavaScriptコードを使用できます。 例:



 <% for (var i = 0; i < articles.length; i++) { %> <% this.partial('article', { article: articles[i] }); %> <% } %>
      
      





または



 <% if (user.authenticated) { %> <%@ partials/user %> <% } else { %> <%@ partials/auth %> <% } %>
      
      





または



 <%= new Date().toString() %>
      
      





テンプレートの継承


実践からわかるように、継承は非常に便利なツールであり、ページをボトムアップで構築できます。 JUSTの継承操作は次のとおりです。



 <%! layout %>
      
      





または



 <% this.extend('layout', { customVar: 'Hello, World!' }); %>
      
      





追加のパラメーターを親テンプレートに渡す必要がある場合。 継承操作はテンプレート内のどこにでも配置できますが、上または下に挿入する方が便利です。



親テンプレートの子の挿入ポイントで、次の構成を挿入する必要があります。



 <%*%>
      
      





または



 <% this.child(); %>
      
      





パターンインジェクション


この操作により、外部テンプレートを呼び出し場所に接続し、必要に応じて必要なパラメーターを指定できます。



 <%@ partial %>
      
      





または



 <% this.partial('partial', { customVar: 'Hello, World!' }); %>
      
      





追加のパラメーターをプラグインテンプレートに渡す必要がある場合。



ブロックの再定義


このメカニズムは、継承にやや似ています。 親テンプレートでは、子を挿入する場所に加えて、ブロックを挿入する場所を宣言できます。 これらのブロックの内容は、子テンプレートで定義されます。 継承とは異なり、ブロックの再定義は最上位で機能します。 任意のテンプレートから、親のブロックだけでなく、親のブロックの内容を決定できます。 ブロックを決定するには、次の構成が使用されます。



 <%[ blockName %> <p>This is block content</p> <%]%>
      
      





または



 <% this.blockStart('blockName'); %> <p>This is block content</p> <% this.blockEnd(); %>
      
      





親テンプレートのいずれかで、次の構成を使用してブロックの挿入位置を決定する必要があります。



 <%* blockName %>
      
      





または



 <% this.child('blockName'); %>
      
      





ブロックは再定義できます。 結果は、最下位レベルで定義されたブロックです。



JUSTにはないもの



データフィルター


ほとんどすべてのテンプレートエンジンには、HTML生成の段階でデータを操作できるフィルターセットが含まれています。 例:タグのエスケープ、文字のキャスト、文字列の切り捨て。 このアプローチは根本的に間違っており、この機能はここではありません。



「このアプローチはMVCに対応していない」などの異論は、この主題に関するコメントに必ず記載されます。 エスケープタグとは、HTML / XML形式のデータの表示のみを指し、PDFなどのエスケープが不要な形式で表示したい場合があります。 したがって、この機能はテンプレートエンジンに含まれている必要があります」。



これについての紛争を防ぐために、私はすぐにこの質問に答えます。



テンプレートエンジンは、MVCの「V」モデルの純粋なコンポーネントではありません。 特別な場合として、それは可能性がありますが、絶対に義務ではありません。 「プレゼンテーション」コンポーネントには、応答を直接作成する手段(テンプレートエンジン)と、特定のプレゼンテーション用のデータを準備する手段の両方を含めることができます。 この時点で、データを準備してキャッシュできます。 このアプローチにより、大量の不要なデータ操作を実行しないようにすることができます。 文字列操作がかなり遅いことを考えると、これは無視できません。 1行または1万行の行の置換回数を気にしない場合、悪いニュースがあります。



論理用語での構文糖


別のファッショントレンドは、独自のテンプレート構文を発明することです。 ほとんどの場合、ブラケットの切り取りなどになります。 言語構造を減らします。 これによる利益は非常に疑わしいです。 開発者はもう1つの構文を知っている必要があり、新しいバージョンのテンプレートエンジンの作成者が「さらに便利に」なることを望み、更新後もテンプレートは引き続き機能します。 言語のネイティブ構文は、開発に関わるすべての人に知られています。 新しい開発者はすぐにビジネスに参入でき、非常に便利な構文の作業を掘り下げることはできません。 プログラマが作成物を細かく分割することをほとんど気にしないレイアウトデザイナーは、テンプレート自体に小さな変更を加えたり、ロジックを微調整することさえできます。 それにもかかわらず、彼らはサービスのためにJavaScriptを知っています。



軟膏で飛ぶ



JUSTでの不愉快な瞬間はまだそこにあります。 テンプレートが未定義の変数にアクセスできる場合、そのテンプレートが処理されると、存在しない変数にアクセスするとReferenceErrorが発生します。 この動作の理由と、修正に失敗した理由について少しお話ししたいと思います。



テンプレート内の変数にアクセスするには、3つの方法があります。
  1. %object%。%Var%の構築による変数へのアクセス。 たとえば、this.varNameまたはdata.varName。 この場合、未定義を参照する場合、エラーは発生せず、この場所のテンプレートに空の行が表示されますが、最終的には、変数のプレフィックスにより非常に大きなテンプレートが取得されます。
  2. %object%。%Var%構造を介してアクセスするための変数へのオートコレクトの直接アクセス。 たとえば、テンプレートに<%= varName%>コンストラクトがある場合、それを解析するときにthis.varNameに簡単に置き換えることができ、未定義の変数によるエラーを排除できます。 ただし、変数へのアクセスは、データ出力の構築だけでなく、ロジックでも可能です。 たとえば、ループ内で配列を走査したり、条件ステートメントに参加したりします。 追加の解析なしでは、そのような場所では変数へのアクセスを自動的に置き換えることはできません。
  3. withを使用して、テンプレートデータを持つオブジェクトをスコープに追加します。 スコープ内にデータを持つオブジェクトを配置すると、オブジェクトプレフィックスなしでそれらにアクセスできますが、未定義の変数にアクセスするとエラーが発生します。
現時点では、テンプレートをさらに解析せずにこの状況を回避する方法はわかりません。 誰かがこの問題の美しい解決策を見つけた場合、それについて読むことは非常に興味深いでしょう。 今のところ、これはこのテンプレートエンジンの機能として受け入れられる必要があります。 ある意味では、このアプローチは規律があり、未定義の変数を散在させることはできません。



All Articles