tonkotu_sister
@tonkotu_sister (tonkotu san)

Are you sure you want to delete the question?

Leaving a resolved question undeleted may help others!

WebpackのPugで別ファイルの関数を呼び出したい

Q&A

Closed

前提・実現したいこと

【webpack5環境】
別ファイルで定義しているPugファイル内の「関数」を呼び出したいです。

発生している問題・エラーメッセージ

関数が呼び出せません。
index.pugというファイルで別ファイル(_function.pug)で定義している関数(is_page)を呼び出すと以下のようなエラーが表示されます。

Html Webpack Plugin:
  ReferenceError: is_page is not defined

  - index.pug:22 template
    webpack_sample_v1_pug3/src/pug/index.pug:22:1

  - index.js:450 
    [webpack_sample_v1_pug3]/[html-webpack-plugin]/index.js:450:16

  - task_queues.js:97 processTicksAndRejections
    internal/process/task_queues.js:97:5

  - async Promise.all

ディレクトリ構造

webpack_sample_v1_pug3
├ package.json
├ package-lock.json
├ webpack.config.js
├ node_modules
└ src
  └ js
  └ pug
    └ _function.pug
    └ index.pug
└ dist
  └ js

該当のソースコード

Pugファイル

_function.pug(関数を宣言)
-
    /**
     * ページ判別
     */

    function has_class( name ) {
        /**
         * Return true if the class is assigned to <body>.
         * ex: if has_class( 'classname' )
         */
        return page.bodyclass.indexOf( name ) != -1;
    }

    function is_page( name ) {
        /**
         * Return true if the class is assigned to <body>.
         * ex: if is_page( 'classname' )
         */
        return has_class( name );
    }
index.pug(関数を呼び出す)

is_page('hoge')でpage.bodyclassがhogeだったらという簡単なif文です。

include /_function

- page = {};
block vars
    - page.title       = 'テスト';
    - page.description = site.description;
    - page.keywords    = site.keywords;
    - page.bodyclass   = 'hoge';

doctype html
html(lang="jp")
    head
        meta(charset="UTF-8")
        meta(http-equiv="X-UA-Compatible", content="IE=edge")
        meta(name="viewport", content="width=device-width, initial-scale=1.0")
        link(href='./css/style.min.css',rel='stylesheet',type='text/css')
        title テスト
    body
        .wrap
            if is_page('hoge') //ここでエラーが起きています。
                p hogeページ
            else
                p hogeページではないです

            script(src="./js/bundle.js")

webpack.config.js

// webpack.config.js

const path = require("path");
const MODE = "development";

const enabledSourceMap = MODE === "development";

const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const CopyPlugin = require("copy-webpack-plugin");

const globule = require("globule");
const webpack = require('webpack');

const app = {
  mode: MODE,
  entry: ['./src/js/index.js'],
  output: {
    path: path.resolve(__dirname, "dist"),
    filename: "./js/bundle.js",
  },
  devtool: "source-map",
  module: {
    rules: [
      {
        test: /\.js$/,
        use: [
          {
            loader: "babel-loader",
            options: {
              presets: [
                "@babel/preset-env",
              ],
            },
          },
        ],
      },
      {
        test: /\.scss/, // 対象となるファイルの拡張子
        use: [
          {
            loader: MiniCssExtractPlugin.loader,
          },
          {
            loader: "css-loader",
            options: {
              url: false,
              sourceMap: enabledSourceMap,

              importLoaders: 2,
            },
          },
          {
            loader: "postcss-loader",
            options: {
              postcssOptions: {
                plugins: [
                  ["autoprefixer", { grid: true }],
                ],
              },
            },
          },
          {
            loader: "sass-loader",
            options: {
              sourceMap: enabledSourceMap,
            },
          },
        ],
      },
      {
        test: /\.pug$/,
        use: [
          {
            loader: "pug-loader",
            options: {
              pretty: true,
              globals: ["page"],
              self: true,
              root: path.resolve(__dirname, 'src/pug')
            }
          }
        ]
      }
    ],
  },
  devServer: {
    static: {
      watch: true,
      directory: `${__dirname}/src`,
    },
    open: true
  },
  plugins: [
    new MiniCssExtractPlugin({
      filename: "./css/style.min.css",
    }),
    new CopyPlugin({
      patterns: [{
        from: `${path.resolve(__dirname, "src")}/img/`,
        to: `${path.resolve(__dirname, "dist")}/img/`
      }],
    }),
    new webpack.ProvidePlugin({
      $: 'jquery'
    })
  ],
  target: ["web",'es5'],
  devtool: "source-map",
  watchOptions: {
    ignored: /node_modules/ //正規表現で指定
  }
};

