How to register service-worker in rails 7 used importmap?

Viewed 52

Facing problem

I want to convert a web application created with Rails 7 that uses importmap into a PWA However, I'm having trouble registering the service-worker using importmap. I'd appreciate it if you could give me some advice.

Status quo

At first, I tried to use this gem, but it didn't work in the importmap environment, so I referred to this site, but it didn't work.

The result of lighthouse check is as below.

enter image description here

Development environment

ruby 3.1.2
rails 7.0.3
importmap-rails 1.1.2
tailwindcss-rails 2.0.10

Related source code

config/route.rb


    get '/service-worker.js', to: 'service_worker#service_worker'
    get '/offline.html', to: 'service_worker#offline'

./app/controllers
├── service_worker_controller.rb

class ServiceWorkerController < ApplicationController
    protect_from_forgery except: :service_worker
    skip_before_action :require_login
    
    def service_worker; end
    
    def offline; end
end

./app/views/service_worker
├── offline.html.erb
└── service-worker.js


const VERSION = 'v1';
const NAME = 'app_name-';
const CACHE_NAME = NAME + VERSION;
const urlsToCache = [
    "./offline.html"
];
    
    
self.addEventListener('install', function (event) {
    event.waitUntil(
      caches.open(CACHE_NAME).then(function (cache) {
        console.log('Opened cache');
        return cache.addAll(urlsToCache);
      })
    );
});
    
self.addEventListener('fetch', function (event) 
    if (event.request.cache === 'only-if-cached' && event.request.mode !== 'same-origin')
        return;
    event.respondWith(
        cache.match(event.request).then(function (response) {
            if (response) {
                return response;
            }
            return fetch(event.request);
        })
    );
});
    
self.addEventListener('activate', event => {
    event.waitUntil(
        cache.keys().then(keys => Promise.all(
            keys.map(key => {
                if (!CACHE_NAME.includes(key)) {
                    return cache.delete(key);
                }
            })
        )).then(() => {
            console.log(CACHE_NAME + "activated");
        })
    );
});

/app/javascript/controllers
└── service-worker_controller.js

import { Controller } from "@hotwired/stimulus"
    
export default class extends Controller {
    connect () {
        if ('serviceWorker' in navigator) {
            window.addEventListener('load', function() {
                navigator.serviceWorker.register("/service-worker.js", {scope: "./" }).then(function (registration) {
                console.log("ServiceWorker registration successful with scope: ", registration.scope);
                }, function (err) {
                    console.log("ServiceWorker registration failed: ", err);
                });
            });
        }
    }
}

app/views/layouts/
└── application.html.erb


    <!DOCTYPE html>
    <html lang="ja">
      <head>
        <meta name="viewport" content="width=device-width,initial-scale=1">
        <%= csrf_meta_tags %>
        <%= csp_meta_tag %>
        <%= stylesheet_link_tag "tailwind", "inter-font", "data-turbo-track": "reload" %>
    
        <%= stylesheet_link_tag "application", "data-turbo-track": "reload" %>
        <%= javascript_importmap_tags %>
    
        <title><%= page_title(yield(:title)) %></title>
        <%= render 'application/favicon' %>
        <%= display_meta_tags(default_meta_tags) %>
      </head>
    
      <body class="pb-420 box-border break-words">
        <main>
          <div data-controller="service-worker">
            <%= render 'shared/navbar' %>
            <%= render 'shared/flash' %>
            <div class="w-full" data-controller="service_worker">
              <%= yield %>
              <%= render 'shared/footer' %>
            </div>
          </div>
        </main>
      </body>
    </html>

Error message

when I reload the page, The following error appears on the console of chrome DV tool. The script does not have a MIME type.
Also, the following message appears on the terminal.


    Started GET "/service-worker.js" for ::1 at xxxxxxxxxxxx
    18:49:40 web.1  | Processing by ServiceWorkerController#service_worker as */*
    18:49:40 web.1  | No template found for ServiceWorkerController#service_worker, rendering head :no_content
    18:49:40 web.1  | Completed 204 No Content in 3ms (ActiveRecord: 0.0ms | Allocations: 1278)

Please let me know if you find anything strange.

0 Answers
Related