Madogiwa Blog

主に技術系の学習メモに使っていきます。

Ruby on Rails: WebpackerからピュアなWebpack環境に置き換えるメモ📝

最近個人のRailsアプリケーションをWebpackerからSimpackerを使ったピュアなWebpack環境に切り替えたので、その手順をメモしておきます📝

今回はWebpackerを導入しときのデフォルトなjs/scssなbuild環境を削除して、Webpackで置き換えていきます。

Webpackerを辞める

まずは既存のRailsアプリケーションからWebpackerを外していきます。

新規でRailsアプリケーション作る場合は当該手順は不要で単にrails new –skip-javascriptを実行して、js環境をrails new時に作るのをやめてあげると良いかと思います。
※Webpackで管理するならsproketsturbolinksもいらない気がするので、上記に加えて--skip-sprockets--skip-turbolinksもつけておくと良さそうです。

Webpackerをuninstallする

Gemfileからwebpackerpackage.jsonから@rails/webpackerを削除します。 ※webpack --watchで十分な場合はwebpack-dev-serverpackage.jsonから削除します。

その後bundle installyarn 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の導入については、過去に基本的な使い方をまとめた記事を書いているので、そちらを参考にしてください。

madogiwa0124.hatenablog.com

一応私が作った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を再現します。

github.com

Simpackerの導入は、 Gemfileに下記を追加してbundle installします。

gem 'simpacker'

まだwebpack環境を作っていない人はrails simpacker:installを実行するとSimpackerがシンプルな環境を作ってくれます。

作成される環境はこちらを参照

simpacker/lib/install at master · hokaccha/simpacker · GitHub

yarnではなくnpmで環境が作成されるので注意してください。

すでにWebpack環境を作成済みの人は、下記のsimpacker.ymlconfig配下に配置して自身の設定に合わせて編集すれば問題ないと思います🙆‍♂️

simpacker/simpacker.yml at master · hokaccha/simpacker · GitHub

これでapplication_pack_tagが定義されて、Webpackでbuildしたjs/cssrails側で読み込めるようになりました🙌

おわりに

今回はWebpackerからSimpackerを使ってピュアなWebpack環境に置き換える手順をメモしました📝

素のWebpackerのまま使う時は非常に導入も楽なのですが、ちょっとカスタマイズが必要になってくるとカオスになってくるので、自分もまだフロントエンドまわりは分からないことが多いですが、複雑になったらWebpackerからWebpackに乗り換えるといったことや、最初からWebpackを選択するようなことが出来るようになっておきたいですね💦(実際のサービスを置き換えるときには、こんなにすんなりとはいかないと思いますが。。。)

参考

inside.pixiv.blog

techlife.cookpad.com