* fix "dev:build" watch mode
* remove cross-env * append build hash to service worker cache names for easy purge
This commit is contained in:
parent
836b1d8d1b
commit
1e9b7a8aa2
@ -7,7 +7,7 @@ import handleNotificationClick from "./service-worker/notification-click";
|
|||||||
import handleFetch from "./service-worker/fetch";
|
import handleFetch from "./service-worker/fetch";
|
||||||
import handleMessage from "./service-worker/message";
|
import handleMessage from "./service-worker/message";
|
||||||
|
|
||||||
declare let self: ServiceWorkerGlobalScope;
|
declare const self: ServiceWorkerGlobalScope;
|
||||||
|
|
||||||
self.addEventListener("install", (event) => {
|
self.addEventListener("install", (event) => {
|
||||||
event.waitUntil(handleInstall(event).then(() => self.skipWaiting()));
|
event.waitUntil(handleInstall(event).then(() => self.skipWaiting()));
|
||||||
|
@ -53,7 +53,6 @@ export default function ServiceWorkerUpdateNotifier() {
|
|||||||
aria-label="An updated version of the app is available. Reload to get the latest version."
|
aria-label="An updated version of the app is available. Reload to get the latest version."
|
||||||
/>
|
/>
|
||||||
</button>
|
</button>
|
||||||
;
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { deleteCaches } from "./cache-utils";
|
import { deleteCaches } from "./cache-utils";
|
||||||
|
|
||||||
declare let self: ServiceWorkerGlobalScope;
|
declare const self: ServiceWorkerGlobalScope;
|
||||||
|
|
||||||
export default async function handleActivate(event: ExtendableEvent) {
|
export default async function handleActivate(event: ExtendableEvent) {
|
||||||
console.debug("Service worker activated");
|
console.debug("Service worker activated");
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
import { json } from "@remix-run/server-runtime";
|
import { json } from "@remix-run/server-runtime";
|
||||||
|
|
||||||
export const ASSET_CACHE = "asset-cache";
|
declare const ASSET_CACHE: string;
|
||||||
export const DATA_CACHE = "data-cache";
|
declare const DATA_CACHE: string;
|
||||||
export const DOCUMENT_CACHE = "document-cache";
|
declare const DOCUMENT_CACHE: string;
|
||||||
|
|
||||||
export function isAssetRequest(request: Request) {
|
export function isAssetRequest(request: Request) {
|
||||||
return ["font", "image", "script", "style"].includes(request.destination);
|
return ["font", "image", "script", "style"].includes(request.destination);
|
||||||
@ -17,7 +17,7 @@ export function isDocumentGetRequest(request: Request) {
|
|||||||
return request.method.toLowerCase() === "get" && request.mode === "navigate";
|
return request.method.toLowerCase() === "get" && request.mode === "navigate";
|
||||||
}
|
}
|
||||||
|
|
||||||
export function cacheAsset(event: FetchEvent): Promise<Response> {
|
export function fetchAsset(event: FetchEvent): Promise<Response> {
|
||||||
// stale-while-revalidate
|
// stale-while-revalidate
|
||||||
const url = new URL(event.request.url);
|
const url = new URL(event.request.url);
|
||||||
return caches
|
return caches
|
||||||
@ -53,7 +53,7 @@ export function cacheAsset(event: FetchEvent): Promise<Response> {
|
|||||||
// stores the timestamp for when each URL's cached response has been revalidated
|
// stores the timestamp for when each URL's cached response has been revalidated
|
||||||
const lastTimeRevalidated: Record<string, number> = {};
|
const lastTimeRevalidated: Record<string, number> = {};
|
||||||
|
|
||||||
export function cacheLoaderData(event: FetchEvent): Promise<Response> {
|
export function fetchLoaderData(event: FetchEvent): Promise<Response> {
|
||||||
const url = new URL(event.request.url);
|
const url = new URL(event.request.url);
|
||||||
const path = url.pathname + url.search;
|
const path = url.pathname + url.search;
|
||||||
|
|
||||||
@ -145,7 +145,7 @@ async function areResponsesEqual(a: Response, b: Response): Promise<boolean> {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function cacheDocument(event: FetchEvent): Promise<Response> {
|
export function fetchDocument(event: FetchEvent): Promise<Response> {
|
||||||
// network-first
|
// network-first
|
||||||
const url = new URL(event.request.url);
|
const url = new URL(event.request.url);
|
||||||
console.debug("Serving document from network", url.pathname);
|
console.debug("Serving document from network", url.pathname);
|
||||||
@ -170,6 +170,7 @@ export function cacheDocument(event: FetchEvent): Promise<Response> {
|
|||||||
|
|
||||||
export async function deleteCaches() {
|
export async function deleteCaches() {
|
||||||
const allCaches = await caches.keys();
|
const allCaches = await caches.keys();
|
||||||
await Promise.all(allCaches.map((cacheName) => caches.delete(cacheName)));
|
const cachesToDelete = allCaches.filter((cacheName) => cacheName !== ASSET_CACHE);
|
||||||
|
await Promise.all(cachesToDelete.map((cacheName) => caches.delete(cacheName)));
|
||||||
console.debug("Caches deleted");
|
console.debug("Caches deleted");
|
||||||
}
|
}
|
||||||
|
@ -1,25 +1,25 @@
|
|||||||
import {
|
import {
|
||||||
cacheAsset,
|
fetchAsset,
|
||||||
cacheDocument,
|
fetchDocument,
|
||||||
cacheLoaderData,
|
fetchLoaderData,
|
||||||
isAssetRequest,
|
isAssetRequest,
|
||||||
isDocumentGetRequest,
|
isDocumentGetRequest,
|
||||||
isLoaderRequest,
|
isLoaderRequest,
|
||||||
} from "./cache-utils";
|
} from "./cache-utils";
|
||||||
|
|
||||||
declare let self: ServiceWorkerGlobalScope;
|
declare const self: ServiceWorkerGlobalScope;
|
||||||
|
|
||||||
export default async function handleFetch(event: FetchEvent) {
|
export default async function handleFetch(event: FetchEvent) {
|
||||||
if (isAssetRequest(event.request)) {
|
if (isAssetRequest(event.request)) {
|
||||||
return cacheAsset(event);
|
return fetchAsset(event);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isLoaderRequest(event.request)) {
|
if (isLoaderRequest(event.request)) {
|
||||||
return cacheLoaderData(event);
|
return fetchLoaderData(event);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isDocumentGetRequest(event.request)) {
|
if (isDocumentGetRequest(event.request)) {
|
||||||
return cacheDocument(event);
|
return fetchDocument(event);
|
||||||
}
|
}
|
||||||
|
|
||||||
return fetch(event.request);
|
return fetch(event.request);
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
declare let self: ServiceWorkerGlobalScope;
|
declare const self: ServiceWorkerGlobalScope;
|
||||||
|
|
||||||
export default async function handleInstall(event: ExtendableEvent) {
|
export default async function handleInstall(event: ExtendableEvent) {
|
||||||
console.debug("Service worker installed");
|
console.debug("Service worker installed");
|
||||||
|
@ -1,8 +1,7 @@
|
|||||||
import type { AssetsManifest } from "@remix-run/react/entry";
|
import type { AssetsManifest } from "@remix-run/react/entry";
|
||||||
|
|
||||||
import { ASSET_CACHE } from "./cache-utils";
|
declare const ASSET_CACHE: string;
|
||||||
|
declare const self: ServiceWorkerGlobalScope;
|
||||||
declare let self: ServiceWorkerGlobalScope;
|
|
||||||
|
|
||||||
export default async function handleMessage(event: ExtendableMessageEvent) {
|
export default async function handleMessage(event: ExtendableMessageEvent) {
|
||||||
if (event.data.type === "SYNC_REMIX_MANIFEST") {
|
if (event.data.type === "SYNC_REMIX_MANIFEST") {
|
||||||
@ -13,32 +12,31 @@ export default async function handleMessage(event: ExtendableMessageEvent) {
|
|||||||
async function handleSyncRemixManifest(event: ExtendableMessageEvent) {
|
async function handleSyncRemixManifest(event: ExtendableMessageEvent) {
|
||||||
console.debug("Caching routes modules");
|
console.debug("Caching routes modules");
|
||||||
|
|
||||||
await cacheStaticAssets(event.data.manifest);
|
const manifest: AssetsManifest = event.data.manifest;
|
||||||
}
|
|
||||||
|
|
||||||
async function cacheStaticAssets(manifest: AssetsManifest) {
|
|
||||||
const cachePromises: Map<string, Promise<void>> = new Map();
|
|
||||||
const assetCache = await caches.open(ASSET_CACHE);
|
|
||||||
const routes = [...Object.values(manifest.routes), manifest.entry];
|
const routes = [...Object.values(manifest.routes), manifest.entry];
|
||||||
|
const assetsToCache: string[] = [];
|
||||||
for (const route of routes) {
|
for (const route of routes) {
|
||||||
if (!cachePromises.has(route.module)) {
|
assetsToCache.push(route.module);
|
||||||
cachePromises.set(route.module, cacheAsset(route.module));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (route.imports) {
|
if (route.imports) {
|
||||||
for (const assetUrl of route.imports) {
|
assetsToCache.push(...route.imports);
|
||||||
if (!cachePromises.has(assetUrl)) {
|
|
||||||
cachePromises.set(assetUrl, cacheAsset(assetUrl));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
await purgeStaticAssets(assetsToCache);
|
||||||
|
await cacheStaticAssets(assetsToCache);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function cacheStaticAssets(assetsToCache: string[]) {
|
||||||
|
const cachePromises: Map<string, Promise<void>> = new Map();
|
||||||
|
const assetCache = await caches.open(ASSET_CACHE);
|
||||||
|
|
||||||
|
assetsToCache.forEach((assetUrl) => cachePromises.set(assetUrl, cacheAsset(assetUrl)));
|
||||||
await Promise.all(cachePromises.values());
|
await Promise.all(cachePromises.values());
|
||||||
|
|
||||||
async function cacheAsset(assetUrl: string) {
|
async function cacheAsset(assetUrl: string) {
|
||||||
if (await assetCache.match(assetUrl)) {
|
if (await assetCache.match(assetUrl)) {
|
||||||
|
// no need to update the asset, it has a unique hash in its name
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -48,3 +46,14 @@ async function cacheStaticAssets(manifest: AssetsManifest) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function purgeStaticAssets(assetsToCache: string[]) {
|
||||||
|
const assetCache = await caches.open(ASSET_CACHE);
|
||||||
|
const cachedAssets = await assetCache.keys();
|
||||||
|
const cachesToDelete = cachedAssets.filter((asset) => !assetsToCache.includes(new URL(asset.url).pathname));
|
||||||
|
console.log(
|
||||||
|
"cachesToDelete",
|
||||||
|
cachesToDelete.map((c) => new URL(c.url).pathname),
|
||||||
|
);
|
||||||
|
await Promise.all(cachesToDelete.map((asset) => assetCache.delete(asset)));
|
||||||
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { removeBadge } from "~/utils/pwa.client";
|
import { removeBadge } from "~/utils/pwa.client";
|
||||||
|
|
||||||
declare let self: ServiceWorkerGlobalScope;
|
declare const self: ServiceWorkerGlobalScope;
|
||||||
|
|
||||||
// noinspection TypeScriptUnresolvedVariable
|
// noinspection TypeScriptUnresolvedVariable
|
||||||
export default async function handleNotificationClick(event: NotificationEvent) {
|
export default async function handleNotificationClick(event: NotificationEvent) {
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import type { NotificationPayload } from "~/utils/web-push.server";
|
import type { NotificationPayload } from "~/utils/web-push.server";
|
||||||
import { addBadge } from "~/utils/pwa.client";
|
import { addBadge } from "~/utils/pwa.client";
|
||||||
|
|
||||||
declare let self: ServiceWorkerGlobalScope;
|
declare const self: ServiceWorkerGlobalScope;
|
||||||
|
|
||||||
const defaultOptions: NotificationOptions = {
|
const defaultOptions: NotificationOptions = {
|
||||||
icon: "/icons/android-chrome-192x192.png",
|
icon: "/icons/android-chrome-192x192.png",
|
||||||
|
41
package-lock.json
generated
41
package-lock.json
generated
@ -23,7 +23,6 @@
|
|||||||
"bullmq": "1.85.1",
|
"bullmq": "1.85.1",
|
||||||
"clsx": "1.1.1",
|
"clsx": "1.1.1",
|
||||||
"compression": "1.7.4",
|
"compression": "1.7.4",
|
||||||
"cross-env": "7.0.3",
|
|
||||||
"express": "4.18.1",
|
"express": "4.18.1",
|
||||||
"ioredis": "5.0.6",
|
"ioredis": "5.0.6",
|
||||||
"isbot": "3.5.0",
|
"isbot": "3.5.0",
|
||||||
@ -75,6 +74,7 @@
|
|||||||
"esbuild": "0.14.42",
|
"esbuild": "0.14.42",
|
||||||
"esbuild-node-externals": "1.4.1",
|
"esbuild-node-externals": "1.4.1",
|
||||||
"eslint": "8.16.0",
|
"eslint": "8.16.0",
|
||||||
|
"glob": "7.2.3",
|
||||||
"happy-dom": "5.0.0",
|
"happy-dom": "5.0.0",
|
||||||
"husky": "7.0.4",
|
"husky": "7.0.4",
|
||||||
"lint-staged": "13.0.0",
|
"lint-staged": "13.0.0",
|
||||||
@ -7298,27 +7298,11 @@
|
|||||||
"node": "*"
|
"node": "*"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/cross-env": {
|
|
||||||
"version": "7.0.3",
|
|
||||||
"resolved": "https://registry.npmjs.org/cross-env/-/cross-env-7.0.3.tgz",
|
|
||||||
"integrity": "sha512-+/HKd6EgcQCJGh2PSjZuUitQBQynKor4wrFbRg4DtAgS1aWO+gU52xpH7M9ScGgXSYmAVS9bIJ8EzuaGw0oNAw==",
|
|
||||||
"dependencies": {
|
|
||||||
"cross-spawn": "^7.0.1"
|
|
||||||
},
|
|
||||||
"bin": {
|
|
||||||
"cross-env": "src/bin/cross-env.js",
|
|
||||||
"cross-env-shell": "src/bin/cross-env-shell.js"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">=10.14",
|
|
||||||
"npm": ">=6",
|
|
||||||
"yarn": ">=1"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/cross-spawn": {
|
"node_modules/cross-spawn": {
|
||||||
"version": "7.0.3",
|
"version": "7.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz",
|
||||||
"integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==",
|
"integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==",
|
||||||
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"path-key": "^3.1.0",
|
"path-key": "^3.1.0",
|
||||||
"shebang-command": "^2.0.0",
|
"shebang-command": "^2.0.0",
|
||||||
@ -16194,6 +16178,7 @@
|
|||||||
"version": "3.1.1",
|
"version": "3.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
|
||||||
"integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==",
|
"integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==",
|
||||||
|
"dev": true,
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=8"
|
"node": ">=8"
|
||||||
}
|
}
|
||||||
@ -19450,6 +19435,7 @@
|
|||||||
"version": "2.0.0",
|
"version": "2.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
|
||||||
"integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==",
|
"integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==",
|
||||||
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"shebang-regex": "^3.0.0"
|
"shebang-regex": "^3.0.0"
|
||||||
},
|
},
|
||||||
@ -19461,6 +19447,7 @@
|
|||||||
"version": "3.0.0",
|
"version": "3.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz",
|
||||||
"integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==",
|
"integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==",
|
||||||
|
"dev": true,
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=8"
|
"node": ">=8"
|
||||||
}
|
}
|
||||||
@ -22389,6 +22376,7 @@
|
|||||||
"version": "2.0.2",
|
"version": "2.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
|
||||||
"integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==",
|
"integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==",
|
||||||
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"isexe": "^2.0.0"
|
"isexe": "^2.0.0"
|
||||||
},
|
},
|
||||||
@ -28071,18 +28059,11 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"cross-env": {
|
|
||||||
"version": "7.0.3",
|
|
||||||
"resolved": "https://registry.npmjs.org/cross-env/-/cross-env-7.0.3.tgz",
|
|
||||||
"integrity": "sha512-+/HKd6EgcQCJGh2PSjZuUitQBQynKor4wrFbRg4DtAgS1aWO+gU52xpH7M9ScGgXSYmAVS9bIJ8EzuaGw0oNAw==",
|
|
||||||
"requires": {
|
|
||||||
"cross-spawn": "^7.0.1"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"cross-spawn": {
|
"cross-spawn": {
|
||||||
"version": "7.0.3",
|
"version": "7.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz",
|
||||||
"integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==",
|
"integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==",
|
||||||
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"path-key": "^3.1.0",
|
"path-key": "^3.1.0",
|
||||||
"shebang-command": "^2.0.0",
|
"shebang-command": "^2.0.0",
|
||||||
@ -34524,7 +34505,8 @@
|
|||||||
"path-key": {
|
"path-key": {
|
||||||
"version": "3.1.1",
|
"version": "3.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
|
||||||
"integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q=="
|
"integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==",
|
||||||
|
"dev": true
|
||||||
},
|
},
|
||||||
"path-parse": {
|
"path-parse": {
|
||||||
"version": "1.0.7",
|
"version": "1.0.7",
|
||||||
@ -37005,6 +36987,7 @@
|
|||||||
"version": "2.0.0",
|
"version": "2.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
|
||||||
"integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==",
|
"integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==",
|
||||||
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"shebang-regex": "^3.0.0"
|
"shebang-regex": "^3.0.0"
|
||||||
}
|
}
|
||||||
@ -37012,7 +36995,8 @@
|
|||||||
"shebang-regex": {
|
"shebang-regex": {
|
||||||
"version": "3.0.0",
|
"version": "3.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz",
|
||||||
"integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A=="
|
"integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==",
|
||||||
|
"dev": true
|
||||||
},
|
},
|
||||||
"shell-quote": {
|
"shell-quote": {
|
||||||
"version": "1.7.3",
|
"version": "1.7.3",
|
||||||
@ -39316,6 +39300,7 @@
|
|||||||
"version": "2.0.2",
|
"version": "2.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
|
||||||
"integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==",
|
"integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==",
|
||||||
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"isexe": "^2.0.0"
|
"isexe": "^2.0.0"
|
||||||
}
|
}
|
||||||
|
20
package.json
20
package.json
@ -3,19 +3,19 @@
|
|||||||
"private": true,
|
"private": true,
|
||||||
"sideEffects": false,
|
"sideEffects": false,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev:build": "cross-env NODE_ENV=development dotenv npm run build:server -- --watch",
|
"dev:build": "NODE_ENV=development dotenv npm run build:server -- -- --watch",
|
||||||
"dev:css": "cross-env NODE_ENV=development tailwindcss -i ./styles/tailwind.css -o ./app/styles/tailwind.css --watch",
|
"dev:css": "NODE_ENV=development tailwindcss -i ./styles/tailwind.css -o ./app/styles/tailwind.css --watch",
|
||||||
"dev:remix": "cross-env NODE_ENV=development remix watch",
|
"dev:remix": "NODE_ENV=development remix watch",
|
||||||
"dev:server": "cross-env NODE_ENV=development dotenv node ./server.js",
|
"dev:server": "NODE_ENV=development dotenv node ./server.js",
|
||||||
"dev:worker": "esbuild ./app/entry.worker.ts --outfile=./public/entry.worker.js --bundle --format=esm --watch",
|
"dev:worker": "NODE_ENV=development npm run build:worker -- --watch",
|
||||||
"dev:init": "cross-env NODE_ENV=development dotenv run-s build:remix build:server",
|
"dev:init": "NODE_ENV=development dotenv run-s build:remix build:server",
|
||||||
"dev": "npm run dev:init && run-p dev:build dev:worker dev:css dev:remix dev:server",
|
"dev": "npm run dev:init && run-p dev:build dev:worker dev:css dev:remix dev:server",
|
||||||
"build:server": "node ./scripts/build-server.js",
|
"build:server": "node ./scripts/build-server.js",
|
||||||
"build:css": "tailwindcss -i ./styles/tailwind.css -o ./app/styles/tailwind.css",
|
"build:css": "tailwindcss -i ./styles/tailwind.css -o ./app/styles/tailwind.css",
|
||||||
"build:remix": "remix build",
|
"build:remix": "remix build",
|
||||||
"build:worker": "esbuild ./app/entry.worker.ts --outfile=./public/entry.worker.js --minify --bundle --format=esm",
|
"build:worker": "node ./scripts/build-worker.js",
|
||||||
"build": "cross-env NODE_ENV=production run-s build:css build:worker build:remix build:server",
|
"build": "NODE_ENV=production run-s build:css build:remix build:worker build:server",
|
||||||
"start": "cross-env NODE_ENV=production node ./server.js",
|
"start": "NODE_ENV=production node ./server.js",
|
||||||
"test": "vitest",
|
"test": "vitest",
|
||||||
"test:coverage": "vitest run --coverage",
|
"test:coverage": "vitest run --coverage",
|
||||||
"lint": "eslint --ignore-path .gitignore --ext .js,.ts,.tsx .",
|
"lint": "eslint --ignore-path .gitignore --ext .js,.ts,.tsx .",
|
||||||
@ -66,7 +66,6 @@
|
|||||||
"bullmq": "1.85.1",
|
"bullmq": "1.85.1",
|
||||||
"clsx": "1.1.1",
|
"clsx": "1.1.1",
|
||||||
"compression": "1.7.4",
|
"compression": "1.7.4",
|
||||||
"cross-env": "7.0.3",
|
|
||||||
"express": "4.18.1",
|
"express": "4.18.1",
|
||||||
"ioredis": "5.0.6",
|
"ioredis": "5.0.6",
|
||||||
"isbot": "3.5.0",
|
"isbot": "3.5.0",
|
||||||
@ -118,6 +117,7 @@
|
|||||||
"esbuild": "0.14.42",
|
"esbuild": "0.14.42",
|
||||||
"esbuild-node-externals": "1.4.1",
|
"esbuild-node-externals": "1.4.1",
|
||||||
"eslint": "8.16.0",
|
"eslint": "8.16.0",
|
||||||
|
"glob": "7.2.3",
|
||||||
"happy-dom": "5.0.0",
|
"happy-dom": "5.0.0",
|
||||||
"husky": "7.0.4",
|
"husky": "7.0.4",
|
||||||
"lint-staged": "13.0.0",
|
"lint-staged": "13.0.0",
|
||||||
|
67
scripts/build-worker.js
Normal file
67
scripts/build-worker.js
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
const fs = require("node:fs");
|
||||||
|
const path = require("node:path");
|
||||||
|
const glob = require("glob");
|
||||||
|
const esbuild = require("esbuild");
|
||||||
|
|
||||||
|
const isDev = process.env.NODE_ENV !== "production";
|
||||||
|
const basePath = process.cwd();
|
||||||
|
const args = process.argv.slice(2);
|
||||||
|
const watch = args.includes("--watch");
|
||||||
|
|
||||||
|
const cacheVersion = isDev
|
||||||
|
? "dev"
|
||||||
|
: (() => {
|
||||||
|
const manifests = glob.sync(path.join(basePath, "/public/build/manifest-*.js"));
|
||||||
|
const manifest = manifests.reduce((mostRecent, manifest) =>
|
||||||
|
fs.statSync(manifest).mtime > fs.statSync(mostRecent).mtime ? manifest : mostRecent,
|
||||||
|
);
|
||||||
|
return manifest.match(/manifest-(\w+).js/)[1].toLowerCase();
|
||||||
|
})();
|
||||||
|
|
||||||
|
esbuild
|
||||||
|
.build({
|
||||||
|
write: true,
|
||||||
|
outfile: path.join(basePath, "public", "entry.worker.js"),
|
||||||
|
entryPoints: [path.join(basePath, "app", "entry.worker.ts")],
|
||||||
|
format: "esm",
|
||||||
|
bundle: true,
|
||||||
|
define: {
|
||||||
|
ASSET_CACHE: `"asset-cache_${cacheVersion}"`,
|
||||||
|
DATA_CACHE: `"data-cache_${cacheVersion}"`,
|
||||||
|
DOCUMENT_CACHE: `"document-cache_${cacheVersion}"`,
|
||||||
|
},
|
||||||
|
watch: watch
|
||||||
|
? {
|
||||||
|
onRebuild(error, buildResult) {
|
||||||
|
const warnings = error?.warnings || buildResult?.warnings;
|
||||||
|
const errors = error?.errors || buildResult?.errors;
|
||||||
|
if (warnings.length) {
|
||||||
|
console.log(esbuild.formatMessages(warnings, { kind: "warning" }));
|
||||||
|
}
|
||||||
|
if (errors.length) {
|
||||||
|
console.log(esbuild.formatMessages(errors, { kind: "error" }));
|
||||||
|
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log("Service worker rebuilt successfully");
|
||||||
|
},
|
||||||
|
}
|
||||||
|
: false,
|
||||||
|
})
|
||||||
|
.then(({ errors, warnings }) => {
|
||||||
|
if (warnings.length) {
|
||||||
|
console.log(esbuild.formatMessages(warnings, { kind: "warning" }));
|
||||||
|
}
|
||||||
|
if (errors.length) {
|
||||||
|
console.log(esbuild.formatMessages(errors, { kind: "error" }));
|
||||||
|
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log("Service worker build succeeded");
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
console.error(err);
|
||||||
|
process.exit(1);
|
||||||
|
});
|
Loading…
Reference in New Issue
Block a user