Rails 7 Alpha 2 を動かしてみる

Rails 7 Alpha 1, 2 が公開されたので、今回は、Rails 7 Alpha 2 を動かしてみます。
中でも気になっているのは、importmap なので、こちらをメインで試していきます。

参考

Rails 7 Alpha 2 導入

以下ファイルを用意。

.env
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# Node.js Ruby のバージョン指定
NODE_V=14.18.0
RUBY_V=3.0.2

# データベース用の接頭辞
APP_NAME_SUFFIX=

# docker環境外からRailsにアクセスする際に使用するポート
# Railsの起動ポート
APP_PORT=

# docker環境外からmysqlにアクセスする際に使用するポート
MYSQL_PORT=

# mysqlのrootユーザーパスワード
MYSQL_ROOT_PASSWORD=

# まず変更しない
RAILS_DATABASE_PORT=
Dockerfile
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
FROM amazonlinux:latest

ARG NODE_V="14.10.0"
ARG RUBY_V="3.0.0"
ARG APP_PORT="3000"

RUN yum update -y && \
yum install -y wget which systemd-sysv crontabs && \
wget https://kojipkgs.fedoraproject.org//packages/sqlite/3.8.11/1.fc21/x86_64/sqlite-devel-3.8.11-1.fc21.x86_64.rpm && \
wget https://kojipkgs.fedoraproject.org//packages/sqlite/3.8.11/1.fc21/x86_64/sqlite-3.8.11-1.fc21.x86_64.rpm && \
yum install -y sqlite-3.8.11-1.fc21.x86_64.rpm sqlite-devel-3.8.11-1.fc21.x86_64.rpm && \
yum install -y git tar gcc gcc-c++ make openssl-devel zlib-devel sqlite sqlite-devel bzip2 readline-devel mysql-devel && \
yum --enablerepo=epel,remi,rpmforge install -y libxml2 libxml2-devel && \
yum install -y curl libcurl libcurl-devel && \

# Ruby設定
git clone https://github.com/rbenv/rbenv.git ~/.rbenv && \
echo 'export PATH="$HOME/.rbenv/bin:$PATH"' >> ~/.bash_profile && \
source ~/.bash_profile && \
echo 'eval "$(rbenv init -)"' >> ~/.bash_profile && \
source ~/.bash_profile && \
mkdir -p "$(rbenv root)"/plugins && \
git clone https://github.com/rbenv/ruby-build.git "$(rbenv root)"/plugins/ruby-build && \
rbenv install $RUBY_V && \
rbenv global $RUBY_V

ENV PATH /root/.rbenv/shims:/root/.rbenv/bin:/root/.nodenv/shims:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin

# 作業ディレクトリ作成、設定
RUN mkdir /usr/src/app
WORKDIR /usr/src/app

EXPOSE $APP_PORT
docker-compose.yml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
version: "3"
services:
app:
build:
context: .
dockerfile: Dockerfile
args:
- NODE_V=${NODE_V:-14.10.1}
- RUBY_V=${RUBY_V:-3.0.0}
networks:
- default
privileged: true
command: /sbin/init
ports:
- "127.0.0.1:${APP_PORT:-3000}:${APP_PORT:-3000}"
volumes:
# :cached を付与して、高速化
- .:/usr/src/app:cached
# vendor以下などホストと連携しなくてもよいものを、上書きして永続化の対象外にする。
# exclude volumes
- /usr/src/app/vendor
- /usr/src/app/tmp
- /usr/src/app/log
- /usr/src/app/.git
tty: true
environment:
- RAILS_DATABASE_HOST=db
- RAILS_DATABASE_PORT=${RAILS_DATABASE_PORT:-3306}
- RAILS_DATABASE_USER=root
- RAILS_DATABASE_PASS=${MYSQL_ROOT_PASSWORD:-password_root}
- BINDING=0.0.0.0
- HOST=0.0.0.0
- PORT=${APP_PORT:-3000}
- APP_NAME_SUFFIX=${APP_NAME_SUFFIX:-app}

