はじめに
simpackerとは
webpackerを使わず、シンプルなwebpackでRailsを開発するgem。
クックパッド技術部の方が作られたgemです。
https://github.com/hokaccha/simpacker
Simpacker: Rails と webpack をもっとシンプルにインテグレーションしたいのです
Githubと、このクックパッドの開発者ブログを見れば、simpackerが何なのかほとんどわかると思います。
なぜsimpacker?
Rails6以降、webpackerが標準搭載になっていますが、webpackerは独自のDSLになっており、webpack本来の設定などが見えなくなっています。簡単にwebpackを扱えますが、設定のカスタマイズには独自DSLを学ぶコストがついてきます。またwebpackの細かい設定などは調整しにくかったりできないこともあるので、純粋なwebpackを使いたいならsimpackerの導入をおすすめします。
またwebpackerの独自DSLを学ぶなら、webpackそのものを学んだ方が今後の開発に活かせる気がします。私は初めて現場で触れたのがsimpackerの方で、webpackerのことはよくわかってなかったりします。笑
Rails + React + TypeScriptで環境構築
バックエンドはRails、フロントエンドはReact + TypeScriptで構成された開発手順をメモしたいと思います。
開発環境
ruby 3.0.0
rails 6.1.1
yarn 1.22.10
tsc 4.1.3
手順
グローバルを汚さないRails環境構築やMySQLのコンテナ化は別記事に解説してますので、よければ参考にしてください。
Dockerでコンテナ化したMySQLを使用してRails環境構築
Railsの環境構築(グローバル環境を汚さずに)
railsプロジェクト立ち上げ
bundle exec rails new my_app --skip-javascript
bundle exec rails db:create
webpackerを入れたくないので、--skip-javascript
を付けます。
simpackerをGemfileに追加
gem 'simpacker'
gemインストール
bundle install
simpacker初期化コマンド実行
bundle exec rails simpacker:install
React, TypeScript、必要なパッケージをインストール
yarn add -D react react-dom
yarn add -D typescript ts-loader
yarnを使っていますが、npmでも問題ありません。
ts-loaderはtypescriptをjavascriptにトランスパイルするためのパッケージです。
webpack.config.jsを作成
ここにwebpackの設定を書いていきます。
純粋なwebpackと全く同じ書き方です。
const path = require("path");
const WebpackAssetsManifest = require("webpack-assets-manifest");
const { NODE_ENV } = process.env;
const isProd = NODE_ENV === "production";
module.exports = {
mode: isProd ? "production" : "development",
devtool: "source-map",
entry: {
application: path.resolve(__dirname, "app/frontend/js/packs/application.tsx"),
},
output: {
path: path.resolve(__dirname, "public/packs"),
publicPath: "/packs/",
filename: isProd ? "[name]-[hash].js" : "[name].js",
},
resolve: {
extensions: [".js", ".ts", ".jsx", "tsx"],
},
module: {
rules: [
{
test: /\.(js|ts|jsx|tsx)$/,
exclude: /node_modules/,
use: [
{loader: "ts-loader"}
]
}
]
},
plugins: [
new WebpackAssetsManifest({
publicPath: true,
output: "manifest.json",
}),
],
};
const path = require("path");
node.jsのpathモジュールを読んでます。
const WebpackAssetsManifest = require("webpack-assets-manifest"); manifest.json
を生成してくれるパッケージです。
const { NODE_ENV } = process.env;
こちらで任意の環境変数を読み込んでいます。
mode:
modeによって出力ファイルの形式が変わります。productionだと圧縮され、develomentだとみやすく整形されて出力されます。
devtool:
ソースマップを指定できます。ソースマップを有効にすると、ブラウザコンソールでエラーを確認するときに、エラー箇所を特定できるため必須だと思います。
entry:
webpackに読み込ませるエントリポイントを指定します。
path.resolve(__dirname, "")
と言う表記は環境に依存しない絶対pathを取得できるっぽいです。
output:
ファイルに出力先を指定します。
publicPath
は本番環境での解決pathを指定しています。
railsではデフォルトでpublic配下がドキュメントルートなので、/packs/
を指定しています。
extensions:
importするファイルの拡張子を省略できます。同じファイル名の異なる拡張子ファイルが存在した場合、配列の先頭のものが読み込まれます。
import File from '../path/to/file';
rules:
トランスパイルするローダーの設定を書きます。
test:
で対象ファイルを指定します。
use
で使用するローダーをしてします。複数書いた場合は後ろから実行されます。
WebpackAssetsManifest
:
manifest.jsonを作成するwebpack用ライブラリです。
webpackの設定はやはり公式を参照すべきだと思います。
https://webpack.js.org/concepts/
こちらも充実しています。
webpack 4 入門 - Qiita
tsconfig.jsonを作成
typescriptの設定を書いていきます。
{
"compilerOptions": {
"target": "es5",
"module": "es2015",
"jsx": "react",
"allowJs": true,
"moduleResolution": "node",
"sourceMap": true,
"strict": true,
"noImplicitAny": false,
},
"include": [
"app/frontend/js/**/*"
],
"exclude": [
"**/*.(spec|test).ts",
"**/setup.jest.ts",
]
}
target:
出力するjsのバージョンを指定します。
module:
使用するモジュールを指定します。
targetやmoduleについてまだ詳しく理解していないので、今後勉強していきたいと思ってます。
jsx:
reactを使用する場合、reactを指定します。
allowJs:
trueでjsファイルもトランスパイルしてくれます。
moduleResolution:
とりあえずnodeにしておけばいい?
strict:
全ての型チェックを有効にします。
tsconfig.jsonについては、
公式にコンパクトにまとまっています。
https://typescript-jp.gitbook.io/deep-dive/project/compilation-context/tsconfig
日本語だと、こちらの記事でかなり詳細に解説してくださっています。
tsconfig.jsonの全オプションを理解する(随時追加中) - Qiita
Reactコンポーネントを作成
エントリーポイントのファイルを作成していきます。
import * as React from 'react';
import * as ReactDOM from 'react-dom';
import Index from '../pages/Index';
const appElement = document.getElementById('app');
if (appElement) {
ReactDOM.render((
<Index />
), appElement);
}
レンダーするコンポーネント
import * as React from 'react';
interface Props {}
const Index: React.FC<Props> = () => {
return(
<div>Hello React</div>
)
};
export default Index;
これをwebpackでビルドしてjsファイルを出力します
yarn webpack
/public/packs/
配下にapplication.js
, application.js.map
, manifest.json
が作成されていると思います。
これらをRails側で読み込みましょう。
bundle exec rails g controller Top
class TopController < ApplicationController
def index; end
end
<div id="app"></div>
<!DOCTYPE html>
<html>
<head>
<title>Sample</title>
<meta name="viewport" content="width=device-width,initial-scale=1">
<%= csrf_meta_tags %>
<%= csp_meta_tag %>
</head>
<body>
<%= yield %>
<%= javascript_pack_tag 'application' %>
</body>
</html>
simpackerが良い感じに<%= javascript_pack_tag 'application' %>
を解釈して読み込んでくれます。
http://localhost:3000/index
にアクセスしてHello Reactが表示されれば成功です。
終わりに
simpackerはシンプルにwebpackを扱えるようにしてくれます。
ただ、今のRailsのフロント周りのgemはwebpackerを前提に作られているものが多いので、そういうgemを利用する際には、かなり苦労することもありますので、少なからずデメリットも存在します。