最近個人のRailsアプリケーションをWebpackerからSimpackerを使ったピュアなWebpack環境に切り替えたので、その手順をメモしておきます📝
今回はWebpackerを導入しときのデフォルトなjs/scss
なbuild環境を削除して、Webpackで置き換えていきます。
Webpackerを辞める
まずは既存のRailsアプリケーションからWebpackerを外していきます。
新規でRailsアプリケーション作る場合は当該手順は不要で単にrails new –skip-javascript
を実行して、js環境をrails new
時に作るのをやめてあげると良いかと思います。
※Webpackで管理するならsprokets
もturbolinks
もいらない気がするので、上記に加えて--skip-sprockets
、--skip-turbolinks
もつけておくと良さそうです。
Webpackerをuninstallする
Gemfile
からwebpacker
、package.json
から@rails/webpacker
を削除します。
※webpack --watch
で十分な場合はwebpack-dev-server
もpackage.json
から削除します。
その後bundle install
とyarn install
を実行してlock
ファイルからも消します。
Webpacker関連ファイルを削除する
unistallが完了したあと、Webpackerが作成した各種ファイルを削除します。
- .browserslistrc
- babel.config.js
- bin/webpack
- postcss.config.js
- config/webpack配下の各種ファイル
※webpack-dev-server
をuninstallした場合はbin/webpack-dev-server
も削除します。
これでWebpackerを辞めることが出来ました。
ピュアなWebpack環境を作る
Webpackの導入
Webpackの導入については、過去に基本的な使い方をまとめた記事を書いているので、そちらを参考にしてください。
一応私が作ったjs/scss
のbuild環境のwebpack.config.js
をサンプルとして記載しておきます。
ポイントは、Rails側で読み込むべきbuild後のjs及びcssを判定するためにWebpackAssetsManifest
で結果をjsonファイルで出力する必要があるところです👷♀️
const glob = require("glob"); const path = require("path"); function entryName(RootPath, filePath) { const dirName = filePath .replace(RootPath, "") .replace(path.basename(filePath), ""); return `${dirName}${path.basename(filePath, path.extname(filePath))}`; } /** * 指定したentryのルートディレクトリ配下のjsまたはtsファイルのファイル名とパスのobjectを取得 * 例) * - /entries/foo.ts => { foo: "/entries/foo.ts" } * - /entries/bars/bar.ts => { "bars/bar": "/entries/bars/bar.ts" } * @param {string} entryRoot entryのルートディレクトリ */ const getEntries = function getEntries(entryRoot) { const ret = {}; const filePaths = glob.sync(`${entryRoot}/**/*.{js,ts}`); filePaths.forEach((filePath) => { ret[entryName(entryRoot, filePath)] = filePath; }); return ret; }; const MiniCssExtractPlugin = require("mini-css-extract-plugin"); const { CleanWebpackPlugin } = require("clean-webpack-plugin"); const WebpackAssetsManifest = require("webpack-assets-manifest"); const JAVASCRIPT_ENTRY_PATH = "./app/javascript/packs/"; const entries = getEntries(JAVASCRIPT_ENTRY_PATH); const { NODE_ENV } = process.env; const isProd = NODE_ENV === "production"; module.exports = { mode: isProd ? "production" : "development", entry: entries, output: { path: `${__dirname}/public/packs`, publicPath: "/packs/", filename: "[name]-[hash].js", }, module: { rules: [ { test: /\.scss|\.css/, use: [MiniCssExtractPlugin.loader, "css-loader", "sass-loader"], }, { test: /\.m?js$/, exclude: /(node_modules|bower_components)/, use: { loader: "babel-loader", options: { presets: ["@babel/preset-env"], plugins: ["@babel/plugin-transform-runtime"], }, }, }, ], }, resolve: { alias: { "@js": `${__dirname}/app/javascript`, "@css": `${__dirname}/app/javascript/stylesheets`, }, }, plugins: [ new MiniCssExtractPlugin({ filename: "[name]-[hash].css" }), new CleanWebpackPlugin(), new WebpackAssetsManifest({ publicPath: true }) ], };
またbuild用のscriptもpackage.json
内に以下のような感じで定義しました。
"scripts": { "webpack": "webpack", "webpack-prod": "webpack --mode=production", "webpack-watch": "webpack --watch", },
ビルドしたjsを読み込むhelperを作る
Webpackerを使うとapplication_pack_tag
のようなhelperが自動で使えるようになりますが、ピュアなWebpack環境では自身でWebpackのbuild時に作成されたmanifestを読み込んでファイルパスを返すようなhelperを独自で作る必要があります。
※またアクセス時のbuildチェックもして、自動でbuildを走らせるような処理も行われません。
そのため今回はSimpacker
というgemを使ってapplication_pack_tag
を再現します。
Simpacker
の導入は、
Gemfileに下記を追加してbundle install
します。
gem 'simpacker'
まだwebpack環境を作っていない人はrails simpacker:install
を実行するとSimpacker
がシンプルな環境を作ってくれます。
作成される環境はこちらを参照
simpacker/lib/install at master · hokaccha/simpacker · GitHub
※yarn
ではなくnpm
で環境が作成されるので注意してください。
すでにWebpack環境を作成済みの人は、下記のsimpacker.yml
をconfig
配下に配置して自身の設定に合わせて編集すれば問題ないと思います🙆♂️
simpacker/simpacker.yml at master · hokaccha/simpacker · GitHub
これでapplication_pack_tag
が定義されて、Webpackでbuildしたjs/cssがrails側で読み込めるようになりました🙌
おわりに
今回はWebpackerからSimpackerを使ってピュアなWebpack環境に置き換える手順をメモしました📝
素のWebpackerのまま使う時は非常に導入も楽なのですが、ちょっとカスタマイズが必要になってくるとカオスになってくるので、自分もまだフロントエンドまわりは分からないことが多いですが、複雑になったらWebpackerからWebpackに乗り換えるといったことや、最初からWebpackを選択するようなことが出来るようになっておきたいですね💦(実際のサービスを置き換えるときには、こんなにすんなりとはいかないと思いますが。。。)