Merge pull request #121 from jderehag/dev
feat(ui): add PWA support with vite-plugin-pwa
This commit is contained in:
4618
package-lock.json
generated
4618
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -62,6 +62,18 @@ You can configure the server using flags or environment variables:
|
||||
Use this only when access is already protected by another layer (SSO proxy, VPN, Coder workspace auth, etc.).
|
||||
If you bind to `0.0.0.0` while skipping auth, anyone who can reach the port can access the API.
|
||||
|
||||
### Progressive Web App (PWA)
|
||||
When running as a server CodeNomad can also be installed as a PWA from any supported browser, giving you a native app experience just like the Electron installation but executing on the remote server instead.
|
||||
|
||||
1. Open the CodeNomad UI in a Chromium-based browser (Chrome, Edge, Brave, etc.).
|
||||
2. Click the install icon in the address bar, or use the browser menu → "Install CodeNomad".
|
||||
3. The app will open in a standalone window and appear in your OS app list.
|
||||
|
||||
> **TLS requirement**
|
||||
> Browsers require a secure (`https://`) connection for PWA installation.
|
||||
> If you host CodeNomad on a remote machine, serve it behind a reverse proxy (e.g. Caddy, nginx) with a valid TLS certificate.
|
||||
> Self-signed certificates generally won't work unless they are explicitly trusted by the device/browser (e.g., via a custom CA).
|
||||
|
||||
### Data Storage
|
||||
- **Config**: `~/.config/codenomad/config.json`
|
||||
- **Instance Data**: `~/.config/codenomad/instances` (chat history, etc.)
|
||||
|
||||
1
packages/ui/.gitignore
vendored
1
packages/ui/.gitignore
vendored
@@ -1,3 +1,4 @@
|
||||
node_modules/
|
||||
dist/
|
||||
.vite/
|
||||
src/renderer/public/logo.png
|
||||
|
||||
@@ -30,11 +30,13 @@
|
||||
"solid-toast": "^0.5.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@vite-pwa/assets-generator": "^1.0.2",
|
||||
"autoprefixer": "10.4.21",
|
||||
"postcss": "8.5.6",
|
||||
"tailwindcss": "3",
|
||||
"typescript": "^5.3.0",
|
||||
"vite": "^5.0.0",
|
||||
"vite-plugin-pwa": "^1.2.0",
|
||||
"vite-plugin-solid": "^2.10.0"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import fs from "fs"
|
||||
import { defineConfig } from "vite"
|
||||
import solid from "vite-plugin-solid"
|
||||
import { VitePWA } from "vite-plugin-pwa"
|
||||
import { resolve } from "path"
|
||||
|
||||
const uiPackageJson = JSON.parse(fs.readFileSync(resolve(__dirname, "package.json"), "utf-8")) as { version?: string }
|
||||
@@ -20,6 +21,55 @@ export default defineConfig({
|
||||
})
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "prepare-pwa-source-icon",
|
||||
apply: "build",
|
||||
buildStart() {
|
||||
// vite-pwa-assets requires the source image inside root/public/
|
||||
const source = resolve(__dirname, "src/images/CodeNomad-Icon.png")
|
||||
const publicDir = resolve(__dirname, "src/renderer/public")
|
||||
const dest = resolve(publicDir, "logo.png")
|
||||
fs.mkdirSync(publicDir, { recursive: true })
|
||||
fs.copyFileSync(source, dest)
|
||||
},
|
||||
},
|
||||
VitePWA({
|
||||
registerType: "autoUpdate",
|
||||
injectRegister: "auto",
|
||||
pwaAssets: {
|
||||
preset: "minimal-2023",
|
||||
image: "public/logo.png",
|
||||
},
|
||||
manifest: {
|
||||
name: "CodeNomad",
|
||||
short_name: "CodeNomad",
|
||||
id: "/",
|
||||
start_url: "/",
|
||||
display: "standalone",
|
||||
display_override: ["window-controls-overlay", "standalone"],
|
||||
background_color: "#1a1a1a",
|
||||
theme_color: "#1a1a1a",
|
||||
},
|
||||
workbox: {
|
||||
// Preserve server-side auth redirects (e.g., /login) instead of serving cached index.html.
|
||||
navigateFallback: null,
|
||||
// Only cache static UI assets; never cache API traffic.
|
||||
runtimeCaching: [
|
||||
{
|
||||
urlPattern: ({ url, request }) => {
|
||||
if (url.pathname.startsWith("/api/")) return false
|
||||
return ["script", "style", "image", "font"].includes(request.destination)
|
||||
},
|
||||
handler: "CacheFirst",
|
||||
options: {
|
||||
cacheName: "asset-cache",
|
||||
expiration: { maxEntries: 200, maxAgeSeconds: 60 * 60 * 24 * 30 },
|
||||
cacheableResponse: { statuses: [0, 200] },
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
}),
|
||||
],
|
||||
css: {
|
||||
postcss: "./postcss.config.js",
|
||||
|
||||
Reference in New Issue
Block a user