以上を用意して、以下のコマンドを実行。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
$ docker-compose build
$ docker-compose up -d
$ docker-compose exec app bash

# 以下コンテナ内

$ bundle init

# gem "rails"
# を
# gem "rails", "~> 7.0.0.alpha2"
# に書き換え

$ bundle install
$ bundle exec rails new .
# <= y
$ bundle exec rails s

これで localhost:3000 にアクセスして、みるといつもの楽しそうな画が出ます。
画は変わらない様子。

この時点で、Node.js は一切導入せずに使えています。
標準で webpacker が不要になったので、警告も出ず。

アクセスしてみると、ファイルはバンドルされず個別に取得されてるのが見えます。

importmap を使って plotly.js 導入

よく見かけるのは React の導入なので、今回は plotly.js を導入してみます。

一旦現在の状況。

plotly.js 導入前のimportmap
1
2
3
4
5
6
7
8
9
10
11
12
$ ./bin/importmap json
{
"imports": {
"application": "/assets/application-37f365cbecf1fa2810a8303f4b6571676fa1f9c56c248528bc14ddb857531b95.js",
"@hotwired/turbo-rails": "/assets/turbo-7c5e418c7a4d154780d11e54c0fbd17ca23ba401e915c299c4166410c90db9df.js",
"@hotwired/stimulus": "/assets/stimulus-24c1fe138493d69738cc137a0b8412877d0ffac33385b62d153012a3e7a13db5.js",
"@hotwired/stimulus-importmap-autoloader": "/assets/stimulus-importmap-autoloader-7366d931317007a1e7e62c8dd8198dbc6d6b438207ff8d8539d06019597bf2f7.js",
"controllers/application": "/assets/controllers/application-0a88d7da94dddbd4b5db3a7e58aba83c761c0de29f578c197e4e41a3a79d014f.js",
"controllers/hello_controller": "/assets/controllers/hello_controller-549135e8e7c683a538c3d6d517339ba470fcfb79d62f738a0a089ba41851a554.js",
"controllers": "/assets/controllers/index-f6aa019eef4d0e13975a27efdf6d17ba2c6446417bfcb3139efd889f948a5dfc.js"
}
}

plotly.js を導入します。

plotly.js 導入と導入後のimportmap
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# ./bin/importmap pin でパッケージを導入
$ ./bin/importmap pin plotly.js-dist-min
# ./bin/importmap unpin plotly.js-dist-min で外せる

$ ./bin/importmap json
{
"imports": {
"application": "/assets/application-37f365cbecf1fa2810a8303f4b6571676fa1f9c56c248528bc14ddb857531b95.js",
"@hotwired/turbo-rails": "/assets/turbo-7c5e418c7a4d154780d11e54c0fbd17ca23ba401e915c299c4166410c90db9df.js",
"@hotwired/stimulus": "/assets/stimulus-24c1fe138493d69738cc137a0b8412877d0ffac33385b62d153012a3e7a13db5.js",
"@hotwired/stimulus-importmap-autoloader": "/assets/stimulus-importmap-autoloader-7366d931317007a1e7e62c8dd8198dbc6d6b438207ff8d8539d06019597bf2f7.js",
"plotly.js-dist-min": "https://ga.jspm.io/npm:plotly.js-dist-min@2.5.1/plotly.min.js",
"controllers/application": "/assets/controllers/application-0a88d7da94dddbd4b5db3a7e58aba83c761c0de29f578c197e4e41a3a79d014f.js",
"controllers/hello_controller": "/assets/controllers/hello_controller-549135e8e7c683a538c3d6d517339ba470fcfb79d62f738a0a089ba41851a554.js",
"controllers": "/assets/controllers/index-f6aa019eef4d0e13975a27efdf6d17ba2c6446417bfcb3139efd889f948a5dfc.js"
}
}

