setup electron app for production
This commit is contained in:
+3
-3
@@ -7,9 +7,9 @@
|
|||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"start": "electron-forge start",
|
"start": "electron-forge start",
|
||||||
"package": "electron-forge package --arch=arm64 && electron-forge package --arch=x64",
|
"package": "APP_ENV=prod electron-forge package --arch=arm64 && APP_ENV=prod electron-forge package --arch=x64",
|
||||||
"make": "electron-forge make --arch=arm64 && electron-forge make --arch=x64",
|
"make": "APP_ENV=prod electron-forge make --arch=arm64 && APP_ENV=prod electron-forge make --arch=x64",
|
||||||
"release": "echo '\n⚠️ Have you bumped the version in package.json? (current: '$(node -p \"require('./package.json').version\")') [y/N]' && read -r answer && [ \"$answer\" = \"y\" ] && electron-forge publish --arch=arm64 && electron-forge publish --arch=x64 && gsutil setmeta -h 'Cache-Control:no-cache, no-store, must-revalidate' gs://flowy-releases/llink/darwin/arm64/RELEASES.json && gsutil setmeta -h 'Cache-Control:no-cache, no-store, must-revalidate' gs://flowy-releases/llink/darwin/x64/RELEASES.json",
|
"release": "echo '\n⚠️ Have you bumped the version in package.json? (current: '$(node -p \"require('./package.json').version\")') [y/N]' && read -r answer && [ \"$answer\" = \"y\" ] && APP_ENV=prod electron-forge publish --arch=arm64 && APP_ENV=prod electron-forge publish --arch=x64 && gsutil setmeta -h 'Cache-Control:no-cache, no-store, must-revalidate' gs://flowy-releases/llink/darwin/arm64/RELEASES.json && gsutil setmeta -h 'Cache-Control:no-cache, no-store, must-revalidate' gs://flowy-releases/llink/darwin/x64/RELEASES.json",
|
||||||
"invalidate-gcs-cache": "gsutil -h \"Cache-Control:no-cache, no-store, max-age=0\" cp gs://flowy-releases/llink/darwin/arm64/RELEASES.json gs://flowy-releases/llink/darwin/arm64/RELEASES.json ; gsutil -h \"Cache-Control:no-cache, no-store, max-age=0\" cp gs://flowy-releases/llink/darwin/x64/RELEASES.json gs://flowy-releases/llink/darwin/x64/RELEASES.json",
|
"invalidate-gcs-cache": "gsutil -h \"Cache-Control:no-cache, no-store, max-age=0\" cp gs://flowy-releases/llink/darwin/arm64/RELEASES.json gs://flowy-releases/llink/darwin/arm64/RELEASES.json ; gsutil -h \"Cache-Control:no-cache, no-store, max-age=0\" cp gs://flowy-releases/llink/darwin/x64/RELEASES.json gs://flowy-releases/llink/darwin/x64/RELEASES.json",
|
||||||
"lint": "eslint --ext .ts,.tsx .",
|
"lint": "eslint --ext .ts,.tsx .",
|
||||||
"compile": "npx tsc --noEmit 2>&1 | grep '^src/'"
|
"compile": "npx tsc --noEmit 2>&1 | grep '^src/'"
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import { appConfig } from "@/config/env";
|
||||||
import { useSessionStore } from "@/stores/session-store";
|
import { useSessionStore } from "@/stores/session-store";
|
||||||
import type { z } from "zod";
|
import type { z } from "zod";
|
||||||
import {
|
import {
|
||||||
@@ -218,7 +219,7 @@ class ApiClient {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const apiClient = new ApiClient({
|
export const apiClient = new ApiClient({
|
||||||
baseUrl: "https://orion.dev.flowy.live",
|
baseUrl: appConfig.orionUrl,
|
||||||
getToken: () => useSessionStore.getState().token,
|
getToken: () => useSessionStore.getState().token,
|
||||||
onUnauthorized: () => useSessionStore.getState().clearToken(),
|
onUnauthorized: () => useSessionStore.getState().clearToken(),
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -0,0 +1,56 @@
|
|||||||
|
// Build-time environment selection.
|
||||||
|
//
|
||||||
|
// __APP_ENV__ is replaced by Vite via `define` in each vite.*.config.ts. Selected
|
||||||
|
// via the APP_ENV env var at build/dev time (defaults to 'dev'). `yarn package`,
|
||||||
|
// `yarn make`, and `yarn release` set APP_ENV=prod.
|
||||||
|
//
|
||||||
|
// Firebase web config is public by design (security is enforced via Firestore
|
||||||
|
// rules + App Check), so both configs live in source. To refresh, run:
|
||||||
|
// cd infra/gcp/{dev,prod} && terraform output -json firebase_config
|
||||||
|
|
||||||
|
declare const __APP_ENV__: "dev" | "prod";
|
||||||
|
|
||||||
|
type FirebaseConfig = {
|
||||||
|
apiKey: string;
|
||||||
|
appId: string;
|
||||||
|
authDomain: string;
|
||||||
|
messagingSenderId: string;
|
||||||
|
projectId: string;
|
||||||
|
storageBucket: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
type AppConfig = {
|
||||||
|
orionUrl: string;
|
||||||
|
pusherUrl: string;
|
||||||
|
firebase: FirebaseConfig;
|
||||||
|
};
|
||||||
|
|
||||||
|
const configs: Record<"dev" | "prod", AppConfig> = {
|
||||||
|
dev: {
|
||||||
|
orionUrl: "https://orion.dev.flowy.live",
|
||||||
|
pusherUrl: "wss://pusher.dev.flowy.live/ws",
|
||||||
|
firebase: {
|
||||||
|
apiKey: "AIzaSyDF_fbk7tDY9tNxUiOwwi--2nYZWZygMGk",
|
||||||
|
appId: "1:1006580076785:web:e2a0736d60a78e02b15950",
|
||||||
|
authDomain: "flowy-dev-440017.firebaseapp.com",
|
||||||
|
messagingSenderId: "1006580076785",
|
||||||
|
projectId: "flowy-dev-440017",
|
||||||
|
storageBucket: "flowy-dev-440017.firebasestorage.app",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
prod: {
|
||||||
|
orionUrl: "https://orion.flowy.live",
|
||||||
|
pusherUrl: "wss://pusher.flowy.live/ws",
|
||||||
|
firebase: {
|
||||||
|
apiKey: "AIzaSyB8it3SKr9DHScHGlpu4uwWicvt8wzjdBg",
|
||||||
|
appId: "1:68063426854:web:5054f16f50898f5706e9e7",
|
||||||
|
authDomain: "flowy-prod-440017.firebaseapp.com",
|
||||||
|
messagingSenderId: "68063426854",
|
||||||
|
projectId: "flowy-prod-440017",
|
||||||
|
storageBucket: "flowy-prod-440017.firebasestorage.app",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export const appConfig: AppConfig = configs[__APP_ENV__];
|
||||||
|
export const appEnv: "dev" | "prod" = __APP_ENV__;
|
||||||
+2
-10
@@ -1,16 +1,8 @@
|
|||||||
import { initializeApp } from 'firebase/app';
|
import { initializeApp } from 'firebase/app';
|
||||||
import { getFirestore } from "firebase/firestore";
|
import { getFirestore } from "firebase/firestore";
|
||||||
|
import { appConfig } from "@/config/env";
|
||||||
|
|
||||||
const firebaseConfig = {
|
export const firebaseApp = initializeApp(appConfig.firebase);
|
||||||
apiKey: "AIzaSyDF_fbk7tDY9tNxUiOwwi--2nYZWZygMGk",
|
|
||||||
appId: "1:1006580076785:web:e2a0736d60a78e02b15950",
|
|
||||||
authDomain: "flowy-dev-440017.firebaseapp.com",
|
|
||||||
messagingSenderId: "1006580076785",
|
|
||||||
projectId: "flowy-dev-440017",
|
|
||||||
storageBucket: "flowy-dev-440017.firebasestorage.app",
|
|
||||||
};
|
|
||||||
|
|
||||||
export const firebaseApp = initializeApp(firebaseConfig);
|
|
||||||
|
|
||||||
export const firestoreDb = getFirestore(firebaseApp);
|
export const firestoreDb = getFirestore(firebaseApp);
|
||||||
// simplifying setup to debug production issues
|
// simplifying setup to debug production issues
|
||||||
|
|||||||
@@ -8,13 +8,11 @@ import {
|
|||||||
} from "react";
|
} from "react";
|
||||||
import { PusherClient, type ConnectionState } from "./pusher-client";
|
import { PusherClient, type ConnectionState } from "./pusher-client";
|
||||||
import { useSessionStore } from "@/stores/session-store";
|
import { useSessionStore } from "@/stores/session-store";
|
||||||
|
import { appConfig } from "@/config/env";
|
||||||
|
|
||||||
const PusherContext = createContext<PusherClient | null>(null);
|
const PusherContext = createContext<PusherClient | null>(null);
|
||||||
const PusherStateContext = createContext<ConnectionState>("disconnected");
|
const PusherStateContext = createContext<ConnectionState>("disconnected");
|
||||||
|
|
||||||
// TODO: make this configurable per environment
|
|
||||||
const PUSHER_URL = "wss://pusher.dev.flowy.live/ws";
|
|
||||||
|
|
||||||
export function PusherProvider({ children }: { children: ReactNode }) {
|
export function PusherProvider({ children }: { children: ReactNode }) {
|
||||||
const token = useSessionStore((s) => s.token);
|
const token = useSessionStore((s) => s.token);
|
||||||
const clientRef = useRef<PusherClient | null>(null);
|
const clientRef = useRef<PusherClient | null>(null);
|
||||||
@@ -33,7 +31,7 @@ export function PusherProvider({ children }: { children: ReactNode }) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const client = new PusherClient({
|
const client = new PusherClient({
|
||||||
url: PUSHER_URL,
|
url: appConfig.pusherUrl,
|
||||||
getToken: () => useSessionStore.getState().token,
|
getToken: () => useSessionStore.getState().token,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
+2
-1
@@ -4,6 +4,7 @@ import started from 'electron-squirrel-startup';
|
|||||||
import { updateElectronApp, UpdateSourceType } from 'update-electron-app';
|
import { updateElectronApp, UpdateSourceType } from 'update-electron-app';
|
||||||
|
|
||||||
import type { LinkMetadata } from './lib/link-metadata';
|
import type { LinkMetadata } from './lib/link-metadata';
|
||||||
|
import { appConfig } from './config/env';
|
||||||
|
|
||||||
if (app.isPackaged) {
|
if (app.isPackaged) {
|
||||||
updateElectronApp({
|
updateElectronApp({
|
||||||
@@ -484,7 +485,7 @@ app.on('ready', () => {
|
|||||||
// The server doesn't handle OPTIONS preflight, so we intercept at the
|
// The server doesn't handle OPTIONS preflight, so we intercept at the
|
||||||
// Electron network layer: inject CORS headers and return 200 for preflight.
|
// Electron network layer: inject CORS headers and return 200 for preflight.
|
||||||
session.defaultSession.webRequest.onHeadersReceived(
|
session.defaultSession.webRequest.onHeadersReceived(
|
||||||
{ urls: ['https://orion.dev.flowy.live/*', 'https://storage.googleapis.com/*'] },
|
{ urls: [`${appConfig.orionUrl}/*`, 'https://storage.googleapis.com/*'] },
|
||||||
(details, callback) => {
|
(details, callback) => {
|
||||||
const headers = { ...details.responseHeaders };
|
const headers = { ...details.responseHeaders };
|
||||||
headers['access-control-allow-origin'] = ['*'];
|
headers['access-control-allow-origin'] = ['*'];
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import path from "path"
|
|||||||
import tailwindcss from "@tailwindcss/vite"
|
import tailwindcss from "@tailwindcss/vite"
|
||||||
import { defineConfig } from 'vite';
|
import { defineConfig } from 'vite';
|
||||||
import react from '@vitejs/plugin-react';
|
import react from '@vitejs/plugin-react';
|
||||||
|
import { defineEnv } from './vite.env';
|
||||||
|
|
||||||
// https://vitejs.dev/config
|
// https://vitejs.dev/config
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
@@ -20,4 +21,5 @@ export default defineConfig({
|
|||||||
allow: [path.resolve(__dirname)],
|
allow: [path.resolve(__dirname)],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
define: defineEnv,
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -0,0 +1,13 @@
|
|||||||
|
// Shared Vite `define` block that injects the build-time __APP_ENV__ constant
|
||||||
|
// consumed by src/config/env.ts. Sourced from process.env.APP_ENV (default 'dev').
|
||||||
|
|
||||||
|
const raw = process.env.APP_ENV ?? "dev";
|
||||||
|
if (raw !== "dev" && raw !== "prod") {
|
||||||
|
throw new Error(`APP_ENV must be "dev" or "prod", got: ${raw}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
export const appEnv = raw;
|
||||||
|
|
||||||
|
export const defineEnv = {
|
||||||
|
__APP_ENV__: JSON.stringify(appEnv),
|
||||||
|
};
|
||||||
@@ -2,6 +2,7 @@ import path from "path"
|
|||||||
import tailwindcss from "@tailwindcss/vite"
|
import tailwindcss from "@tailwindcss/vite"
|
||||||
import { defineConfig } from 'vite';
|
import { defineConfig } from 'vite';
|
||||||
import react from '@vitejs/plugin-react';
|
import react from '@vitejs/plugin-react';
|
||||||
|
import { defineEnv } from './vite.env';
|
||||||
|
|
||||||
// https://vitejs.dev/config
|
// https://vitejs.dev/config
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
@@ -20,4 +21,5 @@ export default defineConfig({
|
|||||||
allow: [path.resolve(__dirname)],
|
allow: [path.resolve(__dirname)],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
define: defineEnv,
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,4 +1,7 @@
|
|||||||
import { defineConfig } from 'vite';
|
import { defineConfig } from 'vite';
|
||||||
|
import { defineEnv } from './vite.env';
|
||||||
|
|
||||||
// https://vitejs.dev/config
|
// https://vitejs.dev/config
|
||||||
export default defineConfig({});
|
export default defineConfig({
|
||||||
|
define: defineEnv,
|
||||||
|
});
|
||||||
|
|||||||
@@ -1,4 +1,7 @@
|
|||||||
import { defineConfig } from 'vite';
|
import { defineConfig } from 'vite';
|
||||||
|
import { defineEnv } from './vite.env';
|
||||||
|
|
||||||
// https://vitejs.dev/config
|
// https://vitejs.dev/config
|
||||||
export default defineConfig({});
|
export default defineConfig({
|
||||||
|
define: defineEnv,
|
||||||
|
});
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import path from "path"
|
|||||||
import tailwindcss from "@tailwindcss/vite"
|
import tailwindcss from "@tailwindcss/vite"
|
||||||
import { defineConfig } from 'vite';
|
import { defineConfig } from 'vite';
|
||||||
import react from '@vitejs/plugin-react';
|
import react from '@vitejs/plugin-react';
|
||||||
|
import { defineEnv } from './vite.env';
|
||||||
|
|
||||||
// https://vitejs.dev/config
|
// https://vitejs.dev/config
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
@@ -11,4 +12,5 @@ export default defineConfig({
|
|||||||
"@": path.resolve(__dirname, "./src"),
|
"@": path.resolve(__dirname, "./src"),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
define: defineEnv,
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import path from "path"
|
|||||||
import tailwindcss from "@tailwindcss/vite"
|
import tailwindcss from "@tailwindcss/vite"
|
||||||
import { defineConfig } from 'vite';
|
import { defineConfig } from 'vite';
|
||||||
import react from '@vitejs/plugin-react';
|
import react from '@vitejs/plugin-react';
|
||||||
|
import { defineEnv } from './vite.env';
|
||||||
|
|
||||||
// https://vitejs.dev/config
|
// https://vitejs.dev/config
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
@@ -20,4 +21,5 @@ export default defineConfig({
|
|||||||
allow: [path.resolve(__dirname)],
|
allow: [path.resolve(__dirname)],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
define: defineEnv,
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user