Регистрация Service Worker завершается неудачно с хостингом и функциями firebase - PullRequest
0 голосов
/ 01 мая 2019

Service Worker не зарегистрирован с приложением, созданным Nuxt.js (Universal), работающим на Firebase Functions.

В настоящее время я пытаюсь создать прототип веб-приложения с универсальным режимом Nuxt.js иФункции Firebase.Приложение использует сервисного работника с официальным официальным pwa-модулем nuxt для управления сеансом вошедшего в систему пользователя, чтобы клиент мог отправить запрос с заголовком авторизации на сервер, а сервер проверил бы сеанс пользователя с помощью Firebase Authentication.

Я уже пытался запустить его на локальном сервере с yarn run build и yarn 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-app, yarn run build и firebase 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)

Ожидаемое поведение - sw.js работает нормально, когда я запускаю приложениес firebase serve и firebase deploy.

1 Ответ

0 голосов
/ 02 мая 2019

Мне удалось найти решение. Возможно, я неправильно понял поведение работников сферы обслуживания.
Я просто оставляю свое решение, чтобы помочь тому, у кого такая же ситуация.

Прежде всего, я вообще не знал о js-файле сервисного работника /static/sw.js, поскольку он автоматически создается yarn run build, и все работало нормально, когда я запускаю приложение с yarn run start. Поэтому я подумал, что мне вообще не придется заботиться об этом файле.

Однако я обнаружил, что все файлы в каталоге /static должны быть помещены в каталог /public, который будет размещаться на хостинге Firebase, чтобы клиенты могли их найти и загрузить. Я предполагаю, что при использовании yarn run start файлы в каталоге /static будут размещаться на сервере dev.

Также я понял, что работники сервиса - это статические файлы 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. Хорошо работает с официальным pwa-модулем, используя importScripts.

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

Надеюсь, это кому-нибудь поможет.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...