From cdfc4599f868fe4f7cb9dd7b07bafea39ecfa839 Mon Sep 17 00:00:00 2001 From: Tim Barton Date: Thu, 25 Jan 2024 10:14:41 +0000 Subject: [PATCH 01/10] feat(conditionalIntl): added env var for Itnl --- __tests__/server/config/env/runTime.spec.js | 17 ++++++++++++ .../server/plugins/reactHtml/index.spec.jsx | 16 ++++++++++++ docs/api/server/Environment-Variables.md | 26 ++++++++++++++++++- src/client/polyfill/Intl.js | 6 +++-- src/server/config/env/runTime.js | 10 +++++++ src/server/plugins/reactHtml/index.jsx | 10 ++++++- src/server/polyfill/intl.js | 6 ++++- 7 files changed, 86 insertions(+), 5 deletions(-) diff --git a/__tests__/server/config/env/runTime.spec.js b/__tests__/server/config/env/runTime.spec.js index bebc5128a..cd6eb5ae5 100644 --- a/__tests__/server/config/env/runTime.spec.js +++ b/__tests__/server/config/env/runTime.spec.js @@ -100,6 +100,7 @@ describe('runTime', () => { 'ONE_CLIENT_ROOT_MODULE_NAME', 'ONE_ENABLE_POST_TO_MODULE_ROUTES', 'ONE_MAX_POST_REQUEST_PAYLOAD', + 'ONE_CONFIG_USE_NATIVE_POLYFILL', ].forEach((name) => { origEnvVarVals[name] = process.env[name]; }); @@ -547,4 +548,20 @@ describe('runTime', () => { expect(otelServiceName.defaultValue).toBe('One App'); }); }); + + describe('ONE_CONFIG_USE_NATIVE_POLYFILL', () => { + const useNativePolyfill = getEnvVarConfig('ONE_CONFIG_USE_NATIVE_POLYFILL'); + + it('should have a default value of false', () => { + expect(useNativePolyfill.defaultValue).toBe('false'); + }); + + it('should normalise the value to false when not explicitly true', () => { + expect(useNativePolyfill.normalize('Value')).toBe('false'); + expect(useNativePolyfill.normalize('VALUE')).toBe('false'); + expect(useNativePolyfill.normalize('true')).toBe('true'); + expect(useNativePolyfill.normalize('TRUE')).toBe('true'); + expect(useNativePolyfill.normalize('FALSE')).toBe('false'); + }); + }); }); diff --git a/__tests__/server/plugins/reactHtml/index.spec.jsx b/__tests__/server/plugins/reactHtml/index.spec.jsx index 23c739c01..34054a2c6 100644 --- a/__tests__/server/plugins/reactHtml/index.spec.jsx +++ b/__tests__/server/plugins/reactHtml/index.spec.jsx @@ -23,6 +23,7 @@ import reactHtml, { renderModuleScripts, renderExternalFallbacks, checkStateForRedirectAndStatusCode, + renderUseNativeIntlPolyfill, } from '../../../../src/server/plugins/reactHtml'; // _client is a method to control the mock // eslint-disable-next-line import/named @@ -1262,4 +1263,19 @@ describe('reactHtml', () => { expect(reply.send.mock.calls[0][0]).toContain('One App'); }); }); + + describe('renderUseNativePolyfill', () => { + it('should not add the polyfill script if there is no environment variable', () => { + expect(renderUseNativeIntlPolyfill('')).toMatchInlineSnapshot('""'); + }); + + it('should add the polyfill script if there is the environment variable and it is true', () => { + process.env.ONE_CONFIG_USE_NATIVE_POLYFILL = 'true'; + expect(renderUseNativeIntlPolyfill('')).toMatchInlineSnapshot(` + "" + `); + }); + }); }); diff --git a/docs/api/server/Environment-Variables.md b/docs/api/server/Environment-Variables.md index afa38be77..5b2ba1a2f 100644 --- a/docs/api/server/Environment-Variables.md +++ b/docs/api/server/Environment-Variables.md @@ -29,6 +29,7 @@ One App can be configured via Environment Variables: * [`ONE_CLIENT_ROOT_MODULE_NAME`](#one_client_root_module_name) ⚠️ * [`ONE_CLIENT_CDN_URL`](#one_client_cdn_url) ⚠️ * [`ONE_CONFIG_ENV`](#one_config_env) ⚠️ + * [`ONE_CONFIG_USE_NATIVE_POLYFILL`](#one_config_use_native_polyfill) * Running in Development * [`NODE_ENV`](#node_env) ⚠️ * [`ONE_CLIENT_ROOT_MODULE_NAME`](#one_client_root_module_name) ⚠️ @@ -36,6 +37,7 @@ One App can be configured via Environment Variables: * [`ONE_DANGEROUSLY_ACCEPT_BREAKING_EXTERNALS`](#ONE_DANGEROUSLY_ACCEPT_BREAKING_EXTERNALS) * [`ONE_CSP_ALLOW_INLINE_SCRIPTS`](#ONE_CSP_ALLOW_INLINE_SCRIPTS) * [`ONE_DANGEROUSLY_DISABLE_CSP`](#ONE_DANGEROUSLY_DISABLE_CSP) + * * [`ONE_CONFIG_USE_NATIVE_POLYFILL`](#one_config_use_native_polyfill) * Server Settings * [`HOLOCRON_SERVER_MAX_MODULES_RETRY`](#holocron_server_max_modules_retry) * [`HOLOCRON_SERVER_MAX_SIM_MODULES_FETCH`](#holocron_server_max_sim_modules_fetch) @@ -74,6 +76,7 @@ One App can be configured via Environment Variables: * [`ONE_CLIENT_REPORTING_URL`](#one_client_reporting_url) ⚠️ * [`ONE_CLIENT_ROOT_MODULE_NAME`](#one_client_root_module_name) ⚠️ * [`ONE_CONFIG_ENV`](#one_config_env) ⚠️ + * [`ONE_CONFIG_USE_NATIVE_POLYFILL`](#one_config_use_native_polyfill) * [`ONE_ENABLE_POST_TO_MODULE_ROUTES`](#one_enable_post_to_module_routes) * [`ONE_MAP_POLLING_MAX`](#one_map_polling_max) * [`ONE_MAP_POLLING_MIN`](#one_map_polling_min) @@ -524,6 +527,27 @@ ONE_CONFIG_ENV=staging ONE_CONFIG_ENV=undefined ``` +## `ONE_CONFIG_USE_NATIVE_POLYFILL` +**Runs In** +* ✅ Production +* ✅ Development + +Feature flag to disable lean-intl polyfill. +This allows you to use modern intl features such as timezones, but will result in your application supporting fewer older browsers. + +**Shape** +```bash +ONE_CONFIG_USE_NATIVE_POLYFILL=Boolean +``` +**Example** +```bash +ONE_CONFIG_USE_NATIVE_POLYFILL=true +``` +**Default Value** +```bash +ONE_CONFIG_USE_NATIVE_POLYFILL=false +``` + ## `ONE_DANGEROUSLY_ACCEPT_BREAKING_EXTERNALS` **Runs In** @@ -824,4 +848,4 @@ OTEL_RESOURCE_ATTRIBUTES="foo=bar;baz=qux" [`HTTPS_PRIVATE_KEY_PASS_FILE_PATH`]: #https_private_key_pass_file_path [`HTTPS_PORT`]: #https_port [OTel Environment Variable Specification]: https://opentelemetry.io/docs/specs/otel/configuration/sdk-environment-variables/ -[OTel Resource SDK documentation]: https://opentelemetry.io/docs/specs/otel/resource/sdk/#specifying-resource-information-via-an-environment-variable \ No newline at end of file +[OTel Resource SDK documentation]: https://opentelemetry.io/docs/specs/otel/resource/sdk/#specifying-resource-information-via-an-environment-variable diff --git a/src/client/polyfill/Intl.js b/src/client/polyfill/Intl.js index 8cbb70143..49f235938 100644 --- a/src/client/polyfill/Intl.js +++ b/src/client/polyfill/Intl.js @@ -19,5 +19,7 @@ import Intl from 'lean-intl'; -global.Intl = Intl; -global.IntlPolyfill = Intl; +if (!(window && window.useNativePolyfill)) { + global.Intl = Intl; + global.IntlPolyfill = Intl; +} diff --git a/src/server/config/env/runTime.js b/src/server/config/env/runTime.js index 7eb82f252..c038926e0 100644 --- a/src/server/config/env/runTime.js +++ b/src/server/config/env/runTime.js @@ -186,6 +186,16 @@ const runTime = [ validate: (value) => { if (!value) { throw new Error('The `ONE_CLIENT_ROOT_MODULE_NAME` environment variable must be defined.'); } }, defaultValue: () => (process.env.NODE_ENV === 'development' ? argv.rootModuleName : undefined), }, + { + name: 'ONE_CONFIG_USE_NATIVE_POLYFILL', + defaultValue: 'false', + normalize: (input) => { + if (input?.toLowerCase() === 'true') { + return 'true'; + } + return 'false'; + }, + }, { name: 'ONE_REFERRER_POLICY_OVERRIDE', defaultValue: () => '', diff --git a/src/server/plugins/reactHtml/index.jsx b/src/server/plugins/reactHtml/index.jsx index b56e4b55a..dbec057ce 100644 --- a/src/server/plugins/reactHtml/index.jsx +++ b/src/server/plugins/reactHtml/index.jsx @@ -236,6 +236,12 @@ export function getHead({ `; } +export function renderUseNativeIntlPolyfill(nonce) { + return process.env.ONE_CONFIG_USE_NATIVE_POLYFILL === 'true' ? `` : ''; +} + export function getBody({ isLegacy, helmetInfo, @@ -253,13 +259,14 @@ export function getBody({ const bundle = isLegacy ? 'legacyBrowser' : 'browser'; const { bodyAttributes, script } = helmetInfo; const bundlePrefixForBrowser = isLegacy ? `${appBundlesURLPrefix}/legacy` : appBundlesURLPrefix; + const nonce = scriptNonce ? `nonce="${scriptNonce}"` : ''; return `
${appHtml || ''}
${disableScripts ? '' : ` - + ${renderUseNativeIntlPolyfill(nonce)} ${assets} ${renderI18nScript(clientInitialState, bundlePrefixForBrowser)} ${renderExternalFallbacks({ diff --git a/src/server/polyfill/intl.js b/src/server/polyfill/intl.js index 4d78166a8..952e213a9 100644 --- a/src/server/polyfill/intl.js +++ b/src/server/polyfill/intl.js @@ -14,4 +14,8 @@ * permissions and limitations under the License. */ -global.Intl = require('lean-intl'); +import Intl from 'lean-intl'; + +if (!process.env.ONE_CONFIG_USE_NATIVE_POLYFILL) { + global.Intl = Intl; +} From 7ef00ed7d95d6247b94cd61781b9868b2818ca49 Mon Sep 17 00:00:00 2001 From: Tim Barton Date: Thu, 25 Jan 2024 11:49:40 +0000 Subject: [PATCH 02/10] feat(conditionalIntl): fixed nonce --- src/server/plugins/reactHtml/index.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/server/plugins/reactHtml/index.jsx b/src/server/plugins/reactHtml/index.jsx index dbec057ce..5cfce5702 100644 --- a/src/server/plugins/reactHtml/index.jsx +++ b/src/server/plugins/reactHtml/index.jsx @@ -266,7 +266,7 @@ export function getBody({ ${disableScripts ? '' : ` - " + `); }); it('should add the polyfill script if there is the environment variable and it is true', () => { - process.env.ONE_CONFIG_USE_NATIVE_POLYFILL = 'true'; - expect(renderUseNativeIntlPolyfill('')).toMatchInlineSnapshot(` + process.env.ONE_CONFIG_USE_NATIVE_INTL = 'true'; + expect(renderEnvironmentVariables('')).toMatchInlineSnapshot(` "" `); }); diff --git a/docs/api/server/Environment-Variables.md b/docs/api/server/Environment-Variables.md index 5b2ba1a2f..e00005b69 100644 --- a/docs/api/server/Environment-Variables.md +++ b/docs/api/server/Environment-Variables.md @@ -29,7 +29,7 @@ One App can be configured via Environment Variables: * [`ONE_CLIENT_ROOT_MODULE_NAME`](#one_client_root_module_name) ⚠️ * [`ONE_CLIENT_CDN_URL`](#one_client_cdn_url) ⚠️ * [`ONE_CONFIG_ENV`](#one_config_env) ⚠️ - * [`ONE_CONFIG_USE_NATIVE_POLYFILL`](#one_config_use_native_polyfill) + * [`ONE_CONFIG_USE_NATIVE_INTL`](#one_config_use_native_intl) * Running in Development * [`NODE_ENV`](#node_env) ⚠️ * [`ONE_CLIENT_ROOT_MODULE_NAME`](#one_client_root_module_name) ⚠️ @@ -37,7 +37,7 @@ One App can be configured via Environment Variables: * [`ONE_DANGEROUSLY_ACCEPT_BREAKING_EXTERNALS`](#ONE_DANGEROUSLY_ACCEPT_BREAKING_EXTERNALS) * [`ONE_CSP_ALLOW_INLINE_SCRIPTS`](#ONE_CSP_ALLOW_INLINE_SCRIPTS) * [`ONE_DANGEROUSLY_DISABLE_CSP`](#ONE_DANGEROUSLY_DISABLE_CSP) - * * [`ONE_CONFIG_USE_NATIVE_POLYFILL`](#one_config_use_native_polyfill) + * * [`ONE_CONFIG_USE_NATIVE_INTL`](#one_config_use_native_intl) * Server Settings * [`HOLOCRON_SERVER_MAX_MODULES_RETRY`](#holocron_server_max_modules_retry) * [`HOLOCRON_SERVER_MAX_SIM_MODULES_FETCH`](#holocron_server_max_sim_modules_fetch) @@ -76,7 +76,7 @@ One App can be configured via Environment Variables: * [`ONE_CLIENT_REPORTING_URL`](#one_client_reporting_url) ⚠️ * [`ONE_CLIENT_ROOT_MODULE_NAME`](#one_client_root_module_name) ⚠️ * [`ONE_CONFIG_ENV`](#one_config_env) ⚠️ - * [`ONE_CONFIG_USE_NATIVE_POLYFILL`](#one_config_use_native_polyfill) + * [`ONE_CONFIG_USE_NATIVE_INTL`](#one_config_use_native_intl) * [`ONE_ENABLE_POST_TO_MODULE_ROUTES`](#one_enable_post_to_module_routes) * [`ONE_MAP_POLLING_MAX`](#one_map_polling_max) * [`ONE_MAP_POLLING_MIN`](#one_map_polling_min) @@ -527,7 +527,7 @@ ONE_CONFIG_ENV=staging ONE_CONFIG_ENV=undefined ``` -## `ONE_CONFIG_USE_NATIVE_POLYFILL` +## `ONE_CONFIG_USE_NATIVE_INTL` **Runs In** * ✅ Production * ✅ Development @@ -537,15 +537,15 @@ This allows you to use modern intl features such as timezones, but will result i **Shape** ```bash -ONE_CONFIG_USE_NATIVE_POLYFILL=Boolean +ONE_CONFIG_USE_NATIVE_INTL=Boolean ``` **Example** ```bash -ONE_CONFIG_USE_NATIVE_POLYFILL=true +ONE_CONFIG_USE_NATIVE_INTL=true ``` **Default Value** ```bash -ONE_CONFIG_USE_NATIVE_POLYFILL=false +ONE_CONFIG_USE_NATIVE_INTL=false ``` ## `ONE_DANGEROUSLY_ACCEPT_BREAKING_EXTERNALS` diff --git a/src/client/polyfill/Intl.js b/src/client/polyfill/Intl.js index 49f235938..234499492 100644 --- a/src/client/polyfill/Intl.js +++ b/src/client/polyfill/Intl.js @@ -19,7 +19,7 @@ import Intl from 'lean-intl'; -if (!(window && window.useNativePolyfill)) { +if (!(window && window.useNativeIntl)) { global.Intl = Intl; global.IntlPolyfill = Intl; } diff --git a/src/server/config/env/runTime.js b/src/server/config/env/runTime.js index c038926e0..817c8ebb5 100644 --- a/src/server/config/env/runTime.js +++ b/src/server/config/env/runTime.js @@ -187,7 +187,7 @@ const runTime = [ defaultValue: () => (process.env.NODE_ENV === 'development' ? argv.rootModuleName : undefined), }, { - name: 'ONE_CONFIG_USE_NATIVE_POLYFILL', + name: 'ONE_CONFIG_USE_NATIVE_INTL', defaultValue: 'false', normalize: (input) => { if (input?.toLowerCase() === 'true') { diff --git a/src/server/plugins/reactHtml/index.jsx b/src/server/plugins/reactHtml/index.jsx index 5cfce5702..0803d49c5 100644 --- a/src/server/plugins/reactHtml/index.jsx +++ b/src/server/plugins/reactHtml/index.jsx @@ -66,7 +66,7 @@ const legacyBrowserChunkAssets = getChunkAssets(readJsonFile('../../../.build-me function renderI18nScript(clientInitialState, appBundlesURLPrefix) { const i18nFile = getI18nFileFromState(clientInitialState); - if (!i18nFile) { + if (!i18nFile || process.env.ONE_CONFIG_USE_NATIVE_INTL === 'true') { return ''; } @@ -236,10 +236,10 @@ export function getHead({ `; } -export function renderUseNativeIntlPolyfill(nonce) { - return process.env.ONE_CONFIG_USE_NATIVE_POLYFILL === 'true' ? `` : ''; +export function renderEnvironmentVariables(nonce) { + return ``; } export function getBody({ @@ -275,7 +275,7 @@ export function getBody({ window.__render_mode__ = '${renderMode}'; window.__HOLOCRON_EXTERNALS__ = ${jsonStringifyForScript(getRequiredExternalsRegistry())}; - ${renderUseNativeIntlPolyfill(nonce)} + ${renderEnvironmentVariables(nonce)} ${assets} ${renderI18nScript(clientInitialState, bundlePrefixForBrowser)} ${renderExternalFallbacks({ diff --git a/src/server/polyfill/intl.js b/src/server/polyfill/intl.js index 952e213a9..2c5c0ca9b 100644 --- a/src/server/polyfill/intl.js +++ b/src/server/polyfill/intl.js @@ -16,6 +16,6 @@ import Intl from 'lean-intl'; -if (!process.env.ONE_CONFIG_USE_NATIVE_POLYFILL) { +if (process.env.ONE_CONFIG_USE_NATIVE_INTL !== 'true') { global.Intl = Intl; } From edb789aa4e5e79e34d18e794e45fc2c3de99841f Mon Sep 17 00:00:00 2001 From: Tim Barton Date: Fri, 2 Feb 2024 14:26:32 +0000 Subject: [PATCH 04/10] feat(conditionalItnl): renderI18nScript return early --- __tests__/server/plugins/reactHtml/index.spec.jsx | 11 +++++++++++ src/server/plugins/reactHtml/index.jsx | 6 +++++- 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/__tests__/server/plugins/reactHtml/index.spec.jsx b/__tests__/server/plugins/reactHtml/index.spec.jsx index a2564bffc..e42e6c630 100644 --- a/__tests__/server/plugins/reactHtml/index.spec.jsx +++ b/__tests__/server/plugins/reactHtml/index.spec.jsx @@ -284,6 +284,8 @@ describe('reactHtml', () => { cdnUrl: '/cdnUrl/', rootModuleName: 'test-root', })); + + process.env.ONE_CONFIG_USE_NATIVE_INTL = 'false'; }); function removeInitialState(body) { @@ -431,6 +433,15 @@ describe('reactHtml', () => { expect(reply.send.mock.calls[0][0]).not.toContain('src="/cdnUrl/app/1.2.3-rc.4-abc123/i18n/'); }); + it('sends a rendered page without the locale data script tag when te ONE_CONFIG_USE_NATIVE_INTL environment variable is true', () => { + process.env.ONE_CONFIG_USE_NATIVE_INTL = 'true'; + setFullMap(); + sendHtml(request, reply); + + expect(reply.send).toHaveBeenCalledTimes(1); + expect(reply.send.mock.calls[0][0]).not.toContain('src="/cdnUrl/app/1.2.3-rc.4-abc123/i18n/'); + }); + it('sends a rendered page with the module styles and scripts', () => { sendHtml(request, reply); expect(reply.send).toHaveBeenCalledTimes(1); diff --git a/src/server/plugins/reactHtml/index.jsx b/src/server/plugins/reactHtml/index.jsx index 0803d49c5..8571ea445 100644 --- a/src/server/plugins/reactHtml/index.jsx +++ b/src/server/plugins/reactHtml/index.jsx @@ -65,8 +65,12 @@ const legacyBrowserChunkAssets = getChunkAssets(readJsonFile('../../../.build-me .map((chunkAsset) => `legacy/${chunkAsset}`); function renderI18nScript(clientInitialState, appBundlesURLPrefix) { + if (process.env.ONE_CONFIG_USE_NATIVE_INTL === 'true') { + return ''; + } + const i18nFile = getI18nFileFromState(clientInitialState); - if (!i18nFile || process.env.ONE_CONFIG_USE_NATIVE_INTL === 'true') { + if (!i18nFile) { return ''; } From c3265dcf2a0f2e8375d637612cc18fb7b8b54061 Mon Sep 17 00:00:00 2001 From: Tim Barton Date: Fri, 2 Feb 2024 14:45:34 +0000 Subject: [PATCH 05/10] feat(conditionalIntl): renaming tests for env var script --- __tests__/server/plugins/reactHtml/index.spec.jsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/__tests__/server/plugins/reactHtml/index.spec.jsx b/__tests__/server/plugins/reactHtml/index.spec.jsx index e42e6c630..b43342480 100644 --- a/__tests__/server/plugins/reactHtml/index.spec.jsx +++ b/__tests__/server/plugins/reactHtml/index.spec.jsx @@ -1275,8 +1275,8 @@ describe('reactHtml', () => { }); }); - describe('renderUseNativePolyfill', () => { - it('should not add the polyfill script if there is no environment variable', () => { + describe('renderEnvironmentVariables', () => { + it('should set useNativeIntl to false if the environment variable is not true', () => { expect(renderEnvironmentVariables('')).toMatchInlineSnapshot(` "