reactjs - I want my CRA PWA to fetch from cache only if there is no internet. Basically I want it to be a Network First approach
问题描述
Attaching my service worker files and package.json. I think I'm missing a step here, otherwise this should have worked. I don't know what else to add here. This should have worked. I even keep clearing all data from my browser, so that the service workers keep updating. But when I open the website, it still shows me the last version of the website, not the latest version.
sw-custom.js
if (typeof importScripts === "function") {
importScripts(
"https://storage.googleapis.com/workbox-cdn/releases/5.0.0/workbox-sw.js"
);
/* global workbox */
if (workbox) {
console.log("Workbox is loaded");
workbox.core.skipWaiting();
/* injection point for manifest files. */
workbox.precaching.precacheAndRoute([]);
/* custom cache rules */
workbox.routing.registerRoute(
new workbox.routing.NavigationRoute(new workbox.strategies.NetworkOnly())
);
} else {
console.log("Workbox could not be loaded. No Offline support");
}
}
sw-build.js
const workboxBuild = require("workbox-build");
const buildSW = () => {
// The build is expected to fail if the
// sw install rules couldn't be generated.
// Add a catch block to handle this scenario.
return workboxBuild
.injectManifest({
swSrc: "src/sw-custom.js", // custom sw rule
swDest: "build/sw.js", // sw output file (auto-generated
globDirectory: "build",
globPatterns: ["**/*.{js,css,html,png,svg}"],
maximumFileSizeToCacheInBytes: 10 * 1024 * 1024,
})
.then(({ count, size, warnings }) => {
warnings.forEach(console.warn);
console.info(`${count} files will be precached,
totaling ${size / (1024 * 1024)} MBs.`);
});
};
buildSW();
serviceWorker.js
// This optional code is used to register a service worker.
// register() is not called by default.
import { ACTIONS } from "./utils/actions";
import { store } from "./utils/configureStore";
// This lets the app load faster on subsequent visits in production, and gives
// it offline capabilities. However, it also means that developers (and users)
// will only see deployed updates on subsequent visits to a page, after all the
// existing tabs open on the page have been closed, since previously cached
// resources are updated in the background.
// To learn more about the benefits of this model and instructions on how to
// opt-in, read -PWA
const isLocalhost = Boolean(
window.location.hostname === "localhost" ||
// [::1] is the IPv6 localhost address.
window.location.hostname === "[::1]" ||
// 127.0.0.1/8 is considered localhost for IPv4.
window.location.hostname.match(
/^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/
)
);
export function register(config) {
if (process.env.NODE_ENV === "production" && "serviceWorker" in navigator) {
// The URL constructor is available in all browsers that support SW.
const publicUrl = new URL(process.env.PUBLIC_URL, window.location.href);
if (publicUrl.origin !== window.location.origin) {
// Our service worker won't work if PUBLIC_URL is on a different origin
// from what our page is served on. This might happen if a CDN is used to
// serve assets; see https://github.com/facebook/create-react-app/issues/2374
return;
}
window.addEventListener("load", () => {
// const swUrl = `${process.env.PUBLIC_URL}/service-worker.js`;
const swUrl = `${process.env.PUBLIC_URL}/sw.js`;
if (isLocalhost) {
// This is running on localhost. Let's check if a service worker still exists or not.
checkValidServiceWorker(swUrl, config);
// Add some additional logging to localhost, pointing developers to the
// service worker/PWA documentation.
navigator.serviceWorker.ready.then(() => {
console.log(
"This web app is being served cache-first by a service " +
"worker. To learn more, visit -PWA"
);
});
} else {
// Is not localhost. Just register service worker
registerValidSW(swUrl, config);
}
});
}
}
function registerValidSW(swUrl, config) {
navigator.serviceWorker
.register(swUrl)
.then((registration) => {
registration.onupdatefound = () => {
const installingWorker = registration.installing;
if (installingWorker == null) {
return;
}
installingWorker.onstatechange = () => {
if (installingWorker.state === "installed") {
if (navigator.serviceWorker.controller) {
// At this point, the updated precached content has been fetched,
// but the previous service worker will still serve the older
// content until all client tabs are closed.
console.log(
"New content is available and will be used when all " +
"tabs for this page are closed. See -PWA."
);
// Execute callback
if (config && config.onUpdate) {
config.onUpdate(registration);
}
} else {
// At this point, everything has been precached.
// It's the perfect time to display a
// "Content is cached for offline use." message.
console.log("Content is cached for offline use.");
// Execute callback
if (config && config.onSuccess) {
config.onSuccess(registration);
}
}
}
};
};
})
.catch((error) => {
console.error("Error during service worker registration:", error);
});
}
function checkValidServiceWorker(swUrl, config) {
// Check if the service worker can be found. If it can't reload the page.
fetch(swUrl)
.then((response) => {
// Ensure service worker exists, and that we really are getting a JS file.
const contentType = response.headers.get("content-type");
if (
response.status === 404 ||
(contentType != null && contentType.indexOf("javascript") === -1)
) {
// No service worker found. Probably a different app. Reload the page.
navigator.serviceWorker.ready.then((registration) => {
registration.unregister().then(() => {
window.location.reload();
});
});
} else {
// Service worker found. Proceed as normal.
registerValidSW(swUrl, config);
}
})
.catch(() => {
console.log(
"No internet connection found. App is running in offline mode."
);
});
}
export function unregister() {
if ("serviceWorker" in navigator) {
navigator.serviceWorker.ready.then((registration) => {
registration.unregister();
});
}
}
register();
package.json
{
"name": "admin",
"version": "0.1.0",
"private": true,
"dependencies": {
"@date-io/date-fns": "^1.3.9",
"@date-io/moment": "^2.4.0",
"@devexpress/dx-react-chart": "^2.6.2",
"@devexpress/dx-react-chart-bootstrap4": "^2.6.2",
"@devexpress/dx-react-chart-material-ui": "^2.6.2",
"@devexpress/dx-react-core": "^2.6.2",
"@devexpress/dx-react-scheduler": "^2.5.0",
"@devexpress/dx-react-scheduler-material-ui": "^2.5.0",
"@material-ui/core": "^4.3.1",
"@material-ui/icons": "^4.2.1",
"@material-ui/lab": "^4.0.0-alpha.24",
"@material-ui/pickers": "^3.2.4",
"@material-ui/styles": "^4.3.0",
"@uppy/core": "^1.2.0",
"@uppy/react": "^1.2.0",
"antd": "^3.22.2",
"antd-mobile": "^2.3.1",
"axios": "^0.19.2",
"braft-editor": "^2.3.9",
"clsx": "^1.1.0",
"connected-react-router": "^6.5.2",
"date-fns": "^2.0.0-beta.5",
"firebase": "^6.3.4",
"localforage": "^1.7.3",
"lodash": "^4.17.15",
"material-table": "^1.57.2",
"moment": "^2.24.0",
"notistack": "^0.8.9",
"qs": "^6.9.3",
"react": "^16.8.6",
"react-dom": "^16.8.6",
"react-firebaseui": "^4.0.0",
"react-geocode": "^0.2.1",
"react-geosuggest": "^2.13.0",
"react-google-maps": "^9.4.5",
"react-helmet": "^5.2.1",
"react-mentions": "^3.3.1",
"react-redux": "^7.1.0",
"react-router-dom": "^5.0.1",
"react-scripts": "3.0.1",
"react-virtualized": "^9.21.2",
"redux": "^4.0.4",
"redux-persist": "^5.10.0",
"redux-thunk": "^2.3.0",
"styled-components": "^4.3.2",
"tabletop": "^1.6.2",
"uppy": "^1.3.0",
"uuid": "^3.3.2"
},
"devDependencies": {
"babel-plugin-import": "^1.12.0",
"customize-cra": "^0.5.0",
"husky": "^3.0.2",
"jest-dom": "^4.0.0",
"jest-enzyme": "^7.0.2",
"less": "^3.10.2",
"less-loader": "^5.0.0",
"lint-staged": "^9.2.1",
"prettier": "^1.18.2",
"react-app-rewired": "^2.1.3",
"react-testing-library": "^8.0.1",
"redux-devtools-extension": "^2.13.8",
"redux-logger": "^3.0.6",
"source-map-explorer": "^2.0.1"
},
"scripts": {
"build-sw": "node ./src/sw-build.js",
"clean-cra-sw": "rm -f build/precache-manifest.*.js && rm -f build/service-worker.js",
"analyze": "source-map-explorer 'build/static/js/*.js'",
"start": "PORT=3002 react-app-rewired start",
"build": "react-app-rewired build && npm run build-sw && npm run clean-cra-sw",
"test": "react-app-rewired test",
"eject": "react-scripts eject"
},
"eslintConfig": {
"extends": "react-app"
},
"browserslist": {
"production": [
">0.2%",
"not dead",
"not op_mini all"
],
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
]
}
}
Can someone please tell me if I'm missing something here?
解决方案
推荐阅读
- maven - IntelliJ 说:
在 maven-jaxws-tools-plugin 中不允许 - sql - 不明白语法错误在哪里?PostgreSQL 11
- rabbitmq - RabbitMQ 发布者确认订单
- android - How to fix permission issue with opencv in native code for android platform
- python - 如何在 Watson Studio 中使用 pandas read_csv 读取压缩的 csv 文件?
- react-native - How to create Close Button in React Navigation?
- javascript - 在 dojo 中拦截响应以读取 cookie
- html - Cant change length of a carousel in bootstrap
- xamarin.android - 我在哪里可以下载带有 Android 包的旧 Xamarin Studios?
- php - 将 2 个字段连接到另一个表中