Firebase托管和功能导致Service Worker注册失败

时间:2019-05-01 15:30:01

标签: firebase nuxt.js workbox

Service Worker未向运行在Firebase Functions上的Nuxt.js(通用)构建的应用程序注册。

我目前正在尝试使用Nuxt.js通用模式和Firebase函数构建原型Web应用程序。 该应用程序使用带有nuxt官方pwa模块的service worker来管理已登录用户的会话,以便客户端可以将带有授权标头的请求发送到服务器,服务器将通过Firebase身份验证来验证用户会话。

我已经尝试使用yarn run buildyarn run start在本地服务器上运行它,并确保服务工作者已经正确注册并可以正常工作。 但是,当我尝试使用firebase serve检查相同的操作时,在浏览器上收到以下错误。

A bad HTTP response code (404) was received when fetching the script.
Failed to load resource: net::ERR_INVALID_RESPONSE
dcbac67bb39a765db27a.js:1 Service worker registration failed: TypeError: Failed to register a ServiceWorker: A bad HTTP response code (404) was received when fetching the script.

我还发现服务工作者没有将会话数据发送到服务器。当我使用firebase deploy将源部署到生产中时,完全可以复制相同的东西。

当我用yarn create nuxt-appyarn run buildfirebase serve彻底清理项目时,甚至会发生这种情况。 “ sw.js”文件指示Chrome开发者工具上的状态失败。

我不确定是否担心,但是我的Firebase是否在Spark计划上。

我的项目树。

.
├── firebase.json
├── firestore.indexes.json
├── firestore.rules
├── functions
│   ├── index.js
│   ├── nuxt
│   │   ├── App.js
│   │   ├── axios.js
│   │   ├── client.js
│   │   ├── components
│   │   ├── dist
│   │   ├── empty.js
│   │   ├── index.js
│   │   ├── loading.html
│   │   ├── middleware.js
│   │   ├── router.js
│   │   ├── server.js
│   │   ├── store.js
│   │   ├── sw.plugin.js
│   │   ├── sw.template.js
│   │   ├── utils.js
│   │   └── views
│   ├── package-lock.json
│   ├── package.json
│   └── yarn.lock
├── public
└── src
    ├── assets
    ├── components
    ├── jest.config.js
    ├── layouts
    ├── middleware
    ├── nuxt.config.js
    ├── package.json
    ├── pages
    ├── plugins
    ├── server
    ├── static
    │   └── sw.js
    ├── store
    └── test
    └── yarn.lock

src / static / sw.js

importScripts('/_nuxt/workbox.4c4f5ca6.js')

workbox.precaching.precacheAndRoute([
  {
    "url": "/_nuxt/021e1640b53136b75c48.js",
    "revision": "2753e747206d803c793b59a324c1931b"
  },
  {
    "url": "/_nuxt/03c9e340d8692d1403a9.js",
    "revision": "2b882d73d20a0b2cfd318e9e05d3496e"
  },
  {
    "url": "/_nuxt/78bddfa6b6a4919b78d6.js",
    "revision": "70312f6623089e3b4aa6454120c1e177"
  },
  {
    "url": "/_nuxt/85c817abccdd40162004.js",
    "revision": "45448f8709d01af59bb125a1d06be23a"
  },
  {
    "url": "/_nuxt/8654a518d0f3e326c9a6.js",
    "revision": "a42426f5e7b458acc6fdf0e9e48c7d35"
  },
  {
    "url": "/_nuxt/95b421159066eff9e318.js",
    "revision": "efd1643042f804defa7212979867558a"
  },
  {
    "url": "/_nuxt/9b487bf2df1190b68565.js",
    "revision": "78837d0e624deccc85761b44f9ede9be"
  },
  {
    "url": "/_nuxt/ce59381752309c170d41.js",
    "revision": "d3e50bf27891c4efa6dff5076a0772a6"
  },
  {
    "url": "/_nuxt/d8fa6ae5ca14331879f6.js",
    "revision": "5da6698c9359df803243ecc44519b610"
  },
  {
    "url": "/_nuxt/dcbac67bb39a765db27a.js",
    "revision": "9505aa84ddb2a70b826d324433daff36"
  },
  {
    "url": "/_nuxt/dee89eef613849499c7f.js",
    "revision": "43117ed819efe3d00c963dd655894d5f"
  }
], {
  "cacheId": "justtest",
  "directoryIndex": "/",
  "cleanUrls": false
})

workbox.clientsClaim()
workbox.skipWaiting()

workbox.routing.registerRoute(new RegExp('/_nuxt/.*'), workbox.strategies.cacheFirst({}), 'GET')

workbox.routing.registerRoute(new RegExp('/.*'), workbox.strategies.networkFirst({}), 'GET')

functions / index.js

const functions = require("firebase-functions")
const { Nuxt } = require("nuxt")
const express = require("express")
const app = express()

const nuxt = new Nuxt({ buildDir: "nuxt", dev: false })

function handleRequest(req, res) {
  res.setHeader('Cache-Control', 'private')
  return new Promise((resolve, reject) => {
    nuxt.render(req, res, promise => {
      promise.then(resolve).catch(reject)
    })
  })
}

