【问题标题】:Ruby on Rails & service workerRuby on Rails 和服务工作者
【发布时间】:2015-05-02 21:16:41
【问题描述】:

我正在尝试在我的 Ruby on Rails 应用程序中使用服务工作者。

我需要在我的 app/javascripts/service-worker.js.erb 文件中使用一些 erb 功能。 Service Worker 注册脚本如下所示:

var registerServiceWorker = function() {
  navigator.serviceWorker.register(
    '<%= asset_path('service-worker.js') %>',
    { scope: '/assets/' }
  )
  .then(function() {
    console.info('Service worker successfully registered');
  })
  .catch(function(error) {
    console.warn('Cannot register sercie worker. Error = ', error);
  });
}

这不起作用;我从来没有在这里得到承诺:

navigator.serviceWorker.ready.then

我也尝试了.// 范围,但我得到了这个错误:

DOMException: 无法注册 ServiceWorker: 的路径 提供的范围 ('/') 不在允许的最大范围 ('/assets/') 之下。 调整范围,移动 Service Worker 脚本,或者使用 Service-Worker-Allowed HTTP 标头允许范围。

如果我将service-worker.js 移动到public 文件夹,删除.erb 扩展并将范围更改为./,一切正常,但我没有模板引擎。

有什么建议吗?

【问题讨论】:

    标签: javascript ruby-on-rails html service-worker


    【解决方案1】:

    现在有一个 gem,serviceworker-rails,它允许您代理对资产管道中的 serviceworker 脚本的请求。由于浏览器注册 serviceworker 脚本的方式,最好避免缓存它们。

    Sprockets 将对资产进行指纹识别,Rails(或您的网络服务器)通常使用来自/assets 目录的积极缓存标头为编译文件提供服务。

    我们想要的是自定义 service worker 路径和响应头的能力并且仍然得到 Sprockets 预处理,即 CoffeeScript/ES2015 到 JavaScript 的转换。

    serviceworker-rails gem 将中间件插入到您的 Rails 堆栈中,该中间件将对 /serviceworker.js(例如)的请求代理到生产中相应的指纹编译资产。在开发中,您会得到您期望的自动重新加载行为。您也可以在不同的范围内设置多个 serviceworker。

    https://github.com/rossta/serviceworker-rails

    【讨论】:

    • 轻松最好的解决方案
    【解决方案2】:

    出于安全考虑,您不能在高于执行位置的范围内注册 ServiceWorker。

    如果您确实需要模板引擎,您可以尝试从 /public 文件夹 (How do I include a JavaScript file in another JavaScript file?) 中的文件动态加载 JS 文件。目前 Firefox 中尚未实现 Service-Worker-Allowed HTTP 标头 (https://bugzilla.mozilla.org/show_bug.cgi?id=1130101)

    【讨论】:

      【解决方案3】:

      我现在也遇到了这个问题。根据我的研究,我认为 Rails 应用程序处理服务工作人员的正确方法是使用资产管道正常提供服务工作人员 javascript 文件,使用范围选项(如您所做的那样)确定服务工作人员的范围,然后使用Service-Worker-Allowed HTTP header 明确允许新范围。

      不幸的是,目前实现此方法存在几个障碍:

      1. Rails 4(显然)不允许将 HTTP 标头添加到它所服务的资产中,除了缓存控制标头。要解决这个问题,您可以添加一个 Rack 插件,如 S.O. answer 中所述,或者如果您使用的是 Nginx 等资产服务器,则可以在生产环境中通过让 Nginx 添加 HTTP 标头来解决此问题。虽然这在开发过程中没有帮助。
      2. Rails 5 确实允许将 HTTP 标头添加到资产,但 detailed in this blog post
      3. 浏览器支持 Service Worker,Service-Worker-Allowed HTTP 标头为 currently poor

      【讨论】:

      • 后面的回答 (stackoverflow.com/a/36849798/1299792) 中提到的 serviceworker-rails gem 是否解决了您上面提到的障碍?
      • @Marklar 我以前没有使用过那个 gem,但是,在 Github 上查看它,它似乎解决了所有的障碍,除了浏览器对服务工作者的支持仍然很差。如果我正在使用服务人员构建一个新的 Rails 应用程序,我肯定会检查一下。
      【解决方案4】:

      只需在根目录中执行即可。比如我放了一条路线

      get 'service-worker(.format)', to: 'core#service_worker'
      

      然后只需放入您的控制器(在我的示例中为 core_controller.rb)

      def service_worker
      end
      

      然后创建 app/views/core/service_worker.js.erb 并将您的 JS 放在那里(包括任何 )。

      【讨论】:

        【解决方案5】:

        我最近写了一篇关于如何完全使用 Webpacker 做到这一点的文章。请找到我的Progressive Web App with Rails 指南。 简而言之:

        使用 yarn add webpacker-pwa 添加 webpacker-pwa npm 包并使用以下命令编辑 environment.js

        const { resolve } = require('path');
        const { config, environment, Environment } = require('@rails/webpacker');
        const WebpackerPwa = require('webpacker-pwa');
        new WebpackerPwa(config, environment);
        module.exports = environment;
        

        这将允许您使用服务人员。请同时查看项目的 README:https://github.com/coorasse/webpacker-pwa/tree/master/npm_package

        【讨论】:

          【解决方案6】:

          将服务工作者文件保留在项目结构所施加的任何目录中,并将scope 选项设置为/,并将Service-Worker-Allowed HTTP 标头添加到服务工作者文件的响应中。

          在 ASP.Net 中,我在 web.config 文件中添加了以下内容:

          <location path="assets/serviceWorker.js">
              <system.webServer>
                  <httpProtocol>
                      <customHeaders>
                          <add name="Service-Worker-Allowed" value="/" />
                      </customHeaders>
                  </httpProtocol>
              </system.webServer>
          </location>
          

          并通过以下方式注册工人:

          navigator.serviceWorker.register('/assets/serviceWorker.js', { scope: '/' })
                  .then(function (registration)
                  {
                    console.log('Service worker registered successfully');
                  }).catch(function (e)
                  {
                    console.error('Error during service worker registration:', e);
                  });
          

          在 Firefox 和 Chrome 上测试。

          参考Service worker specification中的例子

          【讨论】:

          • 它被要求使用 Ruby on rails,而不是 ASP.net 示例
          猜你喜欢
          • 1970-01-01
          • 2018-04-18
          • 1970-01-01
          • 2011-06-22
          • 2023-01-19
          • 2014-01-05
          • 2023-04-08
          • 1970-01-01
          • 2018-01-20
          相关资源
          最近更新 更多