diff --git a/frontend/apps/editor3d/app/src/Classes/GetFrontendEnvironment.ts b/frontend/apps/editor3d/app/src/Classes/GetFrontendEnvironment.ts deleted file mode 100644 index 230aea3999..0000000000 --- a/frontend/apps/editor3d/app/src/Classes/GetFrontendEnvironment.ts +++ /dev/null @@ -1,65 +0,0 @@ -import { Environment } from "~/configs"; - -export enum FrontendEnvironmentType { - Dev, - DevProxy, - Staging, - Production, -} - -export class FrontendEnvironment { - private static instance: FrontendEnvironment; - private readonly environment: FrontendEnvironmentType; - private readonly isLocalDev: boolean; - - public static getInstance(): FrontendEnvironment { - if (FrontendEnvironment.instance !== undefined) { - return FrontendEnvironment.instance; - } - - if (typeof document === "undefined") { - // TODO(bt,2025-02-10): This is digusting. Vite or whatever - // doesn't have 'document' defined early in preloading execution. - // This non-cached codepath is dangerous, because who knows what - // happens downstream. Fix this ASAP. - return new FrontendEnvironment(FrontendEnvironmentType.Production, false); - } - - const isLocalDev = - document.location.host.includes("localhost") || - document.location.host.startsWith("dev.") || - document.location.host.startsWith("development."); - - let environmentType = FrontendEnvironmentType.Production; - - if (isLocalDev) { - environmentType = FrontendEnvironmentType.Dev; - } - - if (document.location.host.includes("dev") && - document.location.hostname.includes("proxy")) { - environmentType = FrontendEnvironmentType.DevProxy; - } - - const instance = new FrontendEnvironment(environmentType, isLocalDev); - FrontendEnvironment.instance = instance; - return instance; - } - - public getFrontendEnvironmentType(): FrontendEnvironmentType { - return this.environment; - } - - public getIsLocalDev(): boolean { - return this.isLocalDev; - } - - private constructor(environment: FrontendEnvironmentType, isLocalDev: boolean) { - this.environment = environment; - this.isLocalDev = isLocalDev; - } -} - -export function GetFrontendEnvironment() : FrontendEnvironment { - return FrontendEnvironment.getInstance(); -} diff --git a/frontend/apps/editor3d/app/src/api/GetCdnOrigin.ts b/frontend/apps/editor3d/app/src/api/GetCdnOrigin.ts index 80376dd74a..79e16f250c 100644 --- a/frontend/apps/editor3d/app/src/api/GetCdnOrigin.ts +++ b/frontend/apps/editor3d/app/src/api/GetCdnOrigin.ts @@ -1,4 +1,4 @@ -import { GetFrontendEnvironment } from "~/Classes/GetFrontendEnvironment"; +// TODO(bt,2025-05-15): Remove this code /** * Return the CDN origin (scheme + host + optional port, but no path) @@ -15,16 +15,9 @@ class CdnHostHelper { return CdnHostHelper.instance; } - const isLocalDev = GetFrontendEnvironment().getIsLocalDev(); - - let origin; - if (isLocalDev) { - //origin = 'https://pub-c8a4a5bdbdb048f286b77bdf9f786ff2.r2.dev'; - origin = 'https://cdn-2.fakeyou.com'; - } else { - origin = 'https://cdn-2.fakeyou.com'; - } + const origin = 'https://cdn-2.fakeyou.com'; const instance = new CdnHostHelper(origin); + CdnHostHelper.instance = instance; return instance; } diff --git a/frontend/apps/editor3d/app/src/pages/PageEnigma/Editor/scene.ts b/frontend/apps/editor3d/app/src/pages/PageEnigma/Editor/scene.ts index f2da3118bd..d25abed154 100644 --- a/frontend/apps/editor3d/app/src/pages/PageEnigma/Editor/scene.ts +++ b/frontend/apps/editor3d/app/src/pages/PageEnigma/Editor/scene.ts @@ -1,9 +1,6 @@ import * as THREE from "three"; import { GLTFLoader, GLTF } from "three/addons/loaders/GLTFLoader.js"; import { MMDLoader } from "three/addons/loaders/MMDLoader.js"; - -import environmentVariables from "~/Classes/EnvironmentVariables"; - import { Font } from "three/examples/jsm/loaders/FontLoader.js"; import { generateUUID } from "three/src/math/MathUtils.js"; import { LoadingPlaceHolderManager } from "./placeholder_manager"; @@ -13,8 +10,6 @@ import { ChromaKeyMaterial } from "./chromakey"; import { TimeLine } from "./timeline"; import { ClipGroup, ClipType } from "~/enums"; import { ClipUI } from "../clips/clip_ui"; -import { GetCdnOrigin } from "~/api/GetCdnOrigin"; -import { GetFrontendEnvironment } from "~/Classes/GetFrontendEnvironment"; import { gridVisibility } from "../signals/engine"; import { InfiniteGridHelper } from "./InfiniteGridHelper"; import { cameras, selectedCameraId } from "../signals/camera"; @@ -382,10 +377,7 @@ class Scene { cameraConfig.position.z, ); - // TODO(bt,2025-02-10): Make the local dev assets more configurable or seedable. - const camera_id = GetFrontendEnvironment().getIsLocalDev() - ? "m_cxh4asqhapdz10j880755dg4yevshb" // Local development - : "m_cxh4asqhapdz10j880755dg4yevshb"; // Production + const camera_id = "m_cxh4asqhapdz10j880755dg4yevshb"; this.loadGlbWithPlaceholder( camera_id, diff --git a/frontend/apps/editor3d/app/src/pages/PageEnigma/signals/demoAssets/demoAnimationItems.ts b/frontend/apps/editor3d/app/src/pages/PageEnigma/signals/demoAssets/demoAnimationItems.ts index 365869f637..39320c31c2 100644 --- a/frontend/apps/editor3d/app/src/pages/PageEnigma/signals/demoAssets/demoAnimationItems.ts +++ b/frontend/apps/editor3d/app/src/pages/PageEnigma/signals/demoAssets/demoAnimationItems.ts @@ -1,5 +1,4 @@ import { signal } from "@preact/signals-core"; -import { GetFrontendEnvironment } from "~/Classes/GetFrontendEnvironment"; import { AssetType } from "~/enums"; import { MediaItem } from "~/pages/PageEnigma/models"; @@ -26,9 +25,7 @@ export const demoAnimationItems = signal([ }, { version: 1, - media_id: GetFrontendEnvironment().getIsLocalDev() ? - "m_z0wj1rckcsea1sb0ht27m41g2w4zss" : // Local development - "m_s7d4ems68sb2vqj4pdje1rc15q3ycp", // Production + media_id: "m_s7d4ems68sb2vqj4pdje1rc15q3ycp", type: AssetType.ANIMATION, length: 100, name: "Walk", diff --git a/frontend/apps/editor3d/app/src/pages/PageEnigma/signals/demoAssets/demoCharacterItems.ts b/frontend/apps/editor3d/app/src/pages/PageEnigma/signals/demoAssets/demoCharacterItems.ts index bdcfd8fbae..e1ba2f42b1 100644 --- a/frontend/apps/editor3d/app/src/pages/PageEnigma/signals/demoAssets/demoCharacterItems.ts +++ b/frontend/apps/editor3d/app/src/pages/PageEnigma/signals/demoAssets/demoCharacterItems.ts @@ -1,14 +1,11 @@ import { signal } from "@preact/signals-core"; import { MediaItem } from "~/pages/PageEnigma/models"; import { AssetType } from "~/enums"; -import { GetFrontendEnvironment } from "~/Classes/GetFrontendEnvironment"; export const demoCharacterItems = signal([ { version: 1, - media_id: GetFrontendEnvironment().getIsLocalDev() ? - "m_8dvne30awgsyrb45xvha9f23gtgg8w" : // Local development - "m_gff67btr810vg3ng9szj85zskztcgy", // Production + media_id: "m_gff67btr810vg3ng9szj85zskztcgy", type: AssetType.CHARACTER, name: "Story Girl", thumbnail: "/resources/characters/img13.png", diff --git a/frontend/apps/editor3d/tsconfig.json b/frontend/apps/editor3d/tsconfig.json index a5421155f0..b89dbb548a 100644 --- a/frontend/apps/editor3d/tsconfig.json +++ b/frontend/apps/editor3d/tsconfig.json @@ -84,6 +84,9 @@ }, { "path": "../../libs/tauri-utils" + }, + { + "path": "../../libs/build-env" } ] } diff --git a/frontend/libs/api/src/lib/GetCdnOrigin.ts b/frontend/libs/api/src/lib/GetCdnOrigin.ts index 5d604bc745..132c39e58c 100644 --- a/frontend/libs/api/src/lib/GetCdnOrigin.ts +++ b/frontend/libs/api/src/lib/GetCdnOrigin.ts @@ -1,45 +1,4 @@ -// import { GetFrontendEnvironment } from "~/Classes/GetFrontendEnvironment"; - -/** - * Return the CDN origin (scheme + host + optional port, but no path) - * See: https://web.dev/articles/url-parts - * - * TODO(bt,2025-02-10): Make this easier to configure in development - */ -// class CdnHostHelper { -// private static instance: CdnHostHelper; -// private readonly origin: string; - -// public static getInstance(): CdnHostHelper { -// if (CdnHostHelper.instance !== undefined) { -// return CdnHostHelper.instance; -// } - -// const isLocalDev = GetFrontendEnvironment().getIsLocalDev(); - -// let origin; -// if (isLocalDev) { -// //origin = 'https://pub-c8a4a5bdbdb048f286b77bdf9f786ff2.r2.dev'; -// origin = "https://cdn-2.fakeyou.com"; -// } else { -// origin = "https://cdn-2.fakeyou.com"; -// } -// const instance = new CdnHostHelper(origin); -// CdnHostHelper.instance = instance; -// return instance; -// } - -// public getOrigin(): string { -// return this.origin; -// } - -// private constructor(origin: string) { -// this.origin = origin; -// } -// } - -// TODO(bt,2025-02-10): Consolidate all of this logic. +// TODO(bt,2025-05-15): Remove this code export function GetCdnOrigin(): string { - // return CdnHostHelper.getInstance().getOrigin(); return "https://cdn-2.fakeyou.com"; } diff --git a/frontend/libs/build-env/.babelrc b/frontend/libs/build-env/.babelrc new file mode 100644 index 0000000000..1ea870ead4 --- /dev/null +++ b/frontend/libs/build-env/.babelrc @@ -0,0 +1,12 @@ +{ + "presets": [ + [ + "@nx/react/babel", + { + "runtime": "automatic", + "useBuiltIns": "usage" + } + ] + ], + "plugins": [] +} diff --git a/frontend/libs/build-env/README.md b/frontend/libs/build-env/README.md new file mode 100644 index 0000000000..9becded76e --- /dev/null +++ b/frontend/libs/build-env/README.md @@ -0,0 +1,7 @@ +# @frontend/build-env + +This library was generated with [Nx](https://nx.dev). + +## Running unit tests + +Run `nx test @frontend/build-env` to execute the unit tests via [Vitest](https://vitest.dev/). diff --git a/frontend/libs/build-env/package.json b/frontend/libs/build-env/package.json new file mode 100644 index 0000000000..8712e95b42 --- /dev/null +++ b/frontend/libs/build-env/package.json @@ -0,0 +1,17 @@ +{ + "name": "@frontend/build-env", + "version": "0.0.1", + "type": "module", + "main": "./dist/index.js", + "module": "./dist/index.js", + "types": "./dist/index.d.ts", + "exports": { + "./package.json": "./package.json", + ".": { + "development": "./src/index.ts", + "types": "./dist/index.d.ts", + "import": "./dist/index.js", + "default": "./dist/index.js" + } + } +} diff --git a/frontend/libs/build-env/src/index.ts b/frontend/libs/build-env/src/index.ts new file mode 100644 index 0000000000..383df5f16d --- /dev/null +++ b/frontend/libs/build-env/src/index.ts @@ -0,0 +1,3 @@ + +export * from './lib/BuildEnv'; +export * from './lib/BuildEnvType'; diff --git a/frontend/libs/build-env/src/lib/BuildEnv.ts b/frontend/libs/build-env/src/lib/BuildEnv.ts new file mode 100644 index 0000000000..983923e3fa --- /dev/null +++ b/frontend/libs/build-env/src/lib/BuildEnv.ts @@ -0,0 +1,30 @@ +import { BuildEnvType, GetBuildEnvType } from "./BuildEnvType"; + +export class BuildEnv { + private static instance: BuildEnv; + private readonly envType: BuildEnvType; + + public static getInstance(): BuildEnv { + if (BuildEnv.instance !== undefined) { + return BuildEnv.instance; + } + + const envType = GetBuildEnvType(); + const instance = new BuildEnv(envType); + BuildEnv.instance = instance; + + return instance; + } + + public getType(): BuildEnvType { + return this.envType; + } + + private constructor(envType: BuildEnvType) { + this.envType = envType; + } +} + +export function GetBuildEnv() : BuildEnv { + return BuildEnv.getInstance(); +} diff --git a/frontend/libs/build-env/src/lib/BuildEnvType.ts b/frontend/libs/build-env/src/lib/BuildEnvType.ts new file mode 100644 index 0000000000..9ea80ecd06 --- /dev/null +++ b/frontend/libs/build-env/src/lib/BuildEnvType.ts @@ -0,0 +1,61 @@ + +/** + * This is cached whenever vite/remix launches or CI/CD bakes in constants. + * It's fed from an environment variable. + */ +export enum BuildEnvType { + Dev, + DevProxy, + Staging, + Production, +} + +// Use CI/CD to replace this value with one of the BuildEnvType values. +const BUILD_ENV_TYPE = '%BUILD_ENV_TYPE_VALUE%'; + +// Attempt to read the environment type. +export function GetBuildEnvType() : BuildEnvType { + let maybeEnvType : BuildEnvType | undefined = undefined; + + if (!BUILD_ENV_TYPE.startsWith("%") && !BUILD_ENV_TYPE.endsWith("%")) { + maybeEnvType = stringToEnvType(BUILD_ENV_TYPE); + if (maybeEnvType !== undefined) { + return maybeEnvType; + } + } + + if (import.meta.env.BUILD_ENV_TYPE !== undefined) { + console.log(`Reading environment variable 'BUILD_ENV_TYPE' (= ${import.meta.env.BUILD_ENV_TYPE}) to determine build environment.`) + maybeEnvType = stringToEnvType(import.meta.env.BUILD_ENV_TYPE); + if (maybeEnvType !== undefined) { + return maybeEnvType; + } + } + + if (import.meta.env.VITE_ENVIRONMENT_TYPE !== undefined) { + console.log(`Reading legacy environment variable 'VITE_ENVIRONMENT_TYPE' (= ${import.meta.env.VITE_ENVIRONMENT_TYPE}) to determine build environment.`) + maybeEnvType = stringToEnvType(import.meta.env.VITE_ENVIRONMENT_TYPE); + if (maybeEnvType !== undefined) { + return maybeEnvType; + } + } + + // Always default to production. + return BuildEnvType.Production; +} + +function stringToEnvType(str: string): BuildEnvType | undefined { + switch (str.toLocaleLowerCase()) { + case "dev": + case "development": + return BuildEnvType.Dev; + case "dev-proxy": + case "devproxy": + return BuildEnvType.DevProxy; + case "stage": + case "staging": + return BuildEnvType.Staging; + default: + return undefined; + } +} diff --git a/frontend/libs/build-env/tsconfig.json b/frontend/libs/build-env/tsconfig.json new file mode 100644 index 0000000000..8c5fc025ff --- /dev/null +++ b/frontend/libs/build-env/tsconfig.json @@ -0,0 +1,13 @@ +{ + "files": [], + "include": [], + "references": [ + { + "path": "./tsconfig.lib.json" + }, + { + "path": "./tsconfig.spec.json" + } + ], + "extends": "../../tsconfig.base.json" +} diff --git a/frontend/libs/build-env/tsconfig.lib.json b/frontend/libs/build-env/tsconfig.lib.json new file mode 100644 index 0000000000..ea31c66850 --- /dev/null +++ b/frontend/libs/build-env/tsconfig.lib.json @@ -0,0 +1,45 @@ +{ + "extends": "../../tsconfig.base.json", + "compilerOptions": { + "outDir": "dist", + "types": [ + "node", + "@nx/react/typings/cssmodule.d.ts", + "@nx/react/typings/image.d.ts", + "vite/client" + ], + "rootDir": "src", + "jsx": "react-jsx", + "tsBuildInfoFile": "dist/tsconfig.lib.tsbuildinfo" + }, + "exclude": [ + "out-tsc", + "dist", + "**/*.spec.ts", + "**/*.test.ts", + "**/*.spec.tsx", + "**/*.test.tsx", + "**/*.spec.js", + "**/*.test.js", + "**/*.spec.jsx", + "**/*.test.jsx", + "vite.config.ts", + "vite.config.mts", + "vitest.config.ts", + "vitest.config.mts", + "src/**/*.test.ts", + "src/**/*.spec.ts", + "src/**/*.test.tsx", + "src/**/*.spec.tsx", + "src/**/*.test.js", + "src/**/*.spec.js", + "src/**/*.test.jsx", + "src/**/*.spec.jsx" + ], + "include": [ + "src/**/*.js", + "src/**/*.jsx", + "src/**/*.ts", + "src/**/*.tsx" + ] +} diff --git a/frontend/libs/build-env/tsconfig.spec.json b/frontend/libs/build-env/tsconfig.spec.json new file mode 100644 index 0000000000..c1faced82c --- /dev/null +++ b/frontend/libs/build-env/tsconfig.spec.json @@ -0,0 +1,34 @@ +{ + "extends": "../../tsconfig.base.json", + "compilerOptions": { + "outDir": "./out-tsc/vitest", + "types": [ + "vitest/globals", + "vitest/importMeta", + "vite/client", + "node", + "vitest" + ], + "jsx": "react-jsx" + }, + "include": [ + "vite.config.ts", + "vite.config.mts", + "vitest.config.ts", + "vitest.config.mts", + "src/**/*.test.ts", + "src/**/*.spec.ts", + "src/**/*.test.tsx", + "src/**/*.spec.tsx", + "src/**/*.test.js", + "src/**/*.spec.js", + "src/**/*.test.jsx", + "src/**/*.spec.jsx", + "src/**/*.d.ts" + ], + "references": [ + { + "path": "./tsconfig.lib.json" + } + ] +} diff --git a/frontend/libs/build-env/vite.config.ts b/frontend/libs/build-env/vite.config.ts new file mode 100644 index 0000000000..577c9d15f1 --- /dev/null +++ b/frontend/libs/build-env/vite.config.ts @@ -0,0 +1,49 @@ +/// +import { defineConfig } from 'vite'; +import react from '@vitejs/plugin-react'; +import dts from 'vite-plugin-dts'; +import * as path from 'path'; + +export default defineConfig(() => ({ + root: __dirname, + cacheDir: '../../node_modules/.vite/libs/build-env', + plugins: [react(), dts({ entryRoot: 'src', tsconfigPath: path.join(__dirname, 'tsconfig.lib.json') })], + // Uncomment this if you are using workers. + // worker: { + // plugins: [ nxViteTsPaths() ], + // }, + // Configuration for building your library. + // See: https://vitejs.dev/guide/build.html#library-mode + build: { + outDir: './dist', + emptyOutDir: true, + reportCompressedSize: true, + commonjsOptions: { + transformMixedEsModules: true, + }, + lib: { + // Could also be a dictionary or array of multiple entry points. + entry: 'src/index.ts', + name: '@frontend/build-env', + fileName: 'index', + // Change this to the formats you want to support. + // Don't forget to update your package.json as well. + formats: ['es' as const] + }, + rollupOptions: { + // External packages that should not be bundled into your library. + external: ['react','react-dom','react/jsx-runtime'] + }, + }, + test: { + watch: false, + globals: true, + environment: 'jsdom', + include: ['{src,tests}/**/*.{test,spec}.{js,mjs,cjs,ts,mts,cts,jsx,tsx}'], + reporters: ['default'], + coverage: { + reportsDirectory: './test-output/vitest/coverage', + provider: 'v8' as const, + } + }, +})); diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 6203d8cd54..051e606855 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -2187,6 +2187,10 @@ "@tauri-apps/plugin-upload": "2.2.1" } }, + "libs/build-env": { + "name": "@frontend/build-env", + "version": "0.0.1" + }, "libs/common": { "name": "@storyteller/common", "version": "0.0.1" @@ -5020,6 +5024,10 @@ "resolved": "apps/artcraft-website", "link": true }, + "node_modules/@frontend/build-env": { + "resolved": "libs/build-env", + "link": true + }, "node_modules/@frontend/login": { "resolved": "libs/login", "link": true diff --git a/frontend/tsconfig.json b/frontend/tsconfig.json index 3c6736b982..ab379e6875 100644 --- a/frontend/tsconfig.json +++ b/frontend/tsconfig.json @@ -89,6 +89,9 @@ }, { "path": "./libs/components/switch" + }, + { + "path": "./libs/build-env" } ] }