app.use(handleRequest)

exports.ssr = functions.https.onRequest(app)

预期的行为是,当我使用firebase servefirebase deploy运行应用程序时,sw.js可以正常工作。

2 个答案:

答案 0 :(得分:0)

我设法找到了解决方案。我可能误解了服务人员的行为。
我只是离开我的解决方案,以便可以帮助遇到同样情况的人。

首先,我根本不了解服务工作者js文件/static/sw.js,因为它是由yarn run build自动创建的,当我使用yarn run start运行应用程序时,一切工作正常。因此,我认为我根本不必关心该文件。

但是我发现/static目录中的所有文件都必须放在/public目录中,该目录将由firebase托管,以便客户端可以找到并下载它们。我猜想当我使用yarn run start时,/static目录中的文件将由开发服务器托管。

我还意识到服务工作者是静态的javascript文件,它们必须由Firebase托管而不是由Firebase函数托管。我曾经尝试将它们放在dist/client中,但这没有任何意义。它必须放置在/public目录中。

我终于使它与以下项目树一起使用。运行yarn run build时,我将/src/static中的所有内容复制到/public中,以使用Firebase托管对其进行托管。

.
├── firebase.json
├── functions
│   ├── index.js
│   ├── nuxt
│   │   ├── App.js
│   │   ├── axios.js
│   │   ├── client.js
│   │   ├── components
│   │   ├── dist
│   │   ├── empty.js
│   │   ├── index.js
│   │   ├── loading.html
│   │   ├── middleware.js
│   │   ├── router.js
│   │   ├── server.js
│   │   ├── store.js
│   │   ├── sw.plugin.js
│   │   ├── sw.template.js
│   │   ├── utils.js
│   │   └── views
│   ├── package-lock.json
│   ├── package.json
│   └── yarn.lock
├── public
│   ├── favicon.ico
│   ├── sw-firebase-auth.js
│   └── sw.js
└── src
    ├── assets
    ├── components
    ├── layouts
    ├── middleware
    ├── nuxt.config.js
    ├── package.json
    ├── pages
    ├── plugins
    ├── server
    ├── static
    │   ├── favicon.ico
    │   ├── sw-firebase-auth.js
    │   └── sw.js
    ├── store
    └── yarn.lock

这是我的sw-firebase-auth.js。 (我使用Browserify编译了此脚本,以使其正常工作。)

var firebase = require('firebase')

// Initialize the Firebase app in the service worker script.
firebase.initializeApp({
  apiKey: '*************',
  authDomain: '*************',
  databaseURL: '*************',
  projectId: '*************',
  storageBucket: '*************',
  messagingSenderId: '*************'
})

/**
 * Returns a promise that resolves with an ID token if available.
 * @return {!Promise<?string>} The promise that resolves with an ID token if
 *     available. Otherwise, the promise resolves with null.
 */
const getIdToken = () => {
  return new Promise((resolve) => {
    const unsubscribe = firebase.auth().onAuthStateChanged((user) => {
      unsubscribe();
      if (user) {
        user.getIdToken().then((idToken) => {
          resolve(idToken)
        }, () => {
          resolve(null)
        });
      } else {
        resolve(null)
      }
    })
  })
}

const getOriginFromUrl = (url) => {
  const pathArray = url.split('/');
  const protocol = pathArray[0];
  const host = pathArray[2];
  return protocol + '//' + host;
};

self.addEventListener('fetch', (event) => {
  const requestProcessor = (idToken) => {
    let req = event.request;
    if (self.location.origin == getOriginFromUrl(event.request.url) &&
        (self.location.protocol == 'https:' ||
         self.location.hostname == 'localhost') &&
        idToken) {
      const headers = new Headers();
      for (let entry of req.headers.entries()) {
        headers.append(entry[0], entry[1]);
      }
      headers.append('Authorization', 'Bearer ' + idToken);
      try {
        req = new Request(req.url, {
          method: req.method,
          headers: headers,
          mode: 'same-origin',
          credentials: req.credentials,
          cache: req.cache,
          redirect: req.redirect,
          referrer: req.referrer,
          body: req.body,
          bodyUsed: req.bodyUsed,
          context: req.context
        });
      } catch (e) {
        console.log(e)
      }
    }
    return fetch(req);
  };
  event.respondWith(getIdToken().then(requestProcessor, requestProcessor));
});

self.addEventListener('activate', event => {
  event.waitUntil(clients.claim());
})

这也是nuxt.conf.js中的工作箱配置。它与使用importScripts的官方pwa-module配合良好。

  workbox: {
    importScripts: [
      'sw-firebase-auth.js'
    ]
  }

我希望这会对某人有所帮助。

答案 1 :(得分:0)

2020年6月的Nuxt.js资深开发人员

如果要通过SSR部署Nuxt.js 2.12.2项目,则项目目录中可能有.nuxt文件夹。将其删除,并根据需要从nuxt.config.js配置Workbox,然后运行nuxt buildnpm run buildyarn build

如果它在本地计算机上可用,则可以尝试清除服务器上的缓存,以确保所有旧的.nuxt文件夹都已消失并重新部署项目。

希望这对您有帮助