//srcフォルダからpngを探す
const templates = globule.find("./src/pug/**/*.pug", {
  ignore: [
    "./src/pug/**/_*.pug",
  ]
});

//pugファイルがある分だけhtmlに変換する
templates.forEach((template) => {
  const fileName = template.replace("./src/pug/", "").replace(".pug", ".html");
  app.plugins.push(
    new HtmlWebpackPlugin({
      filename: `${fileName}`,
      template: template,
      inject: false, //false, head, body, trueから選べる
      minify: false //本番環境でも圧縮しない
    })
  );
});

module.exports = app;

package.json

{
  "scripts": {
    "build": "webpack --mode production",
    "dev": "webpack --mode development",
    "watch": "webpack --mode development --watch",
    "start": "webpack serve --mode development"
  },
  "devDependencies": {
    "@babel/core": "^7.15.5",
    "@babel/preset-env": "^7.15.6",
    "autoprefixer": "^10.3.7",
    "babel-loader": "^8.2.2",
    "copy-webpack-plugin": "^9.0.1",
    "css-loader": "^6.2.0",
    "globule": "^1.3.3",
    "html-loader": "^2.1.2",
    "html-webpack-plugin": "^5.3.2",
    "html-webpack-pug-plugin": "^3.0.0",
    "mini-css-extract-plugin": "^2.3.0",
    "path": "^0.12.7",
    "postcss": "^8.3.9",
    "postcss-loader": "^6.1.1",
    "pug": "^2.0.4",
    "pug-html-loader": "^1.1.5",
    "pug-loader": "^2.4.0",
    "sass": "^1.39.2",
    "sass-loader": "^12.1.0",
    "style-loader": "^3.2.1",
    "webpack": "^5.52.1",
    "webpack-cli": "^4.8.0",
    "webpack-dev-server": "^4.2.0"
  },
  "dependencies": {
    "jquery": "^3.6.0"
  },
  "browserslist": [
    "> 3% in JP",
    "ie 11",
    "android 4.4",
    "last 1 versions"
  ]
}

試したこと

index.pug内で_function.pug内の関数をまるっとコピペしてみると期待通りの関数が呼び出せます。

-
    /**
     * ページ判別
     */

    function has_class( name ) {
        /**
         * Return true if the class is assigned to <body>.
         * ex: if has_class( 'classname' )
         */
        return page.bodyclass.indexOf( name ) != -1;
    }

    function is_page( name ) {
        /**
         * Return true if the class is assigned to <body>.
         * ex: if is_page( 'classname' )
         */
        return has_class( name );
    }
- page = {};
block vars
    - page.title       = 'テスト';
    - page.description = site.description;
    - page.keywords    = site.keywords;
    - page.bodyclass   = 'hoge';

doctype html
html(lang="jp")
    head
        meta(charset="UTF-8")
        meta(http-equiv="X-UA-Compatible", content="IE=edge")
        meta(name="viewport", content="width=device-width, initial-scale=1.0")
        link(href='./css/style.min.css',rel='stylesheet',type='text/css')
        title テスト
    body
        .wrap
            if is_page('hoge') //ok
                p hogeページ
            else
                p hogeページではないです

            script(src="./js/bundle.js")

推測

別ファイルなのでスコープが閉じられている可能性が高いです。
別ファイルの変数はwebpack.config.jsのpug-loader→globalsで変数を定義しているので、サイト全体で使えます。

どうかご教授の方よろしくお願い致します...!!

0

1Answer

設定を globals: ["site", "has_class", "is_page"] として、関数定義を

-
  has_class = function(name) { ... }
  is_page = function(name) { ... }

とすればいいです。

関数の数が多いようなら、適当なオブジェクトをグローバル変数にしてプロパティに関数を追加していくと設定がすっきりします。

// `globals: ["site", "util"]`
-
  util = {}
  util.has_class = function(name) { ... }
  util.is_page = function(name) { ... }
include /_function.pug
= util.is_page("xxx")
1Like

Comments

  1. @tonkotu_sister

    Questioner

    @uasi さん
    前回に引き続きご回答ありがとうございます!
    おかげさまで解決できました!!

    変数に関数を入れるという思考に至っておりませんでした。
    重ね重ねありがとうございました。

Your answer might help someone💌