スポンサーリンク

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

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"
  ]
}

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'
        }),
    ]
};

/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' ); %>

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

参考文献

脱webpack : ejs編 - Qiita
はじめに 現在フロントエンド開発環境のうち、一部のwebpack依存処理をnode.jsスクリプトに置き換えています。 本記事はその結果のうち、ejsをnode.jsスクリプトで変換する方法を共有するためのものです。 ejs...
EJSでテンプレートとデータでファイルを切り分けた開発を行う | オウンドメディア | 大阪市天王寺区ホームページ制作 | 合同会社デザインサプライ-DesignSupply. LLC-
前回記事「EJSでコンポーネントのインクルードや値の受け渡しなどを試してみる」で、コンポーネント間でデータを受け渡す方法についてまとめていました。ただ、取り扱うデータの量が多かったり、たくさんのページに影響する場合には、…
Node.jsユーザーなら押さえておきたいnpm-scriptsのタスク実行方法まとめ
ウェブ制作の現場では作業の自動化が流行っています。「Gulp」「Grunt」などのタスクランナーや「webpack」などのビルドシステムなどのツールにより人力の作業を減らすことができ、生産効率や品質の向上につながります。 どちらもNode.jsのモジュールとして動作するツールですが、実はこれらのタスクランナーを使わずと...
JSONオブジェクトをejs renderFileに渡すことは可能ですか? - node.js、ejs
Idはむしろ私のejsファイルの各フィールド名を入力する必要はありません。これはidが何をしたいのかです。