Skip to content

Commit

Permalink
chore: refactor + add pwa assets example
Browse files Browse the repository at this point in the history
  • Loading branch information
userquin committed Mar 22, 2024
1 parent 35ae858 commit ee9239b
Show file tree
Hide file tree
Showing 23 changed files with 1,377 additions and 332 deletions.
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
node_modules
.DS_Store
dist
dist/
build/
dev-dist
# intellij stuff
.idea/
examples/**/pnpm-lock.yaml

2 changes: 0 additions & 2 deletions build.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ export default defineBuildConfig([{
'workbox-build',
],
rollup: {
emitCJS: true,
dts: {
tsconfig: './tsconfig.node.json',
respectExternal: true,
Expand All @@ -32,7 +31,6 @@ export default defineBuildConfig([{
'virtual:pwa-assets/head',
],
rollup: {
emitCJS: true,
dts: {
tsconfig: './tsconfig.json',
respectExternal: true,
Expand Down
36 changes: 36 additions & 0 deletions examples/pwa-assets/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# Welcome to Remix + Vite!

📖 See the [Remix docs](https://remix.run/docs) and the [Remix Vite docs](https://remix.run/docs/en/main/future/vite) for details on supported features.

## Development

Run the Vite dev server:

```shellscript
npm run dev
```

## Deployment

First, build your app for production:

```sh
npm run build
```

Then run the app in production mode:

```sh
npm start
```

Now you'll need to pick a host to deploy it to.

### DIY

If you're familiar with deploying Node applications, the built-in Remix app server is production-ready.

Make sure to deploy the output of `npm run build`

- `build/server`
- `build/client`
20 changes: 20 additions & 0 deletions examples/pwa-assets/app/entry.client.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
/**
* By default, Remix will handle hydrating your app on the client for you.
* You are free to delete this file if you'd like to, but if you ever want it revealed again, you can run `npx remix reveal` ✨
* For more information, see https://remix.run/file-conventions/entry.client
*/

import { RemixBrowser } from '@remix-run/react'
import { StrictMode, startTransition } from 'react'
import { hydrateRoot } from 'react-dom/client'

import('./pwa')

startTransition(() => {
hydrateRoot(
document,
<StrictMode>
<RemixBrowser />
</StrictMode>,
)
})
137 changes: 137 additions & 0 deletions examples/pwa-assets/app/entry.server.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
/**
* By default, Remix will handle generating the HTTP Response for you.
* You are free to delete this file if you'd like to, but if you ever want it revealed again, you can run `npx remix reveal` ✨
* For more information, see https://remix.run/file-conventions/entry.server
*/

import { PassThrough } from 'node:stream'

import type { AppLoadContext, EntryContext } from '@remix-run/node'
import { createReadableStreamFromReadable } from '@remix-run/node'
import { RemixServer } from '@remix-run/react'
import { isbot } from 'isbot'
import { renderToPipeableStream } from 'react-dom/server'

const ABORT_DELAY = 5_000

export default function handleRequest(
request: Request,
responseStatusCode: number,
responseHeaders: Headers,
remixContext: EntryContext,
// This is ignored so we can keep it in the template for visibility. Feel
// free to delete this parameter in your app if you're not using it!
_loadContext: AppLoadContext,
) {
return isbot(request.headers.get('user-agent') || '')
? handleBotRequest(
request,
responseStatusCode,
responseHeaders,
remixContext,
)
: handleBrowserRequest(
request,
responseStatusCode,
responseHeaders,
remixContext,
)
}

function handleBotRequest(
request: Request,
responseStatusCode: number,
responseHeaders: Headers,
remixContext: EntryContext,
) {
return new Promise((resolve, reject) => {
let shellRendered = false
const { pipe, abort } = renderToPipeableStream(
<RemixServer
context={remixContext}
url={request.url}
abortDelay={ABORT_DELAY}
/>,
{
onAllReady() {
shellRendered = true
const body = new PassThrough()
const stream = createReadableStreamFromReadable(body)

responseHeaders.set('Content-Type', 'text/html')

resolve(
new Response(stream, {
headers: responseHeaders,
status: responseStatusCode,
}),
)

pipe(body)
},
onShellError(error: unknown) {
reject(error)
},
onError(error: unknown) {
responseStatusCode = 500
// Log streaming rendering errors from inside the shell. Don't log
// errors encountered during initial shell rendering since they'll
// reject and get logged in handleDocumentRequest.
if (shellRendered)
console.error(error)
},
},
)

setTimeout(abort, ABORT_DELAY)
})
}

function handleBrowserRequest(
request: Request,
responseStatusCode: number,
responseHeaders: Headers,
remixContext: EntryContext,
) {
return new Promise((resolve, reject) => {
let shellRendered = false
const { pipe, abort } = renderToPipeableStream(
<RemixServer
context={remixContext}
url={request.url}
abortDelay={ABORT_DELAY}
/>,
{
onShellReady() {
shellRendered = true
const body = new PassThrough()
const stream = createReadableStreamFromReadable(body)

responseHeaders.set('Content-Type', 'text/html')

resolve(
new Response(stream, {
headers: responseHeaders,
status: responseStatusCode,
}),
)

pipe(body)
},
onShellError(error: unknown) {
reject(error)
},
onError(error: unknown) {
responseStatusCode = 500
// Log streaming rendering errors from inside the shell. Don't log
// errors encountered during initial shell rendering since they'll
// reject and get logged in handleDocumentRequest.
if (shellRendered)
console.error(error)
},
},
)

setTimeout(abort, ABORT_DELAY)
})
}
11 changes: 11 additions & 0 deletions examples/pwa-assets/app/pwa.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { registerSW } from 'virtual:pwa-register'

registerSW({
immediate: true,
onRegisteredSW(swScriptUrl) {
console.log('SW registered: ', swScriptUrl)
},
onOfflineReady() {
console.log('PWA application ready to work offline')
},
})
31 changes: 31 additions & 0 deletions examples/pwa-assets/app/root.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import {
Links,
Meta,
Outlet,
Scripts,
ScrollRestoration,
} from '@remix-run/react'
import { PWAAssets } from '@vite-pwa/remix/components'

export function Layout({ children }: { children: React.ReactNode }) {
return (
<html lang="en">
<head>
<meta charSet="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<Meta />
<PWAAssets />
<Links />
</head>
<body>
{children}
<ScrollRestoration />
<Scripts />
</body>
</html>
)
}

export default function App() {
return <Outlet />
}
41 changes: 41 additions & 0 deletions examples/pwa-assets/app/routes/_index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import type { MetaFunction } from '@remix-run/node'

export const meta: MetaFunction = () => {
return [
{ title: 'New Remix App' },
{ name: 'description', content: 'Welcome to Remix!' },
]
}

export default function Index() {
return (
<div style={{ fontFamily: 'system-ui, sans-serif', lineHeight: '1.8' }}>
<h1>Welcome to Remix</h1>
<ul>
<li>
<a
target="_blank"
href="https://remix.run/tutorials/blog"
rel="noreferrer"
>
15m Quickstart Blog Tutorial
</a>
</li>
<li>
<a
target="_blank"
href="https://remix.run/tutorials/jokes"
rel="noreferrer"
>
Deep Dive Jokes App Tutorial
</a>
</li>
<li>
<a target="_blank" href="https://remix.run/docs" rel="noreferrer">
Remix Docs
</a>
</li>
</ul>
</div>
)
}
42 changes: 42 additions & 0 deletions examples/pwa-assets/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
{
"name": "pwa-assets",
"private": true,
"sideEffects": false,
"type": "module",
"scripts": {
"build": "remix vite:build",
"dev": "remix vite:dev",
"lint": "eslint --ignore-path .gitignore --cache --cache-location ./node_modules/.cache/eslint .",
"start": "remix-serve ./build/server/index.js",
"typecheck": "tsc"
},
"dependencies": {
"@remix-run/node": "^2.8.1",
"@remix-run/react": "^2.8.1",
"@remix-run/serve": "^2.8.1",
"isbot": "^4.1.0",
"react": "^18.2.0",
"react-dom": "^18.2.0"
},
"devDependencies": {
"@remix-run/dev": "^2.8.1",
"@types/react": "^18.2.20",
"@types/react-dom": "^18.2.7",
"@typescript-eslint/eslint-plugin": "^6.7.4",
"@typescript-eslint/parser": "^6.7.4",
"@vite-pwa/assets-generator": "^0.2.4",
"@vite-pwa/remix": "workspace:*",
"eslint": "^8.57.0",
"eslint-import-resolver-typescript": "^3.6.1",
"eslint-plugin-import": "^2.28.1",
"eslint-plugin-jsx-a11y": "^6.7.1",
"eslint-plugin-react": "^7.33.2",
"eslint-plugin-react-hooks": "^4.6.0",
"typescript": "^5.4.3",
"vite": "^5.2.3",
"vite-tsconfig-paths": "^4.2.1"
},
"engines": {
"node": ">=18.0.0"
}
}
1 change: 1 addition & 0 deletions examples/pwa-assets/public/favicon.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
26 changes: 26 additions & 0 deletions examples/pwa-assets/pwa-assets.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import {
createAppleSplashScreens,
defineConfig,
minimal2023Preset,
} from '@vite-pwa/assets-generator/config'

export default defineConfig({
headLinkOptions: {
preset: '2023',
},
preset: {
...minimal2023Preset,
appleSplashScreens: createAppleSplashScreens({
padding: 0.3,
resizeOptions: { fit: 'contain', background: 'white' },
darkResizeOptions: { fit: 'contain', background: 'black' },
linkMediaOptions: {
log: true,
addMediaScreen: true,
basePath: '/',
xhtml: true,
},
}, ['iPad Air 9.7"']),
},
images: process.env.PNG ? 'public/source-test.png' : 'public/favicon.svg',
})
Loading

0 comments on commit ee9239b

Please sign in to comment.