Skip to content

Commit

Permalink
Merge branch 'create-react-app-v4' into develop
Browse files Browse the repository at this point in the history
  • Loading branch information
xMartin committed Oct 30, 2020
2 parents e3ab3f3 + a1830c0 commit c6fd6e0
Show file tree
Hide file tree
Showing 10 changed files with 5,961 additions and 4,047 deletions.
9,809 changes: 5,814 additions & 3,995 deletions package-lock.json

Large diffs are not rendered by default.

24 changes: 19 additions & 5 deletions package.json
Expand Up @@ -11,7 +11,7 @@
},
"homepage": "https://grouptabs.net/",
"dependencies": {
"@types/jest": "^24.9.1",
"@types/jest": "^26.0.15",
"@types/node": "^12.19.1",
"@types/pouchdb": "^6.4.0",
"@types/react": "^16.9.53",
Expand All @@ -22,7 +22,6 @@
"@types/uuid": "^8.3.0",
"debug": "^4.2.0",
"husky": "^4.3.0",
"jest-localstorage-mock": "^2.4.3",
"lint-staged": "^10.4.2",
"lodash.orderby": "^4.6.0",
"pouchdb": "^7.2.2",
Expand All @@ -32,15 +31,27 @@
"react": "^17.0.1",
"react-dom": "^17.0.1",
"react-redux": "^7.2.1",
"react-scripts": "3.4.4",
"react-scripts": "4.0.0",
"react-test-renderer": "^17.0.1",
"redux": "^4.0.5",
"redux-first-router": "^2.1.5",
"redux-thunk": "^2.3.0",
"reselect": "^4.0.0",
"smooth-scroll": "^16.1.3",
"typescript": "^4.0.3",
"uuid": "^8.3.1"
"uuid": "^8.3.1",
"workbox-background-sync": "^5.1.4",
"workbox-broadcast-update": "^5.1.4",
"workbox-cacheable-response": "^5.1.4",
"workbox-core": "^5.1.4",
"workbox-expiration": "^5.1.4",
"workbox-google-analytics": "^5.1.4",
"workbox-navigation-preload": "^5.1.4",
"workbox-precaching": "^5.1.4",
"workbox-range-requests": "^5.1.4",
"workbox-routing": "^5.1.4",
"workbox-strategies": "^5.1.4",
"workbox-streams": "^5.1.4"
},
"scripts": {
"start": "REACT_APP_GT_VERSION=`git describe HEAD` react-scripts start",
Expand All @@ -50,7 +61,10 @@
"eject": "react-scripts eject"
},
"eslintConfig": {
"extends": "react-app"
"extends": [
"react-app",
"react-app/jest"
]
},
"browserslist": {
"production": [
Expand Down
4 changes: 3 additions & 1 deletion src/config.ts
@@ -1,3 +1,5 @@
export default {
const config = {
backendUrl: process.env.REACT_APP_BACKEND_URL || "http://localhost:5984",
};

export default config;
2 changes: 1 addition & 1 deletion src/db/tab.ts
Expand Up @@ -14,7 +14,7 @@ type ChangesHandler = (
results: PouchDB.Core.ChangesResponseChange<Document>[]
) => void;

export default class {
export default class Tab {
private readonly db: Database;
private readonly remoteDb: Database;

Expand Down
22 changes: 11 additions & 11 deletions src/db/tabidpersistor.test.ts
Expand Up @@ -9,7 +9,7 @@ beforeEach(() => {

describe("loadTabIds", () => {
it("loads a list", () => {
localStorage.__STORE__[KEY] = JSON.stringify(["1111111", "2222222"]);
localStorage.setItem(KEY, JSON.stringify(["1111111", "2222222"]));
const tabs = loadTabIds();
expect(tabs).toEqual(["1111111", "2222222"]);
expect(console.error).not.toHaveBeenCalled();
Expand All @@ -21,14 +21,14 @@ describe("loadTabIds", () => {
});

it("returns empty list if no valid JSON", () => {
localStorage.__STORE__[KEY] = "1111111,2222222";
localStorage.setItem(KEY, "1111111,2222222");
const tabs = loadTabIds();
expect(tabs).toEqual([]);
expect(console.error).toHaveBeenCalledTimes(2);
});

it("returns empty list if stored data is not a list", () => {
localStorage.__STORE__[KEY] = '"1111111,2222222"';
localStorage.setItem(KEY, '"1111111,2222222"');
const tabs = loadTabIds();
expect(tabs).toEqual([]);
expect(console.error).toHaveBeenCalledTimes(1);
Expand All @@ -38,14 +38,14 @@ describe("loadTabIds", () => {
describe("addTabId", () => {
it("stores a name with previously empty store", () => {
addTabId("1111111");
expect(JSON.parse(localStorage.__STORE__[KEY])).toEqual(["1111111"]);
expect(JSON.parse(localStorage.getItem(KEY) || "")).toEqual(["1111111"]);
expect(console.error).not.toHaveBeenCalled();
});

it("adds a name to the existing list", () => {
localStorage.__STORE__[KEY] = JSON.stringify(["1111111", "2222222"]);
localStorage.setItem(KEY, JSON.stringify(["1111111", "2222222"]));
addTabId("3333333");
expect(JSON.parse(localStorage.__STORE__[KEY])).toEqual([
expect(JSON.parse(localStorage.getItem(KEY) || "")).toEqual([
"1111111",
"2222222",
"3333333",
Expand All @@ -54,9 +54,9 @@ describe("addTabId", () => {
});

it("does not add tab ID if it is already stored", () => {
localStorage.__STORE__[KEY] = JSON.stringify(["1111111", "2222222"]);
localStorage.setItem(KEY, JSON.stringify(["1111111", "2222222"]));
addTabId("1111111");
expect(JSON.parse(localStorage.__STORE__[KEY])).toEqual([
expect(JSON.parse(localStorage.getItem(KEY) || "")).toEqual([
"1111111",
"2222222",
]);
Expand All @@ -72,16 +72,16 @@ describe("addTabId", () => {
});

it("overwrites existing tabs if data cannot be loaded", () => {
localStorage.__STORE__[KEY] = "1111111,2222222";
localStorage.setItem(KEY, "1111111,2222222");
addTabId("3333333");
expect(JSON.parse(localStorage.__STORE__[KEY])).toEqual(["3333333"]);
expect(JSON.parse(localStorage.getItem(KEY) || "")).toEqual(["3333333"]);
expect(console.error).toHaveBeenCalledTimes(2);
});
});

describe("clearTabIds", () => {
it("clears", () => {
localStorage.__STORE__[KEY] = "1111111,2222222";
localStorage.setItem(KEY, "1111111,2222222");
clearTabIds();
expect(localStorage.getItem(KEY)).toBe(null);
expect(console.error).not.toHaveBeenCalled();
Expand Down
6 changes: 3 additions & 3 deletions src/index.tsx
Expand Up @@ -19,7 +19,7 @@ import { restoreLocation, startPersistingLocation } from "./util/standalone";
import appReducer from "./redux/reducer";
import App from "./app";
import routes from "./routes";
import * as serviceWorker from "./serviceWorker";
import * as serviceWorkerRegistration from "./serviceWorkerRegistration";
import "./index.css";

const debugSetting =
Expand Down Expand Up @@ -93,5 +93,5 @@ function hideAppLoader() {

// If you want your app to work offline and load faster, you can change
// unregister() to register() below. Note this comes with some pitfalls.
// Learn more about service workers: https://bit.ly/CRA-PWA
serviceWorker.register();
// Learn more about service workers: https://cra.link/PWA
serviceWorkerRegistration.register();
80 changes: 80 additions & 0 deletions src/service-worker.ts
@@ -0,0 +1,80 @@
/// <reference lib="webworker" />
/* eslint-disable no-restricted-globals */

// This service worker can be customized!
// See https://developers.google.com/web/tools/workbox/modules
// for the list of available Workbox modules, or add any other
// code you'd like.
// You can also remove this file if you'd prefer not to use a
// service worker, and the Workbox build step will be skipped.

import { clientsClaim } from 'workbox-core';
import { ExpirationPlugin } from 'workbox-expiration';
import { precacheAndRoute, createHandlerBoundToURL } from 'workbox-precaching';
import { registerRoute } from 'workbox-routing';
import { StaleWhileRevalidate } from 'workbox-strategies';

declare const self: ServiceWorkerGlobalScope;

clientsClaim();

// Precache all of the assets generated by your build process.
// Their URLs are injected into the manifest variable below.
// This variable must be present somewhere in your service worker file,
// even if you decide not to use precaching. See https://cra.link/PWA
precacheAndRoute(self.__WB_MANIFEST);

// Set up App Shell-style routing, so that all navigation requests
// are fulfilled with your index.html shell. Learn more at
// https://developers.google.com/web/fundamentals/architecture/app-shell
const fileExtensionRegexp = new RegExp('/[^/?]+\\.[^/]+$');
registerRoute(
// Return false to exempt requests from being fulfilled by index.html.
({ request, url }: { request: Request; url: URL }) => {
// If this isn't a navigation, skip.
if (request.mode !== 'navigate') {
return false;
}

// If this is a URL that starts with /_, skip.
if (url.pathname.startsWith('/_')) {
return false;
}

// If this looks like a URL for a resource, because it contains
// a file extension, skip.
if (url.pathname.match(fileExtensionRegexp)) {
return false;
}

// Return true to signal that we want to use the handler.
return true;
},
createHandlerBoundToURL(process.env.PUBLIC_URL + '/index.html')
);

// An example runtime caching route for requests that aren't handled by the
// precache, in this case same-origin .png requests like those from in public/
registerRoute(
// Add in any other file extensions or routing criteria as needed.
({ url }) => url.origin === self.location.origin && url.pathname.endsWith('.png'),
// Customize this strategy as needed, e.g., by changing to CacheFirst.
new StaleWhileRevalidate({
cacheName: 'images',
plugins: [
// Ensure that once this runtime cache reaches a maximum size the
// least-recently used images are removed.
new ExpirationPlugin({ maxEntries: 50 }),
],
})
);

// This allows the web app to trigger skipWaiting via
// registration.waiting.postMessage({type: 'SKIP_WAITING'})
self.addEventListener('message', (event) => {
if (event.data && event.data.type === 'SKIP_WAITING') {
self.skipWaiting();
}
});

// Any other custom service worker logic can go here.
59 changes: 29 additions & 30 deletions src/serviceWorker.ts → src/serviceWorkerRegistration.ts
Expand Up @@ -8,16 +8,14 @@
// resources are updated in the background.

// To learn more about the benefits of this model and instructions on how to
// opt-in, read https://bit.ly/CRA-PWA
// opt-in, read https://cra.link/PWA

const isLocalhost = Boolean(
window.location.hostname === "localhost" ||
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}$/
)
window.location.hostname === '[::1]' ||
// 127.0.0.0/8 are considered localhost for IPv4.
window.location.hostname.match(/^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/)
);

type Config = {
Expand All @@ -26,20 +24,17 @@ type Config = {
};

export function register(config?: Config) {
if (process.env.NODE_ENV === "production" && "serviceWorker" in navigator) {
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 as { env: { [key: string]: string } }).env.PUBLIC_URL,
window.location.href
);
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", () => {
window.addEventListener('load', () => {
const swUrl = `${process.env.PUBLIC_URL}/service-worker.js`;

if (isLocalhost) {
Expand All @@ -50,8 +45,8 @@ export function register(config?: Config) {
// 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 https://bit.ly/CRA-PWA"
'This web app is being served cache-first by a service ' +
'worker. To learn more, visit https://cra.link/PWA'
);
});
} else {
Expand All @@ -72,14 +67,14 @@ function registerValidSW(swUrl: string, config?: Config) {
return;
}
installingWorker.onstatechange = () => {
if (installingWorker.state === "installed") {
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 https://bit.ly/CRA-PWA."
'New content is available and will be used when all ' +
'tabs for this page are closed. See https://cra.link/PWA.'
);

// Execute callback
Expand All @@ -90,7 +85,7 @@ function registerValidSW(swUrl: string, config?: Config) {
// 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.");
console.log('Content is cached for offline use.');

// Execute callback
if (config && config.onSuccess) {
Expand All @@ -102,19 +97,21 @@ function registerValidSW(swUrl: string, config?: Config) {
};
})
.catch((error) => {
console.error("Error during service worker registration:", error);
console.error('Error during service worker registration:', error);
});
}

function checkValidServiceWorker(swUrl: string, config?: Config) {
// Check if the service worker can be found. If it can't reload the page.
fetch(swUrl)
fetch(swUrl, {
headers: { 'Service-Worker': 'script' },
})
.then((response) => {
// Ensure service worker exists, and that we really are getting a JS file.
const contentType = response.headers.get("content-type");
const contentType = response.headers.get('content-type');
if (
response.status === 404 ||
(contentType != null && contentType.indexOf("javascript") === -1)
(contentType != null && contentType.indexOf('javascript') === -1)
) {
// No service worker found. Probably a different app. Reload the page.
navigator.serviceWorker.ready.then((registration) => {
Expand All @@ -128,16 +125,18 @@ function checkValidServiceWorker(swUrl: string, config?: Config) {
}
})
.catch(() => {
console.log(
"No internet connection found. App is running in offline mode."
);
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();
});
if ('serviceWorker' in navigator) {
navigator.serviceWorker.ready
.then((registration) => {
registration.unregister();
})
.catch((error) => {
console.error(error.message);
});
}
}
1 change: 0 additions & 1 deletion src/setupTests.ts

This file was deleted.

1 change: 1 addition & 0 deletions tsconfig.json
Expand Up @@ -12,6 +12,7 @@
"allowSyntheticDefaultImports": true,
"strict": true,
"forceConsistentCasingInFileNames": true,
"noFallthroughCasesInSwitch": true,
"module": "esnext",
"moduleResolution": "node",
"resolveJsonModule": true,
Expand Down

0 comments on commit c6fd6e0

Please sign in to comment.