😼

HTMLコーディングでもReact+TypeScriptの開発体験を得る

2021/08/10に公開

前置き

HTMLを納品する形式の仕事の際にEJSやpugではなくReact+TypeScriptを使ってHTMLを生成しつつ開発体験を高めてほしい。

ということで具体的にどのようなメリットがあるのかを伝えたくてまとめてみました。

開発環境

1から環境を作るのは大変なので今回はクラクさんのministaを拡張していきます。

ministaの紹介記事はこちら

https://www.npmjs.com/package/minista

https://zenn.dev/qrac/articles/7537521afcd1bf

必要な設定はTypeScript, ESLint, Prettier, Babel, エディター(今回はVSCode)になります。

webpack.config.js
webpack.config.js
const path = require('path')
const glob = require('glob')
const HtmlWebpackPlugin = require('html-webpack-plugin')

const webpackConfig = {
  entry: './src/assets/index.ts',
  module: {
    rules: [
      {
        test: [/\.ts$/, /\.tsx$/, /\.js$/],
        exclude: /node_modules/,
        use: ['babel-loader', 'ts-loader'],
      },
    ],
  },
  resolve: {
    extensions: ['.js', '.jsx', '.ts', '.tsx'],
  },
  plugins: [],
}

glob
  .sync('**/*.tsx', {
    cwd: 'src/pages',
  })
  .forEach((file) => {
    const extname = path.extname(file)
    const basename = path.basename(file, extname)
    const dirname = path.dirname(file)

    webpackConfig.plugins.push(
      new HtmlWebpackPlugin({
        template: path.resolve('src/pages', file),
        filename: path.join(dirname, basename + '.html'),
      })
    )
  })

module.exports = webpackConfig
.babelrc
.babelrc
{
  "plugins": [
    [
      "module-resolver",  // エイリアスの設定
      {
        "root": ["./"],
        "alias": {
          "@": "./src/"
        }
      }
    ]
  ],
  "presets": [
    [
      "@babel/preset-react", {
        "runtime": "automatic"
      }
    ],
    [
      "@babel/preset-env",
      {
        "useBuiltIns": "usage",
        "corejs": 3,
        "targets": "> 0.25%, not dead"
      }
    ],
    ["@babel/preset-typescript"]
  ]
}
tsconfig.json
tsconfig.json
{
  "compilerOptions": {
    "target": "esnext",
    "baseUrl": ".",
    "paths": {
      "@/*": ["./src/*"] // エイリアスの設定
    },
    "module": "esnext",
    "allowJs": true,
    "jsx": "preserve",
    "strict": true,
    "noImplicitAny": false,
    "strictNullChecks": true,
    "noUnusedLocals": true,
    "noUnusedParameters": true,
    "noImplicitReturns": true,
    "moduleResolution": "node",
    "esModuleInterop": true,
    "isolatedModules": false,
    "skipLibCheck": true,
    "forceConsistentCasingInFileNames": true,
    "resolveJsonModule": true
  },
  "include": ["**/*.js", "**/*.ts", "**/*.tsx"],
  "exclude": ["node_modules", "dist", "webpack.config.js"]
}
.eslintrc
.eslintrc
{
  "extends": [
    "plugin:prettier/recommended",
    "plugin:react/recommended"
  ],
  "plugins": ["@typescript-eslint", "react"],
  "parser": "@typescript-eslint/parser",
  "parserOptions": {
    "sourceType": "module",
    "ecmaFeatures": {
      "jsx": true
    }
  },
  "settings": {
    "react": {
      "version": "detect"
    }
  },
  "rules": {
    "@typescript-eslint/adjacent-overload-signatures": "error",
    "react/prop-types": "off",
    "no-unused-vars": "off",
    "import/no-unresolved": "off",
    "@typescript-eslint/no-unused-vars": "error",
    "react/react-in-jsx-scope": "off"
  }
}

settings.json
settings.json
{
  "editor.codeActionsOnSave": {
    "source.fixAll.eslint": true
  },
}

必要なライブラリについては適宜インストールしてください。

結局Reactだと何がいいのか

  • ESLint, Prettierが利用できる
  • props含め補完が優秀
  • TypeScript(JavaScript)がそのまま使える

ESLint, Prettierが利用できる

TSXファイルなのでESLintとPrettierの恩恵を受けれます。

ファイルのフォーマットができることはもちろんですが、ESLintによって規約を設けられるので複数人の開発においても効率よく開発できます。

また、eslint-plugin-jsx-a11yなどのESLintプラグインも利用できるので品質のコントロールもしやすいです。

props含め補完が優秀

以前はEJSを利用していたのですが、乗り換えた理由にinclude時に引数がサジェストされない・型がわからないことや指定ミスなどでコンパイルが通らないことがありました。

今回の環境ではそんなことはなくpropsの補完・必須項目や型のチェックをしてくれるのでコンパイルを待つことなくエラーを発見できます。

またEJSやPugでの変数宣言時は都度定義元ファイルに移動することもあったと思いますが、この環境ではTSXを利用しているので関数や変数でも補完が効きます。

TypeScript(JavaScript)がそのまま使える

ESLintもPrettierも補完もTypeScriptがそのまま使えるからの恩恵ではあるのですが、他にもjsファイルと同じ定数や環境変数を利用できることや、出力の加工がしやすいなどTypeScriptがかけるからこその恩恵があります。

出力の加工についてよくあるのが、見出しの文字を一文字ずつspanで囲むことなどですね。

何よりエディターの補完が効くのが強みですし、テンプレートエンジンの独自記法に悩まされなくなるのがいいです。

また、babelで設定したエイリアスもそのまま使えるので、コンポーネントのimport時にpathの記述で疲弊することもなくなります。

まとめ

結局「TypeScript(JavaScript)がそのまま使える」これに尽きます。

HTMLとしての出力結果はEJSやPugなどと変わらないのでReactに抵抗がなければ試してみてください。

Discussion