導入後の importmap には、plotly.js-dist-min が含まれているのがわかります。
パッケージのダウンロードがされているわけでもないので動作は高速。
plotly.js-dist-min の取得先は、https://ga.jspm.ioです。
JSPMが管理する importmap 用モジュールを提供してくれる CDN だそうです。

適当なルーティングを作成して、erb に以下のように記述します。

1
2
3
4
5
6
7
8
9
10
11
12
13
<div id="glaph"></div>
<script type="module">
import Plotly from "plotly.js-dist-min";

const data = [
{
x: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
y: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
},
];

Plotly.newPlot("glaph", data);
</script>

これで再度作成した URL にアクセスすると、グラフが作成されました。

開発者ツールのネットワークを見てみます。
plotly.js-dist-min は、https://ga.jspm.io/npm:plotly.js-dist-min@2.5.1/plotly.min.jsから取得されているのがわかります。

スクリプトタグは <script type="module"> で書かないと、import Plotly from "plotly.js-dist-min"; でエラーになるのが注意事項。

esbuild も試してみる

開発者ツールのネットワークを見てみると stimulus は、rails から配信されています。
rake assets:precompile で js のビルドされることがわかります。
ここで、Rails 7 は別の js のビルド環境も用意しているということで試してみます。

rails/jsbundling-rails を見てみます。

以下のように、アプリケーションの作成時に指定できることがわかります。

1
$ rails new myapp -j [esbuild|rollup|webpack]

この方法でアプリケーションを作成してみます。

Dockerfile を変更して、今回は Node.js を導入しておきます。

Dockerfile
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
FROM amazonlinux:latest

ARG NODE_V="14.10.0"
ARG RUBY_V="3.0.0"
ARG APP_PORT="3000"

RUN yum update -y && \
yum install -y wget which systemd-sysv crontabs && \
wget https://kojipkgs.fedoraproject.org//packages/sqlite/3.8.11/1.fc21/x86_64/sqlite-devel-3.8.11-1.fc21.x86_64.rpm && \
wget https://kojipkgs.fedoraproject.org//packages/sqlite/3.8.11/1.fc21/x86_64/sqlite-3.8.11-1.fc21.x86_64.rpm && \
yum install -y sqlite-3.8.11-1.fc21.x86_64.rpm sqlite-devel-3.8.11-1.fc21.x86_64.rpm && \
yum install -y git tar gcc gcc-c++ make openssl-devel zlib-devel sqlite sqlite-devel bzip2 readline-devel mysql-devel && \
yum --enablerepo=epel,remi,rpmforge install -y libxml2 libxml2-devel && \
yum install -y curl libcurl libcurl-devel && \

# Node.js設定
git clone https://github.com/nodenv/nodenv.git ~/.nodenv && \
echo 'export PATH="$HOME/.nodenv/bin:$PATH"' >> ~/.bash_profile && \
source ~/.bash_profile && \
echo 'eval "$(nodenv init -)"' >> ~/.bash_profile && \
source ~/.bash_profile && \
mkdir -p "$(nodenv root)"/plugins && \
git clone https://github.com/nodenv/node-build.git "$(nodenv root)"/plugins/node-build && \
nodenv install $NODE_V && \
nodenv global $NODE_V && \

# Ruby設定
git clone https://github.com/rbenv/rbenv.git ~/.rbenv && \
echo 'export PATH="$HOME/.rbenv/bin:$PATH"' >> ~/.bash_profile && \
source ~/.bash_profile && \
echo 'eval "$(rbenv init -)"' >> ~/.bash_profile && \
source ~/.bash_profile && \
mkdir -p "$(rbenv root)"/plugins && \
git clone https://github.com/rbenv/ruby-build.git "$(rbenv root)"/plugins/ruby-build && \
rbenv install $RUBY_V && \
rbenv global $RUBY_V && \

# Yarn設定
wget https://dl.yarnpkg.com/rpm/yarn.repo -O /etc/yum.repos.d/yarn.repo && \
curl --silent --location https://rpm.nodesource.com/setup_14.x | bash - && \
yum install yarn -y

