プログラミング

Pug(旧Jade)テンプレートファイル内で、npmでインストールしたモジュールを使う方法

投稿日:2016年6月16日 更新日:

Pug(旧Jade)というJavaScriptのテンプレートエンジンがありますが、このテンプレートファイル内では JavaScriptが使えるので、複雑なHTMLを生成することができます。
但しデフォルトの状態だと、npmでインストールしたモジュールを呼び出して使うことができないため、ある程度込み入った処理を書くのは面倒です。

このページでは、Pugのテンプレートファイル内から npmでインストールしたモジュールを呼び出すための手順を説明します。

手順

  • pugコマンドだとできないようなので、面倒ですが自分で「pugテンプレートファイルをHTMLに変換する JavaScriptコード」を書き、それを nodeコマンドで実行します。
    • (リンク先では jadeコマンドになっていますが、pugコマンドに読み替えてください。)
  • pugモジュールのコンパイルを行うメソッド(何種類かあります)の options引数と、そのメソッドの戻り値(関数が返ります)の引数に、Pugテンプレートファイル内で使用したいオブジェクトをセットしておけばOKです。

このサイトで実際に使っているJavaScriptを載せておきます(そのままではないですが)(注意:現在このサイトでは使用していません)。

以下が前提となっています。

  • ./src/html ディレクトリ以下の全ての階層にある Pugテンプレートファイル(拡張子は pug か jade)を、./public ディレクトリ以下に同じ階層のままHTMLファイルに変換して出力します。
  • pugモジュールなどは、npmコマンドで導入します(他にどんなモジュールが必要なのかは下のJavaScriptコードを参照して下さい)。
    $ npm install --save-dev pug
    
  • JavaScriptのファイル名は、runPug.jsとします。
  • Pugテンプレートファイル内で、_ が使えるようにします(中身は lodash)です。
  • 以下のコマンドで実行すると、HTMLファイル生成処理が実行されます。
    $ node runPug.js
    
  • Windows 7 上の MSYS2環境でテストしています。

JavaScriptファイルの内容

  • だいたい以下のような JavaScriptコードになっています。
    /**
     *
     * 以下のページを参考にした。
     * cf. pug-cli/index.js at 1.0.0-alpha5 · pugjs/pug-cli
     *     https://github.com/pugjs/pug-cli/blob/1.0.0-alpha5/index.js
     *
     */
    
    var fs = require('fs'),
        path = require('path'),
        _ = require('lodash'),
        pug = require('pug'),
        program = require('commander'),
        mkdirp = require('mkdirp');
    
    var siteJson = require('./src/data/site.json'),
        // 元となるpugファイルが入っているディレクトリパス(末尾にスラッシュはつけない)
        srcPath = './src/html',
        // 出力先のディレクトリパス(末尾にスラッシュはつけない)
        dstDirPath = './public',
        options = {};
    
    var basename = path.posix.basename;
    var dirname = path.posix.dirname;
    var resolve = path.posix.resolve;
    var join = path.posix.join;
    var relative = path.posix.relative;
    
    //--------------
    // 引数の処理
    //--------------
    // cf. pug-cli/index.js at 1.0.0-alpha5 · pugjs/pug-cli
    //     https://github.com/pugjs/pug-cli/blob/1.0.0-alpha5/index.js
    program
      .version('1.0.0')
      .option('-P, --pretty', 'compile pretty HTML output')
      .option('-D, --no-debug', 'compile without debugging (smaller functions)')
      .parse(process.argv);
    
    //-------------------
    // optionsを設定する
    // - pugテンプレートファイルに、npmで入れたモジュールを渡す場合は、ここで optionsにassignする。
    //-------------------
    // siteJsonオブジェクトをテンプレートから使えるようにする
    _.assignIn(options, siteJson);
    // lodashをPugテンプレートファイル内から使えるようにする
    _.assignIn(options, { _: _ } );
    
    [
      // command option, compile option
      ['debug', 'compileDebug'], // --no-debug
      ['pretty', 'pretty']       // --pretty
    ].forEach(function (o) {
      'use strict';
      if (program[o[0]] !== undefined) {
        options[o[1]] = program[o[0]];
      }
    });
    
    //-----------------
    // メイン処理
    //-----------------
    // 各ファイル毎に pug でコンパイルして HTMLファイルを生成する
    eachFiles(srcPath, null, function(filePath, rootPath) {
      'use strict';
    
      if (!/.*\.(?:pug|jade)$/.test(filePath)) { return }
    
      // 出力ファイルパスを生成
      var dstFilePath = createDstFilePath(filePath, rootPath);
    
      // 出力先パス上に存在しないディレクトリがあれば作っておく
      var dir = resolve(dirname(dstFilePath));
      mkdirp.sync(dir);
    
      // pugファイルをコンパイルしてファイルとして保存する
      // compileFile()とfn()には同じオプション用オブジェクトを渡せば良い
      var fn = pug.compileFile(filePath, options);
      fs.writeFileSync(dstFilePath, fn(options));
      console.log('renderd src:', filePath, 'dst:', dstFilePath);
    });
    
    //------------------
    // Helper functions
    //------------------
    
    /**
     * 出力先ファイルパスを生成して返す関数
     * @param {string} filePath
     * @param {string} rootPath
     */
    function createDstFilePath(filePath, rootPath) {
      'use strict';
    
      var dstPath = filePath.replace(/\.(?:pug|jade)$/, '.html');
    
      if (rootPath) {
        // rootPathを基準とした相対パスを生成する
        // 空になることはほぼない
        dstPath = relative(rootPath, dstPath);
      } else {
        dstPath = basename(dstPath);
      }
      return './' + join(dstDirPath, dstPath);
    }
    
    /**
     * 特定のパス以下のファイルを順番に処理していく関数
     *
     * 以下のページに載っていたのを少し修正して使っている。
     * cf. node.jsでディレクトリ内のファイル全てに対して処理を回す関数 | hacknote
     *     http://hacknote.jp/archives/11249/
     *
     * @param {string} filePath
     * @param {string} rootPath
     * @param {callback} callback
     */
    function eachFiles(filePath, rootPath, callback) {
      'use strict';
    
      if (!rootPath) {
        rootPath = filePath;
      }
      var stat = fs.statSync(filePath);
      if (stat && stat.isDirectory()) {
        var files = fs.readdirSync(filePath);
        if (files) {
          for (var _i in files) {
            (function (i) {
              var file = files[i];
              if (filePath.match(/.*\/$/)) {
                eachFiles(filePath + file, rootPath, callback);
              } else {
                eachFiles(filePath + "/" + file, rootPath, callback);
              }
            }(_i));
          }
        }
      } else if (stat.isFile()) {
        if (callback) {
          callback.call(this, filePath, rootPath);
        }
      } else {
        throw new Error(filePath + " is not a file or directory");
      }
    }
    
    • このJavaScriptコードを使用しなくても、pug-cli/index.jsをダウンロードして使うこともできます。その場合は、コンパイル系メソッド(compileメソッドなど)実行部分で、使用したいnpmモジュールを引数に追加するように書き換えます。(ご自分の環境にインストールした pugモジュールのバージョンに合わせた index.js ファイルをダウンロードして下さい)

