Feat: Local prod proxy
This commit is contained in:
@@ -1,5 +1,8 @@
|
||||
# syntax=docker/dockerfile:1.7
|
||||
|
||||
# Frontend development image only.
|
||||
# Production static serving is owned by Proxy/Local/Dockerfile.
|
||||
|
||||
FROM node:22-alpine AS base
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
@@ -17,30 +17,18 @@ target "dev" {
|
||||
tags = ["moku/work-frontend:dev"]
|
||||
}
|
||||
|
||||
target "prod" {
|
||||
inherits = ["_app"]
|
||||
target = "production"
|
||||
tags = ["moku/work-frontend:prod"]
|
||||
}
|
||||
|
||||
target "dev-image" {
|
||||
inherits = ["_app"]
|
||||
target = "development"
|
||||
tags = ["${REGISTRY}/moku/work-frontend:dev-${TAG}"]
|
||||
}
|
||||
|
||||
target "prod-image" {
|
||||
inherits = ["_app"]
|
||||
target = "production"
|
||||
tags = ["${REGISTRY}/moku/work-frontend:prod-${TAG}"]
|
||||
}
|
||||
|
||||
group "local" {
|
||||
targets = ["dev", "prod"]
|
||||
targets = ["dev"]
|
||||
}
|
||||
|
||||
group "registry" {
|
||||
targets = ["dev-image", "prod-image"]
|
||||
targets = ["dev-image"]
|
||||
}
|
||||
|
||||
group "default" {
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
"scripts": {
|
||||
"dev": "vite dev",
|
||||
"build": "vite build",
|
||||
"build:static": "pnpm build && node ./scripts/render-static-index.mjs",
|
||||
"typecheck": "tsc --noEmit",
|
||||
"start": "vite preview",
|
||||
"preview": "vite preview"
|
||||
|
||||
49
Frontend/scripts/render-static-index.mjs
Normal file
49
Frontend/scripts/render-static-index.mjs
Normal file
@@ -0,0 +1,49 @@
|
||||
import { mkdir, readFile, writeFile } from "node:fs/promises";
|
||||
import { dirname, resolve } from "node:path";
|
||||
|
||||
const manifestPath = resolve("dist/client/.vite/manifest.json");
|
||||
const outputPath = resolve("dist/client/index.html");
|
||||
|
||||
const themeBootstrapScript = `
|
||||
(() => {
|
||||
try {
|
||||
const storageKey = "theme";
|
||||
const stored = localStorage.getItem(storageKey);
|
||||
const theme = stored === "light" || stored === "dark"
|
||||
? stored
|
||||
: (window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light");
|
||||
|
||||
document.documentElement.setAttribute("data-theme", theme);
|
||||
} catch {
|
||||
document.documentElement.setAttribute("data-theme", "light");
|
||||
}
|
||||
})();
|
||||
`.trim();
|
||||
|
||||
const manifest = JSON.parse(await readFile(manifestPath, "utf8"));
|
||||
const entry = manifest["src/entry-client.tsx"];
|
||||
|
||||
if (!entry?.file) {
|
||||
throw new Error("Could not find src/entry-client.tsx in the client manifest.");
|
||||
}
|
||||
|
||||
const cssLinks = Array.isArray(entry.css) ? entry.css.map((href) => ` <link rel="stylesheet" href="/${href}">`).join("\n") : "";
|
||||
|
||||
const html = `<!doctype html>
|
||||
<html lang="en" data-theme="light">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<link rel="icon" href="/favicon.ico">
|
||||
<script>${themeBootstrapScript}</script>
|
||||
${cssLinks}
|
||||
</head>
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
<script type="module" src="/${entry.file}"></script>
|
||||
</body>
|
||||
</html>
|
||||
`;
|
||||
|
||||
await mkdir(dirname(outputPath), { recursive: true });
|
||||
await writeFile(outputPath, html, "utf8");
|
||||
@@ -1,6 +1,5 @@
|
||||
// Path: Frontend/vite.config.ts
|
||||
|
||||
import { nitroV2Plugin as nitro } from "@solidjs/vite-plugin-nitro-2";
|
||||
import { defineConfig } from "vite";
|
||||
|
||||
import { solidStart } from "@solidjs/start/config";
|
||||
@@ -11,7 +10,7 @@ const extraAllowedHosts = (process.env.ALLOWED_HOSTS ?? "")
|
||||
.filter(Boolean);
|
||||
|
||||
export default defineConfig({
|
||||
plugins: [solidStart(), nitro()],
|
||||
plugins: [solidStart({ ssr: false })],
|
||||
server: {
|
||||
allowedHosts: ["localhost", ...extraAllowedHosts],
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user