Skip to content

Commit

Permalink
refactor(app): Client-side configuration bundling (#2036)
Browse files Browse the repository at this point in the history
  • Loading branch information
koistya authored Feb 24, 2023
1 parent 7844b99 commit 906e562
Show file tree
Hide file tree
Showing 12 changed files with 95 additions and 47 deletions.
1 change: 1 addition & 0 deletions .github/workflows/pull_request.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ on: [pull_request]

env:
VERSION: ${{ github.event.pull_request.number }}
HUSKY: 0

jobs:
build:
Expand Down
27 changes: 27 additions & 0 deletions app/core/config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
/* SPDX-FileCopyrightText: 2014-present Kriasoft */
/* SPDX-License-Identifier: MIT */

export type EnvName = "prod" | "test" | "local";
export type Config = {
app: {
env: EnvName;
name: string;
origin: string;
hostname: string;
};
firebase: {
projectId: string;
appId: string;
apiKey: string;
authDomain: string;
measurementId: string;
};
};

export const configs = JSON.parse(import.meta.env.VITE_CONFIG);
export const config: Config =
location.hostname === configs.prod.hostname
? configs.prod
: location.hostname === configs.test.hostname
? configs.test
: configs.local;
10 changes: 2 additions & 8 deletions app/core/firebase.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,17 +14,11 @@ import {
type Auth,
type UserCredential,
} from "firebase/auth";
import { config } from "./config.js";
export { AuthErrorCodes, linkWithCredential } from "firebase/auth";
export { FirebaseError };

export const app = initializeApp({
projectId: import.meta.env.VITE_GOOGLE_CLOUD_PROJECT,
appId: import.meta.env.VITE_FIREBASE_APP_ID,
apiKey: import.meta.env.VITE_FIREBASE_API_KEY,
authDomain: import.meta.env.VITE_FIREBASE_AUTH_DOMAIN,
measurementId: import.meta.env.VITE_GA_MEASUREMENT_ID,
});

export const app = initializeApp(config.firebase);
export const auth = getAuth(app);
export const analytics = getAnalytics(app);

Expand Down
9 changes: 5 additions & 4 deletions app/core/page.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import { getAnalytics, logEvent } from "firebase/analytics";
import * as React from "react";
import { useLocation } from "react-router-dom";
import { config } from "./config.js";

export function usePageEffect(
options?: Options,
Expand All @@ -17,10 +18,10 @@ export function usePageEffect(

document.title =
location.pathname === "/"
? options?.title ?? import.meta.env.VITE_APP_NAME
? options?.title ?? config.app.name
: options?.title
? `${options.title} - ${import.meta.env.VITE_APP_NAME}`
: import.meta.env.VITE_APP_NAME;
? `${options.title} - ${config.app.name}`
: config.app.name;

return function () {
document.title = previousTitle;
Expand All @@ -36,7 +37,7 @@ export function usePageEffect(
React.useEffect(() => {
if (!(options?.trackPageView === false)) {
logEvent(getAnalytics(), "page_view", {
page_title: options?.title ?? import.meta.env.VITE_APP_NAME,
page_title: options?.title ?? config.app.name,
page_path: `${location.pathname}${location.search}`,
});
}
Expand Down
24 changes: 16 additions & 8 deletions app/global.d.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,22 @@
/* SPDX-FileCopyrightText: 2014-present Kriasoft */
/* SPDX-License-Identifier: MIT */

declare const APP_NAME: string;
declare const APP_HOSTNAME: string;
declare const GOOGLE_CLOUD_PROJECT: string;
declare const FIREBASE_APP_ID: string;
declare const FIREBASE_API_KEY: string;
declare const FIREBASE_AUTH_DOMAIN: string;
declare const GA_MEASUREMENT_ID: string;

interface Window {
dataLayer: unknown[];
}

interface ImportMetaEnv {
/**
* Client-side configuration for the production, test/QA, and local
* development environments. See `core/config.ts`, `vite.config.ts`.
*/
readonly VITE_CONFIG: string;
}

declare module "relay-runtime" {
interface PayloadError {
errors?: Record<string, string[] | undefined>;
}
}

declare module "*.css";
3 changes: 2 additions & 1 deletion app/layout/components/Logo.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
/* SPDX-License-Identifier: MIT */

import { Typography, TypographyProps } from "@mui/material";
import { config } from "../../core/config.js";

export function Logo(props: TypographyProps): JSX.Element {
const { sx, ...other } = props;
Expand All @@ -18,7 +19,7 @@ export function Logo(props: TypographyProps): JSX.Element {
variant="h1"
{...other}
>
{import.meta.env.VITE_APP_NAME}
{config.app.name}
</Typography>
);
}
3 changes: 0 additions & 3 deletions app/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,5 @@
"typescript": "^4.9.5",
"vite": "^4.1.4",
"vitest": "^0.28.5"
},
"envars": {
"cwd": "../env"
}
}
3 changes: 2 additions & 1 deletion app/routes/auth/Notice.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
/* SPDX-License-Identifier: MIT */

import { Link, Typography, TypographyProps } from "@mui/material";
import { config } from "../../core/config.js";

export function Notice(props: NoticeProps): JSX.Element {
const { sx, ...other } = props;
Expand All @@ -20,7 +21,7 @@ export function Notice(props: NoticeProps): JSX.Element {
>
<span>
By clicking Continue above, your acknowledge that your have read and
understood, and agree to {import.meta.env.VITE_APP_NAME}&apos;s
understood, and agree to {config.app.name}&apos;s
</span>{" "}
<Link color="inherit" href="/terms">
Terms & Conditions
Expand Down
9 changes: 5 additions & 4 deletions app/routes/legal/Privacy.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,19 @@
/* SPDX-License-Identifier: MIT */

import { Container, Link, Typography } from "@mui/material";
import { config } from "../../core/config.js";
import { usePageEffect } from "../../core/page.js";

const appName = import.meta.env.VITE_APP_NAME;
const appOrigin = `https://${import.meta.env.VITE_APP_HOSTNAME}`;
const email = `support@${import.meta.env.VITE_APP_HOSTNAME}`;

/**
* Generated by https://getterms.io
*/
export default function Privacy(): JSX.Element {
usePageEffect({ title: "Privacy Policy" });

const appName = config.app.name;
const appOrigin = config.app.origin;
const email = `hello@${config.app.hostname}`;

return (
<Container
maxWidth="sm"
Expand Down
7 changes: 4 additions & 3 deletions app/routes/legal/Terms.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,18 @@
/* SPDX-License-Identifier: MIT */

import { Container, Link, Typography } from "@mui/material";
import { config } from "../../core/config.js";
import { usePageEffect } from "../../core/page.js";

const appName = import.meta.env.VITE_APP_NAME;
const appOrigin = `https://${import.meta.env.VITE_APP_HOSTNAME}`;

/**
* Generated by https://getterms.io
*/
export default function Terms(): JSX.Element {
usePageEffect({ title: "Terms of Use" });

const appName = config.app.name;
const appOrigin = config.app.origin;

return (
<Container
maxWidth="sm"
Expand Down
3 changes: 2 additions & 1 deletion app/tsconfig.node.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,10 @@
"compilerOptions": {
"composite": true,
"moduleResolution": "Node",
"types": ["vite/client"],
"allowSyntheticDefaultImports": true,
"outDir": "../.cache/typescript-app",
"emitDeclarationOnly": true
},
"include": ["vite.config.ts"]
"include": ["vite.config.ts", "core/config.ts"]
}
43 changes: 29 additions & 14 deletions app/vite.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,24 +3,39 @@

import react from "@vitejs/plugin-react";
import envars from "envars";
import { URL } from "node:url";
import { defineConfig } from "vitest/config";
import { Config, EnvName } from "./core/config.js";

// Load environment variables for the target environment
envars.config();
// The list of supported environments
const envNames: EnvName[] = ["prod", "test", "local"];

// Tells Vite which environment variables need to be injected into the app
// Bootstrap client-side configuration from environment variables
const configs = envNames.map((envName): [EnvName, Config] => {
const env = envars.config({ env: envName, cwd: "../env" });
return [
envName,
{
app: {
env: envName,
name: env.APP_NAME,
origin: env.APP_ORIGIN,
hostname: new URL(env.APP_ORIGIN).hostname,
},
firebase: {
projectId: env.GOOGLE_CLOUD_PROJECT,
appId: env.FIREBASE_APP_ID,
apiKey: env.FIREBASE_API_KEY,
authDomain: env.FIREBASE_AUTH_DOMAIN,
measurementId: env.GA_MEASUREMENT_ID,
},
},
];
});

// Pass client-side configuration to the web app
// https://vitejs.dev/guide/env-and-mode.html#env-variables-and-modes
[
"APP_ENV",
"APP_NAME",
"APP_ORIGIN",
"APP_HOSTNAME",
"GOOGLE_CLOUD_PROJECT",
"FIREBASE_APP_ID",
"FIREBASE_API_KEY",
"FIREBASE_AUTH_DOMAIN",
"GA_MEASUREMENT_ID",
].forEach((key) => (process.env[`VITE_${key}`] = process.env[key]));
process.env.VITE_CONFIG = JSON.stringify(Object.fromEntries(configs));

/**
* Vite configuration
Expand Down

0 comments on commit 906e562

Please sign in to comment.