たるだめ

のんびりとなんか書きます

Node.js + Webpack + Handlebarsの環境でヘルパー使えなくてハマった

HandlebarsとWebpackを同時に使いたいときの注意

問題

AWS Lambda(Node.js)上で実行する関数内で handlebars を使いたい場面がありました。

Webpack も使っていたので、handlebars 用のローダーを使用したところ、登録したはずのヘルパーがMissing helperで呼び出せない問題が発生しました。

解決策

registerHelper での登録をやめ、handlebars-loader の option「helperDir」にパスを指定することで解決できました。

指定ディレクトリ配下に登録するヘルパーと同じ名前のファイルを作成し、関数は default export します。

名前付き export にしたり、ファイル名をヘルパー名と別の物に変えたりするとダメでした。

他の解決策としては、runtime に registerHelper でヘルパーを登録済みの Handlebars インスタンスを指定することで使えるようにできます。

module.exports = {
  // 省略
  module: {
    rules: [{
      test: /\.hbs$/,
      loader: 'handlebars-loader',
      options: {
        runtime: path.resolve(**dirname, 'src', 'handlebars'),
        helperDirs: path.resolve(\_\_dirname, 'src', 'helpers'),
        precompileOptions: {
          knownHelpersOnly: false,
        },
      },
    },],
  },
};

検証用リポジトリ

最小構成で別途検証しました。

下記リポジトリでは Lambda は使いませんが、同じ事象を起こせます。

環境

  • webpack 5.74.0
  • Nodejs 16.14.0
  • handlebars 4.7.7

何故・・?

registerHelper で登録したヘルパーは Webpack でコンパイルした JS では呼び出せないということがわかりました。

hbs.registerHelper("suffix", suffix)

テスト用に “suffix” という名前のヘルパーを登録してみましたが、呼び出し時に Missing helper というエラーが発生してしまいます。

Error: Missing helper: "suffix"
at Object.eval (webpack://hbs-webpack-test/./node_modules/handlebars/dist/cjs/handlebars/helpers/helper-missing.js?:19:13)
at Object.wrapper (webpack://hbs-webpack-test/./node_modules/handlebars/dist/cjs/handlebars/internal/wrapHelper.js?:15:19)
at Object.main (webpack://hbs-webpack-test/./view/template.hbs?:12:145)
at main (webpack://hbs-webpack-test/./node_modules/handlebars/dist/cjs/handlebars/runtime.js?:208:32)
at ret (webpack://hbs-webpack-test/./node_modules/handlebars/dist/cjs/handlebars/runtime.js?:212:12)
at getTemplate (webpack://hbs-webpack-test/./hbs.js?:12:13)
at Server.eval (webpack://hbs-webpack-test/./app.js?:10:15)
at Server.emit (node:events:520:28)
at parserOnIncoming (node:\_http_server:951:12)
at HTTPParser.parserOnHeadersComplete (node:\_http_common:128:17) {
description: undefined,
fileName: undefined,
lineNumber: undefined,
endLineNumber: undefined,
number: undefined
}

しかし、hbs の helpers には登録されています。

image

上記は実行時にヘルパーを登録してるのですが、Webpack ビルドしたときは、テンプレートがコンパイル済みなので使えないということらしいです。

このあたりのイシューでも言及されています。

実行時に登録してもダメだから loader のオプションにヘルパーを登録しておく仕掛けを入れておくと。

しかし 1 次情報からそのあたりの説明が見つけられなかったのでモヤっと・・・🎃

まとめ

webpack+handlebars では、通常のヘルパー登録は NG。loader のオプションを使って設定する必要があります。

今回は使っていませんが、パーシャルも同じようなことになると思います。

webpack というものをもっと理解できれば今回の問題も上手く咀嚼できてくるのだろうなと思いました。