個人のサービスでwebpackでフロントエンド関連のファイルを管理していてsimpackerを使ってRailsで読み込むみたいなことを行なっているのですが。。。
新規のページをつくるときとかに手でエントリーのJSを用意してページ用のCSSファイルを作ってインポートして、View側にjavascript_pack_tag
といった読み込み用のヘルパーを記載するのが面倒だったので、ジェネレーターを自作してコマンド実行でそれらを行えるようにしました。
作成したジェネレーター
作成したのは以下のようなview_with_front_end
で引数にcontrollerの名前とactionの配列を渡すとview
及びエントリーの.ts
,.scss
を作成してくれるジェネレーターです。
$ bin/rails g view_with_front_end foo index show create app/javascript/packs/foo/index.ts create app/javascript/stylesheets/foo/index.scss create app/views/foo/index.html.erb create app/javascript/packs/foo/show.ts create app/javascript/stylesheets/foo/show.scss create app/views/foo/show.html.erb
実際に作成されるファイルは以下のような形でviewでは、javascript_pack_tag
、stylesheet_pack_tag
で作成したscss
とts
をデフォルトで読み込むようにしてくれます。
import "@css/foo/index.scss"; console.log("foo/index");
h1 { color: blue; }
<%= stylesheet_pack_tag 'foo/index' %> <%= javascript_pack_tag 'foo/index', defer: true %> <h1>foo/index</h1>
実際のコードは以下の通りです。環境によって変更されるであろう値(エントリーのjsファイルのパス等)は、optionで指定できるようにしています。
# frozen_string_literal: true class ViewWithFrontEndGenerator < Rails::Generators::NamedBase VIEW_EXTENSION = 'erb' ENTRY_JS_PATH = 'app/javascript/packs' ENTRY_JS_EXTENSION = 'ts' CSS_PATH = 'app/javascript/stylesheets' CSS_EXTENSION = 'scss' CSS_PATH_ALIAS = '@css' argument :actions, type: :array, default: [], banner: 'action action' class_option :view_extension, type: :string, default: VIEW_EXTENSION class_option :entry_js_path, type: :string, default: ENTRY_JS_PATH class_option :entry_js_extension, type: :string, default: ENTRY_JS_EXTENSION class_option :css_path, type: :string, default: CSS_PATH class_option :css_extension, type: :string, default: CSS_EXTENSION class_option :css_path_alias, type: :string, default: CSS_PATH_ALIAS desc <<~TEXT Description: Create View with FrontEnd files(JS/CSS). Example: $ bin/rails g view_with_front_end foo index show create app/javascript/packs/foo/index.ts create app/javascript/stylesheets/foo/index.scss create app/views/foo/index.html.erb create app/javascript/packs/foo/show.ts create app/javascript/stylesheets/foo/show.scss create app/views/foo/show.html.erb TEXT def create_files build_instance_valiables(options) actions.map do |action| create_file "#{@entry_js_path}/#{@resource}/#{action}.#{@entry_js_extension}", js_file_body(action) create_file "#{@css_path}/#{@resource}/#{action}.#{@css_extension}", css_file_body create_file "app/views/#{@resource}/#{action}.html.#{@view_extension}", view_file_body(action) end end private def build_instance_valiables(options) @resource = file_name @view_extension = options['view_extension'] @entry_js_path = options['entry_js_path'] @entry_js_extension = options['entry_js_extension'] @css_path = options['css_path'] @css_extension = options['css_extension'] @css_path_alias = options['css_path_alias'] end def js_file_body(action) <<~ERB import "#{@css_path_alias}/#{@resource}/#{action}.#{@css_extension}"; console.log("#{@resource}/#{action}"); ERB end def css_file_body <<~ERB h1 { color: blue; } ERB end def view_file_body(action) <<~ERB <%= stylesheet_pack_tag '#{@resource}/#{action}' %> <%= javascript_pack_tag '#{@resource}/#{action}', defer: true %> <h1>#{@resource}/#{action}</h1> ERB end end
ジェネレーターを自作するときの注意事項
ガイド通りに作るとlib配下をeager_loadingするようにしていると、自動読み込み周りでエラーが発生しました。。。
以下の対応が必要なようです。
# NOTE: generatorは自動読み込みでエラーになるのでzeitwerkによるautoloadの対象外にする # https://github.com/rails/rails/issues/38671 Rails.autoloaders.main.ignore(Rails.root.join('lib/generators/**/*.rb'))