From 902bdd0085218fab86e4a1cacba7b29900b2169d Mon Sep 17 00:00:00 2001 From: Artem Alexeyenko Date: Tue, 17 Jan 2023 17:17:20 -0500 Subject: [PATCH 1/5] dynamic config value evaluation at build time --- .../scripts/config/plugins/multisite.ts | 13 ++++++++++++- .../src/templates/nextjs/scripts/config/index.ts | 6 ++++-- .../nextjs/scripts/config/plugins/computed.ts | 2 +- .../src/templates/nextjs/scripts/generate-config.ts | 9 ++++++++- 4 files changed, 25 insertions(+), 5 deletions(-) diff --git a/packages/create-sitecore-jss/src/templates/nextjs-multisite/scripts/config/plugins/multisite.ts b/packages/create-sitecore-jss/src/templates/nextjs-multisite/scripts/config/plugins/multisite.ts index c9baf1bcf7..3d13d3bb4c 100644 --- a/packages/create-sitecore-jss/src/templates/nextjs-multisite/scripts/config/plugins/multisite.ts +++ b/packages/create-sitecore-jss/src/templates/nextjs-multisite/scripts/config/plugins/multisite.ts @@ -13,7 +13,18 @@ class MultisitePlugin implements ConfigPlugin { async exec(config: JssConfig) { let sites: SiteInfo[] = []; - const endpoint = process.env.GRAPH_QL_ENDPOINT || config.graphQLEndpoint; + + const computeConfigValue = (val: string) => { + if(val.startsWith('`') && val.endsWith('`')) { + return new Function('return ' + val.replaceAll('config', 'this')).call(config); + } + else { + return val; + } + }; + + // graphQL endpoint can have a dynamic value in the config - so we resolve it in a special way at build time + const buildTimeGraphQlEndpoint = process.env.GRAPH_QL_ENDPOINT || computeConfigValue(config.computed?.graphQLEndpoint || ''); const apiKey = process.env.SITECORE_API_KEY || config.sitecoreApiKey; if (!endpoint || !apiKey) { diff --git a/packages/create-sitecore-jss/src/templates/nextjs/scripts/config/index.ts b/packages/create-sitecore-jss/src/templates/nextjs/scripts/config/index.ts index 425474d0eb..19be2c355c 100644 --- a/packages/create-sitecore-jss/src/templates/nextjs/scripts/config/index.ts +++ b/packages/create-sitecore-jss/src/templates/nextjs/scripts/config/index.ts @@ -4,13 +4,15 @@ const plugins = require('scripts/temp/config-plugins'); /** * JSS configuration object */ -export interface JssConfig extends Record { +export interface JssConfig extends Record | undefined> { sitecoreApiKey?: string; sitecoreApiHost?: string; jssAppName?: string; graphQLEndpointPath?: string; defaultLanguage?: string; - graphQLEndpoint?: string; + computed?: { + [key: string]: string; + } } export interface ConfigPlugin { diff --git a/packages/create-sitecore-jss/src/templates/nextjs/scripts/config/plugins/computed.ts b/packages/create-sitecore-jss/src/templates/nextjs/scripts/config/plugins/computed.ts index dc487ce88b..2dc3c5aa56 100644 --- a/packages/create-sitecore-jss/src/templates/nextjs/scripts/config/plugins/computed.ts +++ b/packages/create-sitecore-jss/src/templates/nextjs/scripts/config/plugins/computed.ts @@ -10,7 +10,7 @@ class ComputedPlugin implements ConfigPlugin { async exec(config: JssConfig) { return Object.assign({}, config, { - graphQLEndpoint: `${config.sitecoreApiHost}${config.graphQLEndpointPath}`, + computed: { graphQLEndpoint: '`${config.sitecoreApiHost}${config.graphQLEndpointPath}`' }, }); } } diff --git a/packages/create-sitecore-jss/src/templates/nextjs/scripts/generate-config.ts b/packages/create-sitecore-jss/src/templates/nextjs/scripts/generate-config.ts index db3a565686..0bb594238c 100644 --- a/packages/create-sitecore-jss/src/templates/nextjs/scripts/generate-config.ts +++ b/packages/create-sitecore-jss/src/templates/nextjs/scripts/generate-config.ts @@ -47,10 +47,17 @@ function writeConfig(config: JssConfig): void { // See scripts/bootstrap.ts to modify the generation of this file. const config = {};\n`; + const staticConfig = {...config, computed: undefined }; + const computedConfig = config.computed; // Set configuration values, allowing override with environment variables - Object.keys(config).forEach((prop) => { + Object.keys(staticConfig).forEach((prop) => { configText += `config.${prop} = process.env.${constantCase(prop)} || '${config[prop]}',\n`; }); + computedConfig && Object.keys(computedConfig).forEach((prop) => { + configText += `config.${prop} = process.env.${constantCase(prop)} || ${ + computedConfig[prop] + };\n`; + }); configText += `module.exports = config;`; const configPath = path.resolve('src/temp/config.js'); From f77a5a82fc881bf2c640bf20781c35930c1ee6a4 Mon Sep 17 00:00:00 2001 From: Artem Alexeyenko Date: Wed, 18 Jan 2023 12:30:39 -0500 Subject: [PATCH 2/5] finalize dynamic and build time config value processing --- .../nextjs-multisite/scripts/config/plugins/multisite.ts | 4 ++-- .../templates/nextjs/scripts/config/plugins/scjssconfig.ts | 6 +++++- .../src/templates/nextjs/scripts/generate-config.ts | 4 ++-- 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/packages/create-sitecore-jss/src/templates/nextjs-multisite/scripts/config/plugins/multisite.ts b/packages/create-sitecore-jss/src/templates/nextjs-multisite/scripts/config/plugins/multisite.ts index 3d13d3bb4c..b3669d7da2 100644 --- a/packages/create-sitecore-jss/src/templates/nextjs-multisite/scripts/config/plugins/multisite.ts +++ b/packages/create-sitecore-jss/src/templates/nextjs-multisite/scripts/config/plugins/multisite.ts @@ -24,12 +24,12 @@ class MultisitePlugin implements ConfigPlugin { }; // graphQL endpoint can have a dynamic value in the config - so we resolve it in a special way at build time - const buildTimeGraphQlEndpoint = process.env.GRAPH_QL_ENDPOINT || computeConfigValue(config.computed?.graphQLEndpoint || ''); + const endpoint = process.env.GRAPH_QL_ENDPOINT || computeConfigValue(config.computed?.graphQLEndpoint || ''); const apiKey = process.env.SITECORE_API_KEY || config.sitecoreApiKey; if (!endpoint || !apiKey) { console.warn( - chalk.yellow('Skipping site information fetch (missing GraphQL connection details)') + chalk.yellow('Skipping site information fetch (missing GraphQL connection details). Endpoint or API key missing.') ); } else { console.log(`Fetching site information from ${endpoint}`); diff --git a/packages/create-sitecore-jss/src/templates/nextjs/scripts/config/plugins/scjssconfig.ts b/packages/create-sitecore-jss/src/templates/nextjs/scripts/config/plugins/scjssconfig.ts index 4967161658..0484e1d5a3 100644 --- a/packages/create-sitecore-jss/src/templates/nextjs/scripts/config/plugins/scjssconfig.ts +++ b/packages/create-sitecore-jss/src/templates/nextjs/scripts/config/plugins/scjssconfig.ts @@ -13,7 +13,11 @@ class ScJssConfigPlugin implements ConfigPlugin { try { scJssConfig = require('scjssconfig.json'); } catch (e) { - return config; + // fall back on env values + return Object.assign({}, config, { + sitecoreApiKey: process.env.SITECORE_API_KEY, + sitecoreApiHost: process.env.SITECORE_API_HOST, + }); } if (!scJssConfig) return config; diff --git a/packages/create-sitecore-jss/src/templates/nextjs/scripts/generate-config.ts b/packages/create-sitecore-jss/src/templates/nextjs/scripts/generate-config.ts index 0bb594238c..6c1f4e0394 100644 --- a/packages/create-sitecore-jss/src/templates/nextjs/scripts/generate-config.ts +++ b/packages/create-sitecore-jss/src/templates/nextjs/scripts/generate-config.ts @@ -47,10 +47,10 @@ function writeConfig(config: JssConfig): void { // See scripts/bootstrap.ts to modify the generation of this file. const config = {};\n`; - const staticConfig = {...config, computed: undefined }; const computedConfig = config.computed; + delete config['computed']; // Set configuration values, allowing override with environment variables - Object.keys(staticConfig).forEach((prop) => { + Object.keys(config).forEach((prop) => { configText += `config.${prop} = process.env.${constantCase(prop)} || '${config[prop]}',\n`; }); computedConfig && Object.keys(computedConfig).forEach((prop) => { From f60fbd55605ec4397b5c66d0b0d98bb878a7a505 Mon Sep 17 00:00:00 2001 From: Artem Alexeyenko Date: Thu, 19 Jan 2023 17:22:07 -0500 Subject: [PATCH 3/5] rework for build-time config resolution logic, with fallback --- .../scripts/config/plugins/multisite.ts | 13 ++----------- .../nextjs/scripts/config/plugins/computed.ts | 2 +- .../nextjs/scripts/config/plugins/fallback.ts | 19 +++++++++++++++++++ .../scripts/config/plugins/package-json.ts | 6 +++--- .../scripts/config/plugins/scjssconfig.ts | 10 +++------- .../nextjs/scripts/generate-config.ts | 17 +++++------------ 6 files changed, 33 insertions(+), 34 deletions(-) create mode 100644 packages/create-sitecore-jss/src/templates/nextjs/scripts/config/plugins/fallback.ts diff --git a/packages/create-sitecore-jss/src/templates/nextjs-multisite/scripts/config/plugins/multisite.ts b/packages/create-sitecore-jss/src/templates/nextjs-multisite/scripts/config/plugins/multisite.ts index b3669d7da2..5935cb6103 100644 --- a/packages/create-sitecore-jss/src/templates/nextjs-multisite/scripts/config/plugins/multisite.ts +++ b/packages/create-sitecore-jss/src/templates/nextjs-multisite/scripts/config/plugins/multisite.ts @@ -14,18 +14,9 @@ class MultisitePlugin implements ConfigPlugin { async exec(config: JssConfig) { let sites: SiteInfo[] = []; - const computeConfigValue = (val: string) => { - if(val.startsWith('`') && val.endsWith('`')) { - return new Function('return ' + val.replaceAll('config', 'this')).call(config); - } - else { - return val; - } - }; - // graphQL endpoint can have a dynamic value in the config - so we resolve it in a special way at build time - const endpoint = process.env.GRAPH_QL_ENDPOINT || computeConfigValue(config.computed?.graphQLEndpoint || ''); - const apiKey = process.env.SITECORE_API_KEY || config.sitecoreApiKey; + const endpoint = config.graphQLEndpoint; + const apiKey = config.sitecoreApiKey; if (!endpoint || !apiKey) { console.warn( diff --git a/packages/create-sitecore-jss/src/templates/nextjs/scripts/config/plugins/computed.ts b/packages/create-sitecore-jss/src/templates/nextjs/scripts/config/plugins/computed.ts index 2dc3c5aa56..23d2aaab5d 100644 --- a/packages/create-sitecore-jss/src/templates/nextjs/scripts/config/plugins/computed.ts +++ b/packages/create-sitecore-jss/src/templates/nextjs/scripts/config/plugins/computed.ts @@ -10,7 +10,7 @@ class ComputedPlugin implements ConfigPlugin { async exec(config: JssConfig) { return Object.assign({}, config, { - computed: { graphQLEndpoint: '`${config.sitecoreApiHost}${config.graphQLEndpointPath}`' }, + graphQLEndpoint: config.graphQLEndpoint || `${config.sitecoreApiHost}${config.graphQLEndpointPath}`, }); } } diff --git a/packages/create-sitecore-jss/src/templates/nextjs/scripts/config/plugins/fallback.ts b/packages/create-sitecore-jss/src/templates/nextjs/scripts/config/plugins/fallback.ts new file mode 100644 index 0000000000..e31b46fd5e --- /dev/null +++ b/packages/create-sitecore-jss/src/templates/nextjs/scripts/config/plugins/fallback.ts @@ -0,0 +1,19 @@ +import { ConfigPlugin, JssConfig } from '..'; + +/** + * This config will set fallback values for properties that were left empty + * If neither env, nor other places had a proper value, this will ensure a fallback is set + */ +class ComputedPlugin implements ConfigPlugin { + // should always comes last + order = 99; + + async exec(config: JssConfig) { + return Object.assign({}, config, { + defaultLanguage: config.defaultLanguage || 'en', + sitecoreApiKey: config.sitecoreApiKey || 'no-api-key-set' + }); + } +} + +export const computedPlugin = new ComputedPlugin(); diff --git a/packages/create-sitecore-jss/src/templates/nextjs/scripts/config/plugins/package-json.ts b/packages/create-sitecore-jss/src/templates/nextjs/scripts/config/plugins/package-json.ts index 3fffb6b1ec..ce49ee56d5 100644 --- a/packages/create-sitecore-jss/src/templates/nextjs/scripts/config/plugins/package-json.ts +++ b/packages/create-sitecore-jss/src/templates/nextjs/scripts/config/plugins/package-json.ts @@ -11,9 +11,9 @@ class PackageJsonPlugin implements ConfigPlugin { if (!packageConfig.config) return config; return Object.assign({}, config, { - jssAppName: packageConfig.config.appName, - graphQLEndpointPath: packageConfig.config.graphQLEndpointPath, - defaultLanguage: packageConfig.config.language, + jssAppName: config.jssAppName || packageConfig.config.appName, + graphQLEndpointPath: config.graphQLEndpointPath || packageConfig.config.graphQLEndpointPath, + defaultLanguage: config.defaultLanguage || packageConfig.config.language, }); } } diff --git a/packages/create-sitecore-jss/src/templates/nextjs/scripts/config/plugins/scjssconfig.ts b/packages/create-sitecore-jss/src/templates/nextjs/scripts/config/plugins/scjssconfig.ts index 0484e1d5a3..e957f2758b 100644 --- a/packages/create-sitecore-jss/src/templates/nextjs/scripts/config/plugins/scjssconfig.ts +++ b/packages/create-sitecore-jss/src/templates/nextjs/scripts/config/plugins/scjssconfig.ts @@ -13,18 +13,14 @@ class ScJssConfigPlugin implements ConfigPlugin { try { scJssConfig = require('scjssconfig.json'); } catch (e) { - // fall back on env values - return Object.assign({}, config, { - sitecoreApiKey: process.env.SITECORE_API_KEY, - sitecoreApiHost: process.env.SITECORE_API_HOST, - }); + return config; } if (!scJssConfig) return config; return Object.assign({}, config, { - sitecoreApiKey: scJssConfig.sitecore?.apiKey, - sitecoreApiHost: scJssConfig.sitecore?.layoutServiceHost, + sitecoreApiKey: config.sitecoreApiKey || scJssConfig.sitecore?.apiKey, + sitecoreApiHost: config.sitecoreApiHost || scJssConfig.sitecore?.layoutServiceHost, }); } } diff --git a/packages/create-sitecore-jss/src/templates/nextjs/scripts/generate-config.ts b/packages/create-sitecore-jss/src/templates/nextjs/scripts/generate-config.ts index 6c1f4e0394..7fd006027d 100644 --- a/packages/create-sitecore-jss/src/templates/nextjs/scripts/generate-config.ts +++ b/packages/create-sitecore-jss/src/templates/nextjs/scripts/generate-config.ts @@ -10,11 +10,11 @@ import { JssConfig, jssConfigFactory } from './config'; */ const defaultConfig: JssConfig = { - sitecoreApiKey: 'no-api-key-set', - sitecoreApiHost: '', - jssAppName: 'Unknown', - graphQLEndpointPath: '', - defaultLanguage: 'en', + sitecoreApiKey: process.env.SITECORE_API_KEY, + sitecoreApiHost: process.env.SITECORE_API_HOST, + jssAppName: process.env.JSS_APP_NAME, + graphQLEndpointPath: process.env.GRAPH_QL_ENDPOINT_PATH, + defaultLanguage: process.env.DEFAULT_LANGUAGE, }; generateConfig(defaultConfig); @@ -47,17 +47,10 @@ function writeConfig(config: JssConfig): void { // See scripts/bootstrap.ts to modify the generation of this file. const config = {};\n`; - const computedConfig = config.computed; - delete config['computed']; // Set configuration values, allowing override with environment variables Object.keys(config).forEach((prop) => { configText += `config.${prop} = process.env.${constantCase(prop)} || '${config[prop]}',\n`; }); - computedConfig && Object.keys(computedConfig).forEach((prop) => { - configText += `config.${prop} = process.env.${constantCase(prop)} || ${ - computedConfig[prop] - };\n`; - }); configText += `module.exports = config;`; const configPath = path.resolve('src/temp/config.js'); From 0e1b1a0c97390fed2a2c44f7c54b451b9ceefc4e Mon Sep 17 00:00:00 2001 From: Artem Alexeyenko Date: Thu, 19 Jan 2023 17:29:30 -0500 Subject: [PATCH 4/5] revert JssConfig type to how it was --- .../src/templates/nextjs/scripts/config/index.ts | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/packages/create-sitecore-jss/src/templates/nextjs/scripts/config/index.ts b/packages/create-sitecore-jss/src/templates/nextjs/scripts/config/index.ts index 19be2c355c..425474d0eb 100644 --- a/packages/create-sitecore-jss/src/templates/nextjs/scripts/config/index.ts +++ b/packages/create-sitecore-jss/src/templates/nextjs/scripts/config/index.ts @@ -4,15 +4,13 @@ const plugins = require('scripts/temp/config-plugins'); /** * JSS configuration object */ -export interface JssConfig extends Record | undefined> { +export interface JssConfig extends Record { sitecoreApiKey?: string; sitecoreApiHost?: string; jssAppName?: string; graphQLEndpointPath?: string; defaultLanguage?: string; - computed?: { - [key: string]: string; - } + graphQLEndpoint?: string; } export interface ConfigPlugin { From a68cb0a5765229abee300d8568f86d9239abd6ee Mon Sep 17 00:00:00 2001 From: Artem Alexeyenko Date: Fri, 20 Jan 2023 11:05:54 -0500 Subject: [PATCH 5/5] small tweaks, addressing comments --- .../scripts/config/plugins/multisite.ts | 3 +-- .../nextjs/scripts/config/plugins/fallback.ts | 4 ++-- .../src/templates/nextjs/scripts/generate-config.ts | 10 +++++----- 3 files changed, 8 insertions(+), 9 deletions(-) diff --git a/packages/create-sitecore-jss/src/templates/nextjs-multisite/scripts/config/plugins/multisite.ts b/packages/create-sitecore-jss/src/templates/nextjs-multisite/scripts/config/plugins/multisite.ts index 5935cb6103..cd60946469 100644 --- a/packages/create-sitecore-jss/src/templates/nextjs-multisite/scripts/config/plugins/multisite.ts +++ b/packages/create-sitecore-jss/src/templates/nextjs-multisite/scripts/config/plugins/multisite.ts @@ -14,13 +14,12 @@ class MultisitePlugin implements ConfigPlugin { async exec(config: JssConfig) { let sites: SiteInfo[] = []; - // graphQL endpoint can have a dynamic value in the config - so we resolve it in a special way at build time const endpoint = config.graphQLEndpoint; const apiKey = config.sitecoreApiKey; if (!endpoint || !apiKey) { console.warn( - chalk.yellow('Skipping site information fetch (missing GraphQL connection details). Endpoint or API key missing.') + chalk.yellow('Skipping site information fetch (missing GraphQL endpoint or API key).') ); } else { console.log(`Fetching site information from ${endpoint}`); diff --git a/packages/create-sitecore-jss/src/templates/nextjs/scripts/config/plugins/fallback.ts b/packages/create-sitecore-jss/src/templates/nextjs/scripts/config/plugins/fallback.ts index e31b46fd5e..4de86d8b8b 100644 --- a/packages/create-sitecore-jss/src/templates/nextjs/scripts/config/plugins/fallback.ts +++ b/packages/create-sitecore-jss/src/templates/nextjs/scripts/config/plugins/fallback.ts @@ -4,7 +4,7 @@ import { ConfigPlugin, JssConfig } from '..'; * This config will set fallback values for properties that were left empty * If neither env, nor other places had a proper value, this will ensure a fallback is set */ -class ComputedPlugin implements ConfigPlugin { +class FallbackPlugin implements ConfigPlugin { // should always comes last order = 99; @@ -16,4 +16,4 @@ class ComputedPlugin implements ConfigPlugin { } } -export const computedPlugin = new ComputedPlugin(); +export const fallbackPlugin = new FallbackPlugin(); diff --git a/packages/create-sitecore-jss/src/templates/nextjs/scripts/generate-config.ts b/packages/create-sitecore-jss/src/templates/nextjs/scripts/generate-config.ts index 7fd006027d..72ddb2474e 100644 --- a/packages/create-sitecore-jss/src/templates/nextjs/scripts/generate-config.ts +++ b/packages/create-sitecore-jss/src/templates/nextjs/scripts/generate-config.ts @@ -10,11 +10,11 @@ import { JssConfig, jssConfigFactory } from './config'; */ const defaultConfig: JssConfig = { - sitecoreApiKey: process.env.SITECORE_API_KEY, - sitecoreApiHost: process.env.SITECORE_API_HOST, - jssAppName: process.env.JSS_APP_NAME, - graphQLEndpointPath: process.env.GRAPH_QL_ENDPOINT_PATH, - defaultLanguage: process.env.DEFAULT_LANGUAGE, + sitecoreApiKey: process.env[`${constantCase('sitecoreApiKey')}`], + sitecoreApiHost: process.env[`${constantCase('sitecoreApiHost')}`], + jssAppName: process.env[`${constantCase('jssAppName')}`], + graphQLEndpointPath: process.env[`${constantCase('graphQLEndpointPath')}`], + defaultLanguage: process.env[`${constantCase('defaultLanguage')}`], }; generateConfig(defaultConfig);