🐤

テンプレートエンジンに React を使いつつ、きれいな HTML を生成したいんじゃ!!

3 min read

イントロダクション

きれいな HTML で納品してほしいという案件、まだまだあるかと思います。

HTML を生成するツールとして選択肢に出てくるのは、 EJS / Pug / Nunjucks といった JavaScript のテンプレートエンジンだと思いますが、個人的には React を知ってしまってから JSX 以外でマークアップをすることがとても億劫になってしまっています。

HTML はロジックが紛れ込むことを考慮されてない言語だと思うので、 HTML をベースにしたテンプレートは使いづらいです(個人の感想です)。逆に JSX は JavaScript の中に HTML があるので、 HTML の分割のしやすさも相まってロジックの中に紛れ込ませやすく、ほしい要素の塊をコンポーネントとして切り出して使う、コンポーネント指向にとても向いています。

テンプレートエンジンに React を使いたいんじゃ!!

Next.js や Gatsby.js 等の静的サイトジェネレーターを使えば、レンダリングされた HTML を出力することはできるのですが、人が触れるようなきれいな HTML にはなりません。

なので、きれいな HTML を生成できる開発環境を作ってみました。

チュートリアル

renderToStaticMarkup() で React を HTML 文字列に変換

ReactDomServer の renderToStaticMarkup() を使うと、 React 要素を初期状態の HTML 文字列へ変換することができます。

https://ja.reactjs.org/docs/react-dom-server.html#rendertostaticmarkup

以下のように、 body 要素の中で <App /> を HTML 文字列に変換すれば、いい感じの HTML が文字列となって export default されます。

import React from "react";
import { renderToStaticMarkup } from "react-dom/server";

const App = () => <div>Use React !!</div>;

export default () => `
  <!DOCTYPE html>
  <html lang="ja">
  <head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>タイトル</title>
  </head>
  <body>
    ${renderToStaticMarkup(<App />)}
  </body>
  </html>
`;

次に、こいつを HtmlWebpackPlugin で HTML ファイルに変換します。

HtmlWebpackPlugin で HTML ファイルに変換

適当な ディレクトリを作り、 webpack と HtmlWebpackPlugin 、そして React をビルドするためのパッケージ一式を npm install しましょう。

$ mkdir react-to-html
$ cd react-to-html
$ npm init -y
$ npm i -D webpack webpack-cli html-webpack-plugin react react-dom babel-loader @babel/preset-react @babel/core

webpack.config.js を作成し、 HtmlWebpackPlugin と bable-loader の設定をします。

const HtmlWebpackPlugin = require("html-webpack-plugin");

module.exports = {
  plugins: [
    new HtmlWebpackPlugin({
      title: "My App",
      template: "src/index.jsx",
    }),
  ],
  module: {
    rules: [
      {
        test: /\.js(|x)$/,
        use: [
          {
            loader: "babel-loader",
            options: {
              presets: ["@babel/react"],
            },
          },
        ],
      },
    ],
  },
};

さきほどの HTML 文字列を作る JavaScript は、 src/index.jsx で保存します。

HtmlWebpackPlugin の templatesrc/index.jsx を指定すれば、 HTML ファイルとして出力してくれます。

また、 title: "My App" でタイトルを指定している部分は引数で受け取ることができます。

import React from "react";
import { renderToStaticMarkup } from "react-dom/server";

const App = () => <div>Use React !!</div>;

export default ({ htmlWebpackPlugin }) => `
  <!DOCTYPE html>
  <html lang="ja">
  <head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>${htmlWebpackPlugin.options.title}</title>
  </head>
  <body>
    ${renderToStaticMarkup(<App />)}
  </body>
  </html>
`;

エントリーポイントとして src/index.js を空で作っておきます。あとは、以下のコマンドで src/index.jsx が HTML 化した dist/index.html として出力されます。

$ npx webpack

Prettier で HTML をきれいにする

prettier で HTML をきれいにしてあげましょう。

$ npm i -D prettier

npm scripts に prettier で dist/index.html が整形されるように設定します。

{
  "scripts": {
    "build": "webpack && prettier --write dist/index.html"
  }
}
$ npm run build

きれいな HTML になりましたね!

あとは、よしなに @babel/preset-env なり css-loader なりを入れて、いい感じに開発してください!

参考: https://dev.to/jantimon/html-webpack-plugin-4-has-been-released-125d

Discussion

ログインするとコメントできます