13 | {message}
14 |
15 | This example utilizes a hand crafted web worker that employs multiple
16 | caching strategies depending on the requests.
17 |
18 |
19 |
20 | Network First is used for document and data requests.
21 |
22 |
23 | Cache First is used for assets.
24 |
25 |
26 |
27 | Viewing the behavior
28 |
29 | I'm assuming you're using chrome and have used dev-tools before or are
30 | capable of googling:
31 |
32 |
33 | Open dev-tools
34 |
35 | Open the Application tab, select Storage and click{" "}
36 | Clear site data
37 |
38 | Reload the page
39 |
40 | Click on the Home link above. This will do a client side
41 | navigation to the home page
42 |
43 |
44 | Open the Network tab and set throttling to Offline
45 |
46 |
47 |
48 |
49 | If you've followed the steps above, even though you did not visit the
50 | home page via a document request, you can still reload the page and
51 | access it.
52 |
53 |
54 | Similarly, even though you didn't client side navigate to the about
55 | page, if you click on the About link from the home page you can
56 | still access the about page.
57 |
58 |
59 | );
60 | }
61 |
--------------------------------------------------------------------------------
/app/routes/index.tsx:
--------------------------------------------------------------------------------
1 | import { Link, useLoaderData } from "remix";
2 | import type { LoaderFunction } from "remix";
3 |
4 | export let loader: LoaderFunction = () => {
5 | return { message: "Welcome!" };
6 | };
7 |
8 | export default function IndexRoute() {
9 | let { message } = useLoaderData();
10 |
11 | return (
12 |
13 | {message}
14 |
15 | This is an example PWA built with{" "}
16 |
17 | Remix
18 |
19 | .
20 |
21 |
22 | Since Remix utlizes SSR + client side navigations you actually have two
23 | ways the data ends up in your components:
24 |
25 |
26 | embeded in the initial HTML for document requests
27 |
28 | or fetch() from the network for client side navigations
29 |
30 |
31 |
32 | To account for this when you landed on a page through a document request
33 | the service worker will fetch() the equivilant data in the
34 | background to simulate that you landed on the page through a cient side
35 | navigation.
36 |
37 |
38 | Similarly, if you land on a page through a client side navigation the
39 | service worker will simulate a full page document navigation and cache
40 | that in the background so when you reload the page you can still access
41 | it.
42 |
43 |
44 | Head on over to the about page for instructions
45 | on how to view this behavior.
46 |
47 |
48 | );
49 | }
50 |
--------------------------------------------------------------------------------
/app/routes/resources/manifest[.]json.ts:
--------------------------------------------------------------------------------
1 | import { json } from "remix";
2 | import type { LoaderFunction } from "remix";
3 |
4 | export let loader: LoaderFunction = () => {
5 | return json(
6 | {
7 | short_name: "Remix TODO",
8 | name: "Remix TODO",
9 | start_url: "/",
10 | display: "standalone",
11 | background_color: "#d3d7dd",
12 | theme_color: "#c34138",
13 | icons: [
14 | {
15 | src: "/icons/android-icon-36x36.png",
16 | sizes: "36x36",
17 | type: "image/png",
18 | density: "0.75",
19 | },
20 | {
21 | src: "/icons/android-icon-48x48.png",
22 | sizes: "48x48",
23 | type: "image/png",
24 | density: "1.0",
25 | },
26 | {
27 | src: "/icons/android-icon-72x72.png",
28 | sizes: "72x72",
29 | type: "image/png",
30 | density: "1.5",
31 | },
32 | {
33 | src: "/icons/android-icon-96x96.png",
34 | sizes: "96x96",
35 | type: "image/png",
36 | density: "2.0",
37 | },
38 | {
39 | src: "/icons/android-icon-144x144.png",
40 | sizes: "144x144",
41 | type: "image/png",
42 | density: "3.0",
43 | },
44 | {
45 | src: "/icons/android-icon-192x192.png",
46 | sizes: "192x192",
47 | type: "image/png",
48 | density: "4.0",
49 | },
50 | ],
51 | },
52 | {
53 | headers: {
54 | "Cache-Control": "public, max-age=600",
55 | },
56 | }
57 | );
58 | };
59 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "private": true,
3 | "name": "remix-pwa",
4 | "description": "",
5 | "license": "",
6 | "scripts": {
7 | "typecheck": "tsc",
8 | "build": "run-p build:*",
9 | "build:remix": "cross-env NODE_ENV=production remix build",
10 | "build:worker": "esbuild ./app/entry.worker.ts --outfile=./public/entry.worker.js --minify --bundle --format=esm --define:process.env.NODE_ENV='\"production\"'",
11 | "dev": "run-p dev:*",
12 | "dev:remix": "dotenv -- remix dev",
13 | "dev:worker": "esbuild ./app/entry.worker.ts --outfile=./public/entry.worker.js --bundle --format=esm --define:process.env.NODE_ENV='\"development\"' --watch",
14 | "start": "cross-env NODE_ENV=production remix-serve build",
15 | "postinstall": "remix setup node"
16 | },
17 | "dependencies": {
18 | "@remix-run/react": "^1.1.3",
19 | "@remix-run/serve": "^1.1.3",
20 | "awsm.css": "^3.0.7",
21 | "react": "^17.0.2",
22 | "react-dom": "^17.0.2",
23 | "remix": "^1.1.3"
24 | },
25 | "devDependencies": {
26 | "@remix-run/dev": "^1.1.3",
27 | "@types/react": "^17.0.24",
28 | "@types/react-dom": "^17.0.9",
29 | "cross-env": "^7.0.3",
30 | "dotenv-cli": "^4.1.1",
31 | "npm-run-all": "^4.1.5",
32 | "typescript": "^4.1.2"
33 | },
34 | "engines": {
35 | "node": ">=14"
36 | },
37 | "sideEffects": false
38 | }
39 |
--------------------------------------------------------------------------------
/public/icons/android-icon-144x144.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jacob-ebey/remix-pwa/8a12cf63f5569f553b1faf6bba41d1693b2b1b52/public/icons/android-icon-144x144.png
--------------------------------------------------------------------------------
/public/icons/android-icon-192x192.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jacob-ebey/remix-pwa/8a12cf63f5569f553b1faf6bba41d1693b2b1b52/public/icons/android-icon-192x192.png
--------------------------------------------------------------------------------
/public/icons/android-icon-36x36.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jacob-ebey/remix-pwa/8a12cf63f5569f553b1faf6bba41d1693b2b1b52/public/icons/android-icon-36x36.png
--------------------------------------------------------------------------------
/public/icons/android-icon-48x48.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jacob-ebey/remix-pwa/8a12cf63f5569f553b1faf6bba41d1693b2b1b52/public/icons/android-icon-48x48.png
--------------------------------------------------------------------------------
/public/icons/android-icon-72x72.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jacob-ebey/remix-pwa/8a12cf63f5569f553b1faf6bba41d1693b2b1b52/public/icons/android-icon-72x72.png
--------------------------------------------------------------------------------
/public/icons/android-icon-96x96.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jacob-ebey/remix-pwa/8a12cf63f5569f553b1faf6bba41d1693b2b1b52/public/icons/android-icon-96x96.png
--------------------------------------------------------------------------------
/public/icons/apple-icon-114x114.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jacob-ebey/remix-pwa/8a12cf63f5569f553b1faf6bba41d1693b2b1b52/public/icons/apple-icon-114x114.png
--------------------------------------------------------------------------------
/public/icons/apple-icon-120x120.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jacob-ebey/remix-pwa/8a12cf63f5569f553b1faf6bba41d1693b2b1b52/public/icons/apple-icon-120x120.png
--------------------------------------------------------------------------------
/public/icons/apple-icon-144x144.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jacob-ebey/remix-pwa/8a12cf63f5569f553b1faf6bba41d1693b2b1b52/public/icons/apple-icon-144x144.png
--------------------------------------------------------------------------------
/public/icons/apple-icon-152x152.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jacob-ebey/remix-pwa/8a12cf63f5569f553b1faf6bba41d1693b2b1b52/public/icons/apple-icon-152x152.png
--------------------------------------------------------------------------------
/public/icons/apple-icon-180x180.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jacob-ebey/remix-pwa/8a12cf63f5569f553b1faf6bba41d1693b2b1b52/public/icons/apple-icon-180x180.png
--------------------------------------------------------------------------------
/public/icons/apple-icon-57x57.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jacob-ebey/remix-pwa/8a12cf63f5569f553b1faf6bba41d1693b2b1b52/public/icons/apple-icon-57x57.png
--------------------------------------------------------------------------------
/public/icons/apple-icon-60x60.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jacob-ebey/remix-pwa/8a12cf63f5569f553b1faf6bba41d1693b2b1b52/public/icons/apple-icon-60x60.png
--------------------------------------------------------------------------------
/public/icons/apple-icon-72x72.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jacob-ebey/remix-pwa/8a12cf63f5569f553b1faf6bba41d1693b2b1b52/public/icons/apple-icon-72x72.png
--------------------------------------------------------------------------------
/public/icons/apple-icon-76x76.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jacob-ebey/remix-pwa/8a12cf63f5569f553b1faf6bba41d1693b2b1b52/public/icons/apple-icon-76x76.png
--------------------------------------------------------------------------------
/public/icons/apple-icon-precomposed.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jacob-ebey/remix-pwa/8a12cf63f5569f553b1faf6bba41d1693b2b1b52/public/icons/apple-icon-precomposed.png
--------------------------------------------------------------------------------
/public/icons/apple-icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jacob-ebey/remix-pwa/8a12cf63f5569f553b1faf6bba41d1693b2b1b52/public/icons/apple-icon.png
--------------------------------------------------------------------------------
/public/icons/favicon-16x16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jacob-ebey/remix-pwa/8a12cf63f5569f553b1faf6bba41d1693b2b1b52/public/icons/favicon-16x16.png
--------------------------------------------------------------------------------
/public/icons/favicon-32x32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jacob-ebey/remix-pwa/8a12cf63f5569f553b1faf6bba41d1693b2b1b52/public/icons/favicon-32x32.png
--------------------------------------------------------------------------------
/public/icons/favicon-96x96.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jacob-ebey/remix-pwa/8a12cf63f5569f553b1faf6bba41d1693b2b1b52/public/icons/favicon-96x96.png
--------------------------------------------------------------------------------
/public/icons/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jacob-ebey/remix-pwa/8a12cf63f5569f553b1faf6bba41d1693b2b1b52/public/icons/favicon.ico
--------------------------------------------------------------------------------
/public/icons/ms-icon-144x144.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jacob-ebey/remix-pwa/8a12cf63f5569f553b1faf6bba41d1693b2b1b52/public/icons/ms-icon-144x144.png
--------------------------------------------------------------------------------
/public/icons/ms-icon-150x150.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jacob-ebey/remix-pwa/8a12cf63f5569f553b1faf6bba41d1693b2b1b52/public/icons/ms-icon-150x150.png
--------------------------------------------------------------------------------
/public/icons/ms-icon-310x310.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jacob-ebey/remix-pwa/8a12cf63f5569f553b1faf6bba41d1693b2b1b52/public/icons/ms-icon-310x310.png
--------------------------------------------------------------------------------
/public/icons/ms-icon-70x70.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jacob-ebey/remix-pwa/8a12cf63f5569f553b1faf6bba41d1693b2b1b52/public/icons/ms-icon-70x70.png
--------------------------------------------------------------------------------
/remix.config.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @type {import('@remix-run/dev/config').AppConfig}
3 | */
4 | module.exports = {
5 | appDirectory: "app",
6 | assetsBuildDirectory: "public/build",
7 | publicPath: "/build/",
8 | serverBuildDirectory: "build",
9 | devServerPort: 8002,
10 | ignoredRouteFiles: [".*"]
11 | };
12 |
--------------------------------------------------------------------------------
/remix.env.d.ts:
--------------------------------------------------------------------------------
1 | ///