JavaScriptファイルのポイント

  • pugモジュールを取り込みます。
    pug = require('pug'),
    
  • Pugテンプレートファイル内から使用したいモジュールを、optionsにセットします。
    _.assignIn(options, { _: _ } );
    
  • pugオブジェクトの compileFileメソッドを実行して、Pugテンプレートファイル(filePath)をHTMLに変換するための関数を取得します。
    var fn = pug.compileFile(filePath, options);
    
  • 出力先ファイル(dstFilePath)に、HTMLを書き込みます。
    fs.writeFileSync(dstFilePath, fn(options));
    

Pugテンプレートの作成

  • 上記の JavaScriptコードにより、Pugテンプレートファイル内では、_ が使えるようになります(中身はlodashです)。

処理を実行する(PugテンプレートファイルをHTMLに変換したファイルを生成する)

以下のコマンドで実行します。

$ node runPug.js

まとめ

  • JavaScriptだけで複雑なHTMLを生成したい場合、Pug(旧Jade)は大変便利です。
  • Pugを使って複雑なHTMLを作るには Pugテンプレートファイル内でJavaScriptを使うことになると思いますが、今回の方法で npmでインストールしたモジュールが使えるようになるので、更に可能性が広がります。

参考サイト

📂-プログラミング
-

執筆者:labo


comment

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

関連記事

React Redux

React + Redux の最小限の雛形コード

ここに載せている JavaScriptのコードは、React + Redux を使っています。 但し、まだ何も意味のある処理を書いていないので、このままだと 属性 id=”root” を持った要素内に …

WSL のターミナルから vagrant.exe up がエラーになる場合の対処法

目次1. 問題となった現象2. 対処法3. 補足 1. 問題となった現象 WSL (Windows Subsystem for Linux) のターミナルから、Windows用にインストールした va …

React Redux

React と Redux を使ったウェブページのサンプルその1

React と Redux を使ってウェブページのサンプルを作ってみました。以下のURLからアクセスすることがでます。 デモページ 🔗 React + Redux のサンプル002 こ …

Web Programming

アクセス元のグローバルIPアドレスが表示されるだけのWebページを作る (Content-Type を変えた2種類)(PHP利用)

目次1. はじめに2. 手順(HTMLバージョン)(1) ウェブサーバー上にディレクトリを用意します(2) index.php ファイルを作成します(3) この Webページにアクセスします3. 手順 …

JavaScript でスロットマシーンを作ってみました(3回目)

「JavaScript でスロットマシーンを作ってみる」の3回目です。 今回は ゲームっぽくしてみました。 目次1. スクリーンショット2. デモページ3. 内容4. ソースコード5. 参考情報 1. …