更新于 1/18/2023 以反映 Bijan
的回答我想将使用 importmap 的 Rails 7 创建的 Web 应用程序转换为 PWA。 但是,我在使用 importmap 注册服务工作者时遇到了问题。 如果你能给我一些建议,我将不胜感激。
开始尝试使用this gem,但是在importmap环境下不行,于是参考了this site,但是不行
灯塔检查的结果如下。
红宝石 3.1.3
轨道 7.0.3
importmap-rails 1.1.2
tailwindcss-rails 2.0.10
链轮 4.1.1.
config/route.rb
get '/service_worker', to: 'service_workers#service_worker'
get '/offline', to: 'service_workers#offline'
./应用程序/控制器
├──
service_workers_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.html.erb
<script>
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");
})
);
});
</script>
/应用程序/javascript/控制器
└──
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", {scope: "/" }).then(function (registration) {
console.log("ServiceWorker registration successful with scope: ", registration.scope);
}, function (err) {
console.log("ServiceWorker registration failed: ", err);
});
});
}
}
}
应用程序/视图/布局/
└──
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="dark:bg-gray-800 break-words flex flex-col min-h-screen">
<%= render 'static_pages/navbar' %>
<div id="flash" class="z-50 flex-col fixed top-16 right-1 ">
<%= render 'shared/flash' %>
</div>
<%= tag.main class: "mb-auto relative" do %>
<div class="w-full" data-controller="service-worker">
<%= yield %>
</div>
<% end %>
<%= render 'static_pages/footer' %>
</body>
</html>
当我重新加载页面时,以下错误出现在 chrome DV 工具的控制台上。
The script has an unsupported MIME type ('text/html').
如果你发现任何奇怪的事情,请告诉我。
到目前为止,除了通过控制器呈现 service-worker.js 文件外,您的示例看起来还不错。你的控制器抱怨它没有找到模板。您可以为 service_worker 方法创建一个视图,并将 service-worker.js 文件的内容粘贴到其中。你也可以让你的控制器方法直接发送文件。应该很容易解决。
这不是模板问题。您发布的错误消息中提到了该错误。当脚本应该是 javascript 时,脚本以 text/html 形式返回。
您当前的代码将 JS 作为文本/html 发送,这让浏览器感到困惑,然后停止执行工作人员的代码。
你需要在标题中提到工作人员的代码是 application/javascript 或类似的东西,以确保浏览器以正确的方式解释它。