Node.jsとEJSとwebpackでテンプレート管理出来るweb制作環境を作る

過去に似たようなことを試しましたが、webpackのバージョンも上がり新たに環境を作ってみました。

前回はEJSのwebpack用プラグインを使いましたが、アップデートが放置されており不安だったのと、プラグインを使わない方法を実践している参考文献を見つけたので、それを参考に構築しています。

環境設定

package.json

{
  "name": "js_template",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "all": "npm run ejs & npm run build",
    "ejs": "node task/ejs.js",
    "watch:ejs": "onchange \"./src/**/*.ejs\" -- npm run ejs",
    "build": "webpack --mode=production",
    "build:dev": "webpack --mode=development",
    "watch:dev": "webpack --mode=development --watch"
  },
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "autoprefixer": "^10.2.5",
    "css-loader": "^5.2.0",
    "ejs": "^3.1.6",
    "glob": "^7.1.6",
    "make-dir": "^3.1.0",
    "mini-css-extract-plugin": "^1.4.0",
    "onchange": "^7.1.0",
    "postcss-loader": "^5.2.0",
    "sass": "^1.32.8",
    "sass-loader": "^11.0.1",
    "webpack": "^5.28.0",
    "webpack-cli": "^4.6.0"
  },
  "browserslist": [
    "last 2 version",
    "ie >= 11"
  ]
}

追記:

npmのonchangeをWindowsで利用する場合は、対象ファイルをダブルクォーテーションで囲む必要があるらしいです。

また、後日に”webpack-dev-server”(開発用サーバー)も追加でインストールし、”scripts”に下記も追加しています。

"devserver": "webpack-dev-server --mode development"

webpack.config.js

jsとcssは分けて出力するようにします。

const path = require('path');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const webpack = require('webpack');

module.exports = {
    entry: './src/index.js',
    output: {
        path: path.resolve(__dirname, 'dist'),
        filename: './js/bundle.js'
    },
    module: {
        rules: [
            {
                test: /\.(sa|sc|c)ss$/,
                use: [
                    {
                        loader: MiniCssExtractPlugin.loader
                    },
                    {
                        loader: 'css-loader',
                        options: {
                            url: false
                        }
                    },
                    {
                        loader: "postcss-loader",
                        options: {
                          postcssOptions: {
                            plugins: [
                                require('autoprefixer')()
                            ],
                          },
                        },
                    },
                    {
                        loader: 'sass-loader'
                    },
                ]
            },
        ],
    },
    // ES5(IE11等)向けの指定(webpack 5以上で必要)
    target: ["web", "es5"],
    plugins: [   
        new MiniCssExtractPlugin({
            filename: './css/style.css'
        }),
    ]
};

追記:

“webpack-dev-server”(開発用サーバー)のインストールに伴い、下記も追記しました。(編集時のブラウザ自動リロード設定)

module.exports = {
  devServer: {
    watchFiles: ["src/**/*.ejs", "src/scss/*.scss", "src/ejs/page-data.json"],
  },
}

/task/ejs.js

外部の設定情報ファイルとしてpage-data.jsonを読み込んでいます。

"use strict";

const fs = require("fs");
const path = require("path");
const ejs = require("ejs");
const glob = require("glob");
const makeDir = require("make-dir");

const srcDir = `${process.cwd()}/src/ejs`;
const distDir = `${process.cwd()}/dist`;
const jsonDataPath = `${process.cwd()}/src/ejs/page-data.json`;

const json = JSON.parse(fs.readFileSync(jsonDataPath, 'utf-8'));

glob(
    `**/*.ejs`,
    {
        cwd: srcDir,
        ignore: `**/_*.ejs`,
    },
    (er, files) => {
        for (let fileName of files) {
            convert(fileName, srcDir, distDir);
        }
    }
);

const convert = (fileName, srcDir, distDir) => {
    ejs.renderFile(path.resolve(srcDir, fileName), { pageData: json }, (err, str) => {
        if (err) {
            console.log(err);
            return;
        }

        const distPath = path.resolve(distDir, fileName);
        makeDir(path.dirname(distPath)).then(() => {
            const htmlPath = path.format({
                dir: path.dirname(distPath),
                name: path.basename(distPath, ".ejs"),
                ext: ".html",
            });
            fs.writeFile(htmlPath, str, () => {});
        });
    });
};

テンプレート作成&ビルド

/src ディレクトリ以下に各種ファイルを設置する。

/src/index.js

/* My CSS */
import "./scss/common.scss";

/* My JS */
import './js/debug';

/src/ejs/

index.ejs

<%- include( 'components/_header.ejs', { meta: pageData['home'] } ); %>
        <main>メインコンテンツ100%</main>
<%- include( 'components/_footer.ejs' ); %>

サブディレクトリ内に設置した場合など、includeするファイルまでの相対パスの指定に注意します。

page-data.json

{
    "home": {
        "title": "ほげほげウェブサイト",
        "description": "ほげほげウェブサイトへようこそ!"
    },
    "profile": {
        "title": "プロフィール | ほげほげウェブサイト",
        "description": "ほげほげェブサイトの運営者についてご紹介します。"
    }
}

components/

_header.ejs
<!doctype html>
<html lang="ja">
    <head>
        <meta charset="utf-8">
        <meta name="description" content="<%= meta.description %>">
        <title><%= meta.title %></title>
        <link rel="stylesheet" href="/css/style.css">
        <script src="/js/bundle.js"></script>
    </head>
    <body>
        <header>ヘッダーエリア</header>
_footer.ejs
        <footer>フッターエリア</footer>
    </body>
</html>

ビルド

$ nmp run all

追記:開発中は主に下記

  • npm run devserver(開発用サーバーの起動と開発ビルドwatch、scssやjs編集時に自動ビルドとブラウザリロード、ただしブラウザが読み込んでいるビルドされたファイルは更新されるものの実際のビルド出力先のファイルは更新されないようで、後で手動ビルドが必要?)
  • (別のターミナルを起動して)npm run watch:ejs(ejs編集時にコンパイルとブラウザリロード)

参考文献

脱webpack : ejs編 - Qiita
はじめに現在フロントエンド開発環境のうち、一部のwebpack依存処理をnode.jsスクリプトに置き換えています。本記事はその結果のうち、ejsをnode.jsスクリプトで変換する方法を共有す…
301 Moved Permanently
Node.jsユーザーなら押さえておきたいnpm-scriptsのタスク実行方法まとめ - ICS MEDIA
ウェブ制作の現場では作業の自動化を行うことが多いです。Node.jsインストール時に付属するnpm (Node PackageManager)を使用すれば、タスク処理が実現できます。
JSONオブジェクトをejs renderFileに渡すことは可能ですか? - node.js、ejs
Idはむしろ私のejsファイルの各フィールド名を入力する必要はありません。これはidが何をしたいのかです。
タイトルとURLをコピーしました