From 6d2a4037828e485cca6d5c66b51ef00e8c03f45f Mon Sep 17 00:00:00 2001 From: Vasyl Ivanchuk Date: Fri, 3 Nov 2023 11:02:21 +0200 Subject: [PATCH] feat: app to support realtime environment config (#78) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit # What ❔ Adjust app so it supports realtime environment config ## Why ❔ We need this feature to set different app configs from the CLI ## Checklist - [X] PR title corresponds to the body of PR (we generate changelog entries from PRs). - [X] Tests for the changes have been added / updated. --- .../src/composables/useEnvironmentConfig.ts | 14 ++++++--- .../app/src/composables/useRuntimeConfig.ts | 9 ++---- packages/app/src/configs/index.ts | 7 +++++ packages/app/src/main.ts | 8 ++--- .../composables/useEnvironmentConfig.spec.ts | 30 +++++++++++++++++-- 5 files changed, 51 insertions(+), 17 deletions(-) diff --git a/packages/app/src/composables/useEnvironmentConfig.ts b/packages/app/src/composables/useEnvironmentConfig.ts index 975be18e20..0bf3c76df6 100644 --- a/packages/app/src/composables/useEnvironmentConfig.ts +++ b/packages/app/src/composables/useEnvironmentConfig.ts @@ -1,22 +1,28 @@ import { computed, ref } from "vue"; -import type { EnvironmentConfig, NetworkConfig } from "@/configs"; +import type { EnvironmentConfig, NetworkConfig, RuntimeConfig } from "@/configs"; const config = ref(null); const HYPERCHAIN_CONFIG_NAME = "hyperchain"; const DEVELOPMENT_CONFIG_NAME = "dev"; -export async function loadEnvironmentConfig(appEnvironment: string): Promise { +export async function loadEnvironmentConfig(runtimeConfig: RuntimeConfig): Promise { + // runtime environment config takes precedence over hard coded config + if (runtimeConfig.environmentConfig) { + config.value = runtimeConfig.environmentConfig; + return; + } + let envConfig: EnvironmentConfig; - if (appEnvironment === "default") { + if (runtimeConfig.appEnvironment === "default") { try { envConfig = (await import(`../configs/${HYPERCHAIN_CONFIG_NAME}.config.json`)).default; } catch { envConfig = (await import(`../configs/${DEVELOPMENT_CONFIG_NAME}.config.json`)).default; } } else { - envConfig = (await import(`../configs/${appEnvironment}.config.json`)).default; + envConfig = (await import(`../configs/${runtimeConfig.appEnvironment}.config.json`)).default; } config.value = envConfig; } diff --git a/packages/app/src/composables/useRuntimeConfig.ts b/packages/app/src/composables/useRuntimeConfig.ts index 4be88e0b53..eca6a21706 100644 --- a/packages/app/src/composables/useRuntimeConfig.ts +++ b/packages/app/src/composables/useRuntimeConfig.ts @@ -1,4 +1,4 @@ -import type { NetworkConfig } from "@/configs"; +import type { NetworkConfig, RuntimeConfig } from "@/configs"; export const DEFAULT_NETWORK: NetworkConfig = { apiUrl: "https://block-explorer-api.testnets.zksync.dev", @@ -17,11 +17,7 @@ export const DEFAULT_NETWORK: NetworkConfig = { rpcUrl: "https://testnet.era.zksync.dev", }; -export default (): { - version: string; - sentryDSN: string; - appEnvironment: string; -} => { +export default (): RuntimeConfig => { // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore const runtimeConfig = window && window["##runtimeConfig"]; @@ -30,5 +26,6 @@ export default (): { version: import.meta.env?.VITE_VERSION || "localhost", sentryDSN: runtimeConfig?.sentryDSN || import.meta.env?.VITE_SENTRY_DSN, appEnvironment: runtimeConfig?.appEnvironment || import.meta.env?.VITE_APP_ENVIRONMENT || "default", + environmentConfig: runtimeConfig?.environmentConfig, }; }; diff --git a/packages/app/src/configs/index.ts b/packages/app/src/configs/index.ts index 61c9caf166..3856403daf 100644 --- a/packages/app/src/configs/index.ts +++ b/packages/app/src/configs/index.ts @@ -18,3 +18,10 @@ export type NetworkConfig = { export type EnvironmentConfig = { networks: NetworkConfig[]; }; + +export type RuntimeConfig = { + version: string; + sentryDSN: string; + appEnvironment: string; + environmentConfig?: EnvironmentConfig; +}; diff --git a/packages/app/src/main.ts b/packages/app/src/main.ts index 428c2ad9ab..377d449e50 100644 --- a/packages/app/src/main.ts +++ b/packages/app/src/main.ts @@ -35,7 +35,7 @@ const i18n = createI18n<[MessageSchema], "en">({ app.use(router); app.use(i18n); app.use(testId); -const config = useRuntimeConfig(); +const runtimeConfig = useRuntimeConfig(); const context = useContext(); @@ -50,11 +50,11 @@ const { initialize: initializeWallet } = useWallet({ }); initializeWallet(); -if (config.sentryDSN?.length) { - useSentry(app, config.sentryDSN, config.appEnvironment, config.version, router); +if (runtimeConfig.sentryDSN?.length) { + useSentry(app, runtimeConfig.sentryDSN, runtimeConfig.appEnvironment, runtimeConfig.version, router); } -(process.env.NODE_ENV === "test" ? Promise.resolve() : loadEnvironmentConfig(config.appEnvironment)) +(process.env.NODE_ENV === "test" ? Promise.resolve() : loadEnvironmentConfig(runtimeConfig)) .catch(() => null) .then(context.identifyNetwork); diff --git a/packages/app/tests/composables/useEnvironmentConfig.spec.ts b/packages/app/tests/composables/useEnvironmentConfig.spec.ts index da7d407bcf..4b5e6d2191 100644 --- a/packages/app/tests/composables/useEnvironmentConfig.spec.ts +++ b/packages/app/tests/composables/useEnvironmentConfig.spec.ts @@ -4,6 +4,8 @@ import { GOERLI_BETA_NETWORK, GOERLI_NETWORK } from "../mocks"; import useEnvironmentConfig, { loadEnvironmentConfig } from "@/composables/useEnvironmentConfig"; +import type { RuntimeConfig } from "@/configs"; + vi.mock("../../src/configs/local.config", () => { return { default: { @@ -39,20 +41,42 @@ describe("useEnvironmentConfig:", () => { describe("loadEnvironmentConfig", () => { it("sets networks data to config", async () => { const { networks } = useEnvironmentConfig(); - await loadEnvironmentConfig("local"); + await loadEnvironmentConfig({ appEnvironment: "local" } as RuntimeConfig); expect(networks.value).toEqual([GOERLI_BETA_NETWORK, GOERLI_NETWORK]); }); + + it("sets networks to values from runtime config if specified", async () => { + const runtimeConfig = { + environmentConfig: { + networks: [ + { + name: "runtime network", + published: true, + }, + ], + }, + appEnvironment: "local", + } as RuntimeConfig; + const { networks } = useEnvironmentConfig(); + await loadEnvironmentConfig(runtimeConfig); + expect(networks.value).toEqual([ + { + name: "runtime network", + published: true, + }, + ]); + }); }); describe("networks", () => { it("returns empty array when networks are not defined", async () => { const { networks } = useEnvironmentConfig(); - await loadEnvironmentConfig("production"); + await loadEnvironmentConfig({ appEnvironment: "production" } as RuntimeConfig); expect(networks.value).toEqual([]); }); it("returns only published network configs", async () => { const { networks } = useEnvironmentConfig(); - await loadEnvironmentConfig("staging"); + await loadEnvironmentConfig({ appEnvironment: "staging" } as RuntimeConfig); expect(networks.value).toEqual([GOERLI_BETA_NETWORK]); }); });