はじめに
WebアプリケーションをネイティブなアプリのようにできるPWA化に憧れて、実装してみました!
紆余曲折しましたがなんとか完成!
忘れないうちにまとめておこうと思います!
おおまかな流れは、こちらのREADMEを参考にしています↓
前提
Ruby 3.1.2
Rails 6.1.7.7
Rails6以降の記事が少なくて…!苦戦しました💦
Serviceworkerの導入
gem導入
gem 'serviceworker-rails'
$ bundle install
ファイルはコマンドを実行すれば、自動作成してもらえます
$ rails g serviceworker:install
Running via Spring preloader in process 31804
create app/assets/javascripts/manifest.json.erb
create app/assets/javascripts/serviceworker.js.erb
create app/assets/javascripts/serviceworker-companion.js
create config/initializers/serviceworker.rb
The file /home/ec2-user/environment/go_out_planning/app/assets/javascripts/application.js does not appear to exist
application.jsはRails 5.x以前だとassets/javascript/に格納されていましたが、現在Rails6のため下記が出力されます
The file /home/ec2-user/environment/go_out_planning/app/assets/javascripts/application.js does not appear to exist
serviceworker-companion.jsの読み込み
app/assets/javascripts/serviceworker-companion.js
のjsファイルをapplication.jsのあるapp/javascript/packsに移動します
次に、application.jsでserviceworker-companionを読み込みます
import Rails from "@rails/ujs"
import Turbolinks from "turbolinks"
import * as ActiveStorage from "@rails/activestorage"
import "channels"
import "jquery";
import "popper.js";
import "bootstrap";
import "../stylesheets/application";
// この行を追加
import '../packs/serviceworker-companion';
Rails.start()
Turbolinks.start()
ActiveStorage.start()
設定
Rails.configuration.assets.precompile += %w[serviceworker.js manifest.json]
を最終行に追加
# Be sure to restart your server when you modify this file.
# Version of your assets, change this if you want to expire all your assets.
Rails.application.config.assets.version = '1.0'
# Add additional assets to the asset load path.
# Rails.application.config.assets.paths << Emoji.images_path
# Add Yarn node_modules folder to the asset load path.
Rails.application.config.assets.paths << Rails.root.join('node_modules')
# Precompile additional assets.
# application.js, application.css, and all non-JS/CSS in the app/assets
# folder are already added.
Rails.application.config.assets.precompile += %w( admin.js admin.css )
# この行を追加
Rails.configuration.assets.precompile += %w[serviceworker.js manifest.json]
こちらは特に触る必要はありませんでした
# frozen_string_literal: true
Rails.application.configure do
config.serviceworker.routes.draw do
# map to assets implicitly
match "/serviceworker.js"
match "/manifest.json"
# Examples
#
# map to a named asset explicitly
# match "/proxied-serviceworker.js" => "nested/asset/serviceworker.js"
# match "/nested/serviceworker.js" => "another/serviceworker.js"
#
# capture named path segments and interpolate to asset name
# match "/captures/*segments/serviceworker.js" => "%{segments}/serviceworker.js"
#
# capture named parameter and interpolate to asset name
# match "/parameter/:id/serviceworker.js" => "project/%{id}/serviceworker.js"
#
# insert custom headers
# match "/header-serviceworker.js" => "another/serviceworker.js",
# headers: { "X-Resource-Header" => "A resource" }
#
# anonymous glob exposes `paths` variable for interpolation
# match "/*/serviceworker.js" => "%{paths}/serviceworker.js"
end
end
serviceworker.js
この状態で一旦サーバーを立ち上げてみます
$ rails s
[Webpacker] Compiling...
Started GET "/service_worker.js" for 180.0.182.32 at 2024-09-17 05:07:08 +0000
Cannot render console from 180.0.182.32! Allowed networks: 127.0.0.0/127.255.255.255, ::1
ActionController::RoutingError (No route matches [GET] "/service_worker.js"):
/service_worker.jsに接続できないよーと言われてますね
ということでservice_worker.jsをpublicの中に作成しましょう
なぜpublicの中なのか?
publicの中に配置することにより、Rails のルーティングを介さずに静的ファイルとして提供でき、url/service_worker.jsで接続することが可能になります!
self.addEventListener('install', function(event) {
console.log('[Service Worker] Installing Service Worker...');
});
self.addEventListener('activate', function(event) {
console.log('[Service Worker] Activating Service Worker...');
});
self.addEventListener('fetch', function(event) {
console.log('[Service Worker] Fetching something....', event.request.url);
});
アドレスバーに~.com/service_worker.jsを打ち込むと、
以下のような画面になっていればOK!
検証ツールで確認
Application>Service workersを開いてStatusを確認
ちゃんとactivated is a runningになってますね!
manifest.json.erb
/assets/javascript/manifest.json.erb
が現在では読み込まれていないいないので、application.html.erbの<head>
部分に<link rel="manifest" href="/manifest.json" crossorigin="use-credentials">
を追記していきます!
<!DOCTYPE html>
<html>
<head>
<title>GoOutPlanning</title>
<link rel="manifest" href="/manifest.json" crossorigin="use-credentials">
</head>
<body>
:
</body>
</html>
majifest.json.erbを編集
デフォルトの記述がこちら↓
<% icon_sizes = Rails.configuration.serviceworker.icon_sizes %>
{
"name": "My Progressive Rails App",
"short_name": "Progressive",
"start_url": "/",
"icons": [
<% icon_sizes.map { |s| "#{s}x#{s}" }.each.with_index do |dim, i| %>
{
"src": "<%= image_path "serviceworker-rails/heart-#{dim}.png" %>",
"sizes": "<%= dim %>",
"type": "image/png"
}<%= i == (icon_sizes.length - 1) ? '' : ',' %>
<% end %>
],
"theme_color": "#000000",
"background_color": "#FFFFFF",
"display": "fullscreen",
"orientation": "portrait"
}
今回は下記のように編集↓
iconはサイズ別に複数用意しておく(適当な変換サイトでOK)
assets/imagesに入れておこう!
{
"name": "おでかけプランニング-GoOutPlanning-",
"short_name": "GoOutPlanning",
"start_url": "/",
"icons": [
{
"src": "<%= image_path "go_out_planning_logo_36.png" %>",
"sizes": "36x36",
"type": "image/png"
},
{
"src": "<%= image_path "go_out_planning_logo_48.png" %>",
"sizes": "48x48",
"type": "image/png"
},
{
"src": "<%= image_path "go_out_planning_logo_72.png" %>",
"sizes": "72x72",
"type": "image/png"
},
{
"src": "<%= image_path "go_out_planning_logo_96.png" %>",
"sizes": "96x96",
"type": "image/png"
},
{
"src": "<%= image_path "go_out_planning_logo_144.png" %>",
"sizes": "144x144",
"type": "image/png"
},
{
"src": "<%= image_path "go_out_planning_logo_192.png" %>",
"sizes": "192x192",
"type": "image/png"
},
{
"src": "<%= image_path "go_out_planning_logo_512.png" %>",
"sizes": "512x512",
"type": "image/png"
}
],
"theme_color": "#3B4674",
"background_color": "#FFFFFF",
"display": "standalone",
"orientation": "portrait",
"screenshots": [
{
"src": "<%= image_path "screenshot-wide_1472x720.png" %>",
"sizes": "1472x720",
"type": "image/png",
"form_factor": "wide"
},
{
"src": "<%= image_path "screenshot-mobile_640x1280.png" %>",
"sizes": "640x1280",
"type": "image/png",
"form_factor": "narrow"
}
]
}
検証ツールで確認
Application>Manifestを開いて内容が反映されていればOK!
アプリをインストールしてみる
アドレスバーにインストールのマークが出ているのでクリックし、インストールする
これで開発環境のアプリインストールができました!
あとはデプロイして本番環境でも問題なく動作するか確認しましょう!
本番環境での動作確認
最初に本番環境で確認したら反映されていなかったので、もし同じ方がいらっしゃったらassets:precompile
を実行してみるといいかもです!
また、一応UIが非表示かされてはいるのですが、本番環境で/service_worker.jsにアクセスできなくなっていたので修正しておきます
/service_worker.jsに接続できないようですね
ちなみに、アドレスバーにgo-out-planning.net/service_worker.jsを打ち込むと、以下のような画面が出てきます!
publicにservice_worker.jsを格納しているはずなのに、出てこない!
というのはこれで一発で解消できます!
config.public_file_server.enabled = ENV['RAILS_SERVE_STATIC_FILES'].present?
を↓に修正するだけ!
config.public_file_server.enabled = true
config.public_file_server.enabled の設定を true に変更すると、Rails アプリケーションが静的ファイルを自動的に提供するようになります。具体的には、public ディレクトリにある静的ファイル(例: JavaScript、CSS、画像ファイルなど)が、Rails アプリケーションのサーバーを通じて提供されるようになります。
ただ、今回は小規模なアプリケーション開発のため上記をtrueにしていますが、基本的には非推奨のようです…
もっといい方法あれば是非教えてください🙇
実際のアプリ
さいごに
長くなってしまいましたが、以上がRailsアプリをPWA化するために私が行ったことです!
参照サイト
ありがとうございました!