From a2931839014317bb005bf0ff94664e9960dfd592 Mon Sep 17 00:00:00 2001 From: Gigin George Date: Sat, 11 Jan 2025 09:47:59 +0530 Subject: [PATCH] Update Care Apps Setup; API URL on window (#9883) --- .env | 6 +- scripts/setup-care-apps.ts | 82 ++++++++++++++++++------ src/index.tsx | 10 +++ vite.config.mts | 126 ++++++++++++++++--------------------- 4 files changed, 131 insertions(+), 93 deletions(-) diff --git a/.env b/.env index 4e9159b2bf0..4928b31e2ba 100644 --- a/.env +++ b/.env @@ -14,4 +14,8 @@ ESLINT_NO_DEV_ERRORS=true CARE_CDN_URL="https://egov-s3-facility-10bedicu.s3.amazonaws.com https://egov-s3-patient-data-10bedicu.s3.amazonaws.com http://localhost:4566" REACT_ALLOWED_LOCALES="en,hi,ta,ml,mr,kn" -REACT_ENABLED_APPS="https://care-scribe-fe.pages.dev|ohcnetwork/care_scribe_fe" +# Remote apps +# Localhost : ohcnetwork/care_scribe_fe@localhost:4173 +# Remote URL : ohcnetwork/care_scribe_fe@https://care-scribe-fe.pages.dev +# Repo/Github Pages : ohcnetwork/care_scribe_fe +REACT_ENABLED_APPS="" diff --git a/scripts/setup-care-apps.ts b/scripts/setup-care-apps.ts index c1e8896644d..f03c07f6cad 100644 --- a/scripts/setup-care-apps.ts +++ b/scripts/setup-care-apps.ts @@ -16,28 +16,70 @@ interface Plugin { camelCaseName: string; } +interface ParsedRemoteConfig { + url: string; + org: string; + repo: string; +} + +/** + * Parses a remote app configuration string into its components + * Supports two formats: + * 1. GitHub Pages: "organization/repository" + * Example: "coronasafe/care_fe" + * + * 2. Custom URL: "organization/repository@url" + * Example: "coronasafe/care_fe@localhost:5173" + * Example: "coronasafe/care_fe@care.coronasafe.network" + * Note: Protocol (http/https) is automatically added in the vite config: + * - localhost URLs use http:// + * - all other URLs use https:// + * + * @param appConfig - Configuration string for a remote app + * @returns Parsed configuration object + */ +function parseRemoteConfig(appConfig: string): ParsedRemoteConfig { + // Handle custom URLs (both localhost and custom hosted) + if (appConfig.includes("@")) { + const [package_] = appConfig.split("@"); + const [org, repo] = package_.split("/"); + return { + url: "", // URL not needed for plugin setup + org, + repo, + }; + } + + // Handle GitHub Pages URLs + const [org, repo] = appConfig.split("/"); + return { + url: "", // URL not needed for plugin setup + org, + repo, + }; +} + // Function to read enabled apps from env function readAppsConfig(): Plugin[] { - const appsConfig = process.env.REACT_ENABLED_APPS - ? process.env.REACT_ENABLED_APPS.split(",").map((app) => { - const package_ = app.includes("|") - ? app.split("|")[1].split("@")[0] - : app.split("@")[0]; - console.log(package_); - const [, repo] = package_.split("/"); - return { - repo, - // Convert repo name to camelCase for import - camelCaseName: repo - .replace(/[-_]/g, "") - .replace(/\b\w/g, (char, index) => - index === 0 ? char.toLowerCase() : char.toUpperCase(), - ), - }; - }) - : []; - console.log("Found plugins: ", appsConfig); - return appsConfig; + if (!process.env.REACT_ENABLED_APPS) { + return []; + } + + const plugins = process.env.REACT_ENABLED_APPS.split(",").map((app) => { + const { repo } = parseRemoteConfig(app); + return { + repo, + // Convert repo name to camelCase for import + camelCaseName: repo + .replace(/[-_]/g, "") + .replace(/\b\w/g, (char, index) => + index === 0 ? char.toLowerCase() : char.toUpperCase(), + ), + }; + }); + + console.log("Found plugins:", plugins); + return plugins; } const plugins = readAppsConfig(); diff --git a/src/index.tsx b/src/index.tsx index cfef8691acb..31f3787f9e5 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -6,6 +6,16 @@ import App from "@/App"; import "@/i18n"; import "@/style/index.css"; +// Extend Window interface to include CARE_API_URL +declare global { + interface Window { + CARE_API_URL: string; + } +} + +// Set API URL from environment variable +window.CARE_API_URL = import.meta.env.REACT_CARE_API_URL; + if ("serviceWorker" in navigator) { registerSW({ immediate: false }); } diff --git a/vite.config.mts b/vite.config.mts index bfa39919163..31f31f90995 100644 --- a/vite.config.mts +++ b/vite.config.mts @@ -60,66 +60,70 @@ function getPluginAliases() { return aliases; } -function getPluginDependencies(): string[] { - const pluginsDir = path.resolve(__dirname, "apps"); - // Make sure the `apps` folder exists - if (!fs.existsSync(pluginsDir)) { - return []; - } - const pluginFolders = fs.readdirSync(pluginsDir); - - const dependencies = new Set(); - - pluginFolders.forEach((pluginFolder) => { - const packageJsonPath = path.join(pluginsDir, pluginFolder, "package.json"); - if (fs.existsSync(packageJsonPath)) { - const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, "utf8")); - const pluginDependencies = packageJson.dependencies - ? Object.keys(packageJson.dependencies) - : []; - pluginDependencies.forEach((dep) => dependencies.add(dep)); - } - }); - - return Array.from(dependencies); +/** + * Parses a remote app configuration string into its components + * @param appConfig - Configuration string for a remote app + * @returns Parsed configuration object + */ +interface ParsedRemoteConfig { + url: string; + org: string; + repo: string; } -// Recursive function to check if the module is statically imported by an entry point -function isStaticallyImportedByEntry( - getModuleInfo: (moduleId: string) => any, - moduleId: string, - visited = new Set(), -) { - if (visited.has(moduleId)) return false; - visited.add(moduleId); - - const modInfo = getModuleInfo(moduleId); - if (!modInfo) return false; - - // Check if the module is an entry point - if (modInfo.isEntry) { - return true; +function parseRemoteConfig(appConfig: string): ParsedRemoteConfig { + if (!appConfig.includes("/")) { + throw new Error( + `Invalid app configuration format: ${appConfig}. Expected 'org/repo' or 'org/repo@url'.`, + ); } - - // Check all static importers - for (const importerId of modInfo.importers) { - if (isStaticallyImportedByEntry(getModuleInfo, importerId, visited)) { - return true; + // Handle custom URLs (both localhost and custom hosted) + if (appConfig.includes("@")) { + const [package_, url] = appConfig.split("@"); + const [org, repo] = package_.split("/"); + if (!org || !repo || !url) { + throw new Error( + `Invalid custom URL configuration: ${appConfig}. Expected 'org/repo@url'.`, + ); } + // Add appropriate protocol based on whether it's localhost + const protocol = url.includes("localhost") ? "http://" : "https://"; + const fullUrl = url.startsWith("http") ? url : `${protocol}${url}`; + + return { + url: `${fullUrl}/assets/remoteEntry.js`, + org, + repo, + }; } - return false; + // Handle GitHub Pages URLs + const [org, repo] = appConfig.split("/"); + if (!org || !repo) { + throw new Error( + `Invalid GitHub Pages configuration: ${appConfig}. Expected 'org/repo'.`, + ); + } + return { + url: `https://${org}.github.io/${repo}/assets/remoteEntry.js`, + org, + repo, + }; } /** * Generates remote module configurations for Module Federation * * Supports two formats for REACT_ENABLED_APPS: - * 1. GitHub Pages: "organization/repository[@branch]" - * Example: "coronasafe/care_fe@main" + * 1. GitHub Pages: "organization/repository" + * Example: "coronasafe/care_fe" * - * 2. Custom URL: "prot://localhost:port|organization/repository[@branch]" - * Example: "http://localhost:5173|coronasafe/care_fe@main" + * 2. Custom URL: "organization/repository@url" + * Example: "coronasafe/care_fe@localhost:5173" + * Example: "coronasafe/care_fe@care.coronasafe.network" + * Note: Protocol (http/https) is automatically added based on the URL: + * - localhost URLs use http:// + * - all other URLs use https:// * * @param enabledApps - Comma-separated list of enabled apps * @returns Remote module configuration object for Module Federation @@ -128,35 +132,13 @@ function getRemotes(enabledApps: string) { if (!enabledApps) return {}; return enabledApps.split(",").reduce((acc, app) => { - const [package_, branch = "main"] = app.split("@"); + const { repo, url } = parseRemoteConfig(app); + console.log(`Configuring Remote Module for ${repo}:`, url); - // Handle custom URLs - if ((package_.includes("|"))) { - const [host, pathParts] = package_.split("|"); - const [org, repo] = pathParts.split("/"); - const remoteUrl = `"${host}/assets/remoteEntry.js"`; - console.log(`Using Local Remote Module for ${org}/${repo}:`, remoteUrl); - return { - ...acc, - [repo]: { - external: `Promise.resolve(${remoteUrl})`, - from: "vite", - externalType: "promise", - }, - }; - } - - // Handle GitHub Pages URLs - const [org, repo] = package_.split("/"); - const remoteUrl = `"https://${org}.github.io/${repo}/assets/remoteEntry.js"`; - console.log( - `Using GitHub Pages Remote Module for ${org}/${repo}:`, - remoteUrl, - ); return { ...acc, [repo]: { - external: `Promise.resolve(${remoteUrl})`, + external: `Promise.resolve("${url}")`, from: "vite", externalType: "promise", },