EJSを使って スクリプトなどをヒアドキュメントっぽくextends する

この記事は Node.js Advent Calendar 2013 20日目の記事です。

概要

Node.js というか express で使っているテンプレート ejs でのお話です。

expressで実装していて、この書き方で良いのかなという疑問があるので今回書いてみました。

Node.jsの フレームワーク、express ではデフォルトでテンプレートエンジン Jade を使用しますが、オプションで EJS を使用することも出来ます。

以下、EJSでの利用フロー。

EJS を使う上で共通部分を一括管理したいので express-locals をインストールし、app.js で反映させます。

npm install ejs-locals --save

この ejs-localsで Viewの 共通レイアウトを layout.ejs として メインレイアウト index.ejs を表示しようとします。

するとこう。

app.js(抜粋)

var app = express();

// use ejs-locals for all ejs templates:
app.engine('ejs', require('ejs-locals')); //ここ追加

// all environments
app.set('port', process.env.PORT || 3000);
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'ejs');
 

layout.ejs

<!DOCTYPE html>
<html>
  <head>
    <title><%= title %></title>
    <link rel='stylesheet' href='/stylesheets/style.css' />
    <!-- header scripts -->
  </head>
  <body>
   
    <header>
      <h1><%= title %></h1>
    </header>

    <%- body %>

    <footer>Copyright hoge</footer>
    <!-- footer scripts -->
  </body>
</html>

index.ejs

<% layout('layout') -%>

<p>Welcome to <%= title %></p> 

layout.ejs<%- body %> の部分が index.ejs で記述されている内容となります。

ここまではよくあるのですが、ページによってはどうしても script を書き込む所を指定したくなります。

今のままだと <%- body %> に各 view がインクルードされているだけです。

場合によっては、このスクリプトは head の中に、あのスクリプトは </body> の直前にと設定したいのです。

( ※上記 layout.ejs の<!-- header scripts --><!-- footer scripts --> 部分)

もう少し柔軟(?)に記述するために、ejs-localsのサンプルをみましょう。

ejs-locals Features

  • layout(view)
  • partial(name,optionsOrCollection)
  • block(name,html)
  • script(src,type)
  • stylesheet(href,media)

用途としては layout.ejs 内の特定の場所に index.ejs からソースを記述したいので blockが使えそう。

layout.ejs

<!DOCTYPE html>
<html>
  <head>
    <title><%= title %></title>
    <link rel='stylesheet' href='/stylesheets/style.css' />
    
    <!-- header scripts -->
    <%- blocks.header_scripts %>
  </head>
  <body>

    <header>
      <h1><%= title %></h1>
    </header>

    <%- body %>

    <footer>Copyright hoge</footer>
    <!-- fotter scripts -->
    <%- blocks.footer_scripts %>
  </body>
</html>

index.ejs

<% layout('layout') -%>

<p>Welcome to <%= title %></p>

<% block("header_scripts", "<script src='hoge.js'></script>") -%>
<% block("footer_scripts", "<script src='fuga.js'></script>") -%> 

こうすることで、layout.ejs の任意の場所にindex.ejs から 特定のタグを文字列で埋め込めるようになりました。

はい、文字列で。

これだと直接 スクリプト を書こうと思った時、文字列で結合するのがとてもめんどくさい。

で、以下のサイトを参考にしてみました。

するとこうなりました。。。

index.ejs

<% layout('layout') -%>

<p>Welcome to <%= title %></p>

<% var header_scripts = (function () {/*
<script>	
	if( location.href == "なんちゃら" ){
		//何かの処理
	}
</script>
*/}).toString().match(/[^]*\/\*([^]*)\*\/\}$/)[1]; %>
<% block("header_scripts", header_scripts) -%>


<% var footer_scripts = (function () {/*
<script>
( function( d, w ){
  
  if(w.console){
  	w.console.log("Hello");
  }
})( document, window );
</script>
*/}).toString().match(/[^]*\/\*([^]*)\*\/\}$/)[1]; %>
<% block("footer_scripts", footer_scripts) -%> 

これもどうよ?という感じなのですが、一応やりたいことは実現出来たので今の所これで書いています。

なにか良さげな方法があれば教えて下さい。

ということで、本日担当の私からは以上です。