JavaScriptライブラリのためのRubyGemを作ってみたので、作成手順を順を追いながらまとめます。JavaScriptライブラリのGem作成方法は日本語記事があまりなかったので、参考になれば幸いです。
JavaScriptライブラリのGemは、有名所ですとjquery-rails等です。
今回は、Gemを使うときに下記のようにAsset Pipelineのマニフェストファイルで宣言して読み込むタイプのものについて見ていきます。
//= require jquery
今回作ったGem
react_rails_modalというreact-rails上でモーダルを動かすためのGemを今回作りました。react-railsはRailsにReactを導入するためのものです。
使い方は簡単です。
まずreact-railsをインストールした上で、本Gemをインストールします。
gem 'react_rails_modal'
$ bundle install
次にRailsコマンドを実行します。
$ rails g react_rails_modal:install
これにより、下記がapplication.js
に追記され、マニフェストファイルにライブラリの読み込みが宣言されます。
//= require react_rails_modal
これでreact_rails_modalが読み込まれるようになったので、react-rails上でモーダルが使えるようになります。
モーダルの使い方に関してはreact-railsでモーダルを実装するにまとめしたのでそちらをご覧ください。
ここから、Gemの作成手順を追いながら、JavaScriptライブラリのためのGemの作成方法を見ていきます。
準備
まずGemとbundlerのアップデートをします。
$ gem update --system
# bundlerをインストールしていない場合はインストールします
$ gem install bundler
$ gem update bundler
ひな形の作成
Gemのひな形をテストありで作ります。
$ bundle gem react_rails_modal -t
gemspec
Gemの基本的な情報をgemspecにまとめます。
# coding: utf-8
lib = File.expand_path('../lib', __FILE__)
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
require 'react_rails_modal/version'
Gem::Specification.new do |spec|
spec.name = 'react_rails_modal'
spec.version = ReactRailsModal::VERSION
spec.summary = 'Accessible modal dialog component on react-rails'
spec.description = 'React_rails_modal creates modal dialog easily on react-rails'
spec.homepage = 'https://github.com/kiyodori/react_rails_modal'
spec.license = 'MIT'
spec.authors = ['kiyodori']
spec.add_development_dependency 'bundler', '>= 1.13'
spec.add_development_dependency 'rspec', '>= 3.0'
spec.add_development_dependency 'rails', '>= 3.2'
spec.add_development_dependency 'react-rails', '>= 1.7.0'
spec.files = Dir[
'lib/**/*',
'README.md',
'LICENSE.txt'
]
spec.require_paths = ['lib']
end
今回はreact-railsとセットで動くGemなので、 rails
とreact-rails
をadd_development_dependency
に追加します。
add_development_dependency
に開発に必要なGemを記載することで、Gemfileはこの中身を参照します。
Gemの本体の実装
それではGem本体を下記手順で実装していきます。
- Asset Pipelineのパスにreact_rails_modalファイルが読み込まれるよう設定する
- Asset Pipelineにreact_rails_modalファイルを追加するRailsコマンドを作成する。具体的には、マニフェストファイルに
//= require react_rails_modal
を追記するRailsコマンドを作成する - 設定したパスにreact_rails_modalファイルを設置する
Gem本体の実装はlib/
ディレクトリに行います。
── lib
├── react_rails_modal
│ └── railtie.rb
│ └── version.rb
└── react_rails_modal.rb
呼び出し側でGemが読み込まれるとlib/react_rails_modal.rb
が呼ばれるようになっているので、lib/react_rails_modal.rb
でlib/react_rails_modal/
ディレクトリ配下のファイルをrequire
します。
require 'react_rails_modal/version'
require 'react_rails_modal/railtie'
1. Asset Pipelineのパスにreact_rails_modalファイルが読み込まれるよう設定する
パスはRailsの起動時に設定されます。Rails::Railtie
を使うことで、Railsの起動時にフックしてパスの追記を行います。
require 'rails'
module ReactRailsModal
class Railtie < ::Rails::Railtie
GEM_ROOT = Pathname.new('../../../').expand_path(__FILE__)
config.react_rails_modal = ActiveSupport::OrderedOptions.new
initializer 'react_rails_modal.set_variant' do |app|
app.config.assets.paths << GEM_ROOT.join('lib/assets/javascripts/').to_s if app.config.respond_to?(:assets)
end
end
end
Rails::Railtie
を継承したクラスで、initializer
マクロを用いて、Railsの起動プロセス時にconfig.assets.paths
にパスを追記します。
これにより、lib/assets/javascripts/
がAsset Pipelineのパスに追加されます。
実際に本Gemを読み込んだアプリケーションでパスを確認してみると、次のようになっています。
$ rails console
[1] pry(main)> Rails.application.config.assets.paths
=> ["{other_path}", ..., "{project_path}/vendor/bundle/ruby/{ruby_version}/gems/react_rails_modal-{gem_version}/lib/assets/javascripts/"]
最終的にはlib/assets/javascripts/
にreact_rails_modal.js
ファイルを置いておけば、マニフェストファイルでreact_rails_modalファイルが宣言された時に読み込まれます。
2. Asset Pipelineにreact_rails_modalファイルを追加するrailsコマンドを作成する
Asset Pipelineにreact_rails_modalファイルを追加するために、下記Railsコマンドを準備しました。
$ rails g react_rails_modal:install
上記コマンドにより、下記がapplication.js
に追記されます。
//= require react_rails_modal
このコマンドは、Railsジェネレータを利用することで作成できます。
lib/generators/react_rails_modal/install_generator.rb
というファイルを作成します。
module ReactRailsModal
module Generators
class InstallGenerator < ::Rails::Generators::Base
desc 'Install react_rails_modal'
def inject_react_rails_modal
require_react_rails_modal = "//= require react_rails_modal\n"
if manifest.exist?
manifest_contents = File.read(manifest)
if match = manifest_contents.match(/\/\/=\s+require_tree[^\n]*/)
inject_into_file manifest, require_react_rails_modal, { before: match[0] }
else
append_file manifest, require_react_rails_modal
end
else
create_file manifest, require_react_rails_modal
end
end
private
def manifest
Pathname.new(destination_root).join('app/assets/javascripts', 'application.js')
end
end
end
end
Rails::Generators::Base
を継承したクラスを作成します。ジェネレータが起動されると、ジェネレータ内で定義されているパブリックメソッドが定義順に実行されます。
今回はinject_react_rails_modal
メソッドの中で、app/assets/javascripts/application.js
に"//= require react_rails_modal\n"
を追記しています。
3. 設定したパスにreact_rails_modalファイルを設置する
ここまででAsset Pipelineに、パスを設定し、react_rails_modalファイルを追加できました。あとは設定したパスにreact_rails_modalファイルを置くだけです。
今回はreact_buildsディレクトリに、Reactでモーダルを実現するためのjsxファイルを置き、それをwebpackでjsファイルにコンパイルしています。
コンパイルされたjsファイルを、上記で設定したパスであるlib/assets/javascripts/
以下にreact_rails_modal.jsとして設置しています。
ここはJavaScript関連の処理になるので、具体的な内容は省略します。
このコンパイル作業をRakeタスク化し、下記コマンドで簡単に呼び出せるようにします。
$ rake react_rails_modal:build
Rakeタスクの定義はRakefileに行います。
begin
require 'bundler/setup'
rescue LoadError
puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
end
Bundler::GemHelper.install_tasks
namespace :react_rails_modal do
desc 'Build the JS bundles with Webpack'
task :build do
Dir.chdir("react_builds") do
`yarn run build`
end
end
end
Rakeタスクではyarn run build
コマンドを実行していて、その中でwebpackを用いて、Reactのjsxファイルをjsファイルにコンパイルしています。
このように、lib/assets/javascripts/
以下にreact_rails_modal.jsを設置することで、Asset Pipelineから読み込むことができます。
以上で完成です。
まとめ
JavaScriptライブラリをGemにする手順を見てきました。
まとめると、下記手順になります。
- Gemのひな形を
bundle gem
コマンドで作成する - gemspecにGemの基本的な情報をまとめる
- Gemの本体である
lib/react_rails_modal.rb
で必要なファイルを読み込む - Asset Pipelineのパスにreact_rails_modalファイルが読み込まれるよう設定する
- パスの追加は、
Rails::Railtie
を使い、Railsの起動時にフックして設定する
- パスの追加は、
- Asset Pipelineにreact_rails_modalファイルを追加するrailsコマンドを作成する
- マニフェストファイルに
//= require react_rails_modal
を追記するRailsコマンドを作成する - Railsコマンドは
Rails::Generators::Base
を用いることで設定できる
- マニフェストファイルに
- 設定したパスにreact_rails_modalファイルを設置する
- Reactのjsxファイルをjsファイルにコンパイルしたものをパスに設置する
JavaScriptライブラリをGemにされる時に参考になれば幸いです。