ENV PATH /root/.rbenv/shims:/root/.rbenv/bin:/root/.nodenv/shims:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin

# 作業ディレクトリ作成、設定
RUN mkdir /usr/src/app
WORKDIR /usr/src/app

EXPOSE $APP_PORT

https://rpm.nodesource.com/setup_6.x としていたが、https://rpm.nodesource.com/setup_14.xに変更。
そもそもが古すぎた。

https://rpm.nodesource.com/setup_6.x だと yarn が見つからない?ということも起きた。

以下コマンドで準備。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
$ docker-compose build
$ docker-compose up -d
$ docker-compose exec app bash

# 以下コンテナ内

$ bundle init

# gem "rails"
# を
# gem "rails", "~> 7.0.0.alpha2"
# に書き換え

$ bundle install
$ bundle exec rails new . -j esbuild
# <= y

# しれっと、次のような指示が来るので、package.json に追記しておく
# Add "scripts": { "build": "esbuild app/javascript/*.* --bundle --outdir=app/assets/builds" to your package.json

# run gem install foreman from "."
# とforemanがインストールされる
# bin/dev から起動したいが、
# forman には が、パスが通っていない。
# のでシェルの中でエイリアスを 使う

# #!/usr/bin/env bash
#
# foreman start -f Procfile.dev
#
# を書き換えて
#
# #!/usr/bin/env bash
#
# shopt -s expand_aliases
# alias foreman='rbenv exec foreman' <= 2 行書き足す
#
# foreman start -f Procfile.dev

$ bin/dev

ここまでやって、いつもの画面が出ます。
コンソールを見るとわかることですが、以下のメッセージがコンソールに上がります。
$ esbuild app/javascript/*.* --bundle --outdir=app/assets/builds --watch

app/javascript/ 以下が、監視されているので書き換えると、以下のメッセージが上がります。
[watch] build started (change: "app/javascript/controllers/application.js")

試しに、こちらでも plotly.js-dist-min を導入してみます。

1
$ npm install plotly.js-dist-min

適当なルーティングを追加して、app/javascript/graph.js を作成。

app/javascript/graph.js
1
2
3
4
5
6
7
8
9
10
import Plotly from "plotly.js-dist-min";

const data = [
{
x: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
y: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
},
];

Plotly.newPlot("glaph", data);

読み込み側で追記。

app/javascript/application.js
1
2
3
4
// Entry point for the build script in your package.json
import "@hotwired/turbo-rails";
import "./controllers";
import "./graph"; // <= 追記

以上で、<div id="glaph"></div> のタグが有るページには、plotly.js で作成されたグラフが出るようになりました。

esbuild を使用できました。
開発者ツールのネットワークを見てみると、js ファイルはビルド済みの1つだけ取得されていています。

js のロードは esbuild では、次のようになっています。

<%= javascript_include_tag "application", "data-turbo-track": "reload", defer: true %>

対して、importmap は、<%= javascript_importmap_tags %> でした。
あいも変わらずヘルパーは便利です。


今回は、Rails 7 Alpha 2 を動かしてみましたが、importmap を使った場合でも stimulus はビルドして返されていました。
アプリケーションと強く結びつく stimulus は必須なのでそうするが、それ以外はそれこそ塩をまぶすような使い方の想定を感じます。

対して、本当に外部ライブラリも含めたアプリケーションを作る、外部ライブラリが動作できないとアプリケーションとして成立しない。
というときに esbuild などを選択するといった具合に。

foreman がインストールされたりと便利なのですが、Gemfile に記載がない形で導入されています。
そのためチームで開発していて、途中参入した人は「素直に bundle install しても、動かないんですが」ということも発生しそうではあります。

Docker での導入では、既存環境の構成という前提が無いので、再現性もあるし何をするかはっきりしてやはりイイです。

ではでは。