core-app-api: add support for backstage.io/config tags
Signed-off-by: Patrik Oldsberg <poldsberg@gmail.com>
This commit is contained in:
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/core-app-api': patch
|
||||
---
|
||||
|
||||
The `defaultConfigLoader` now also reads configuration from scripts tags with `type="backstage.io/config"`. The tag is expected to contain a JSON-serialized array of `AppConfig` objects. If any of these script tags are present, the injected runtime configuration in the static assets will no longer be used.
|
||||
+42
@@ -14,7 +14,10 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { render } from '@testing-library/react';
|
||||
import { defaultConfigLoaderSync } from './defaultConfigLoader';
|
||||
import { ConfigReader } from '@backstage/config';
|
||||
|
||||
(process as any).env = { NODE_ENV: 'test' };
|
||||
const anyEnv = process.env as any;
|
||||
@@ -53,6 +56,45 @@ describe('defaultConfigLoaderSync', () => {
|
||||
]);
|
||||
});
|
||||
|
||||
it('loads config from script tags and ignore static config', () => {
|
||||
anyEnv.APP_CONFIG = [];
|
||||
|
||||
render(
|
||||
<script type="backstage.io/config">
|
||||
{`[{"data":{"my":"config"},"context":"a"},{"data":{"my":"override-config"},"context":"b"}]`}
|
||||
</script>,
|
||||
);
|
||||
|
||||
const configs = (defaultConfigLoaderSync as any)('{"my":"runtime-config"}');
|
||||
expect(configs).toEqual([
|
||||
{ data: { my: 'config' }, context: 'a' },
|
||||
{ data: { my: 'override-config' }, context: 'b' },
|
||||
]);
|
||||
expect(ConfigReader.fromConfigs(configs).get('my')).toBe('override-config');
|
||||
});
|
||||
|
||||
it('loads config from all script tags in order', () => {
|
||||
anyEnv.APP_CONFIG = [];
|
||||
|
||||
render(
|
||||
<>
|
||||
<script type="backstage.io/config">
|
||||
{`[{"data":{"my":"config"},"context":"a"}]`}
|
||||
</script>
|
||||
<script type="backstage.io/config">
|
||||
{`[{"data":{"my":"override-config"},"context":"b"}]`}
|
||||
</script>
|
||||
</>,
|
||||
);
|
||||
|
||||
const configs = (defaultConfigLoaderSync as any)('{"my":"runtime-config"}');
|
||||
expect(configs).toEqual([
|
||||
{ data: { my: 'config' }, context: 'a' },
|
||||
{ data: { my: 'override-config' }, context: 'b' },
|
||||
]);
|
||||
expect(ConfigReader.fromConfigs(configs).get('my')).toBe('override-config');
|
||||
});
|
||||
|
||||
it('fails to load invalid missing config', () => {
|
||||
expect(() => defaultConfigLoaderSync()).toThrow(
|
||||
'No static configuration provided',
|
||||
@@ -49,9 +49,36 @@ export function defaultConfigLoaderSync(
|
||||
}
|
||||
const configs = appConfig.slice() as unknown as AppConfig[];
|
||||
|
||||
// Avoiding this string also being replaced at runtime
|
||||
if (
|
||||
// Check if we have any config script tags, otherwise fall back to injected config
|
||||
const configScripts = document.querySelectorAll(
|
||||
'script[type="backstage.io/config"]',
|
||||
);
|
||||
if (configScripts.length > 0) {
|
||||
for (const el of configScripts) {
|
||||
try {
|
||||
const content = el.textContent;
|
||||
if (!content) {
|
||||
throw new Error('tag is empty');
|
||||
}
|
||||
let data;
|
||||
try {
|
||||
data = JSON.parse(content);
|
||||
} catch (error) {
|
||||
throw new Error(`failed to parse config; ${error}`);
|
||||
}
|
||||
if (!Array.isArray(data)) {
|
||||
throw new Error('data is not an array');
|
||||
}
|
||||
configs.push(...data);
|
||||
} catch (error) {
|
||||
throw new Error(
|
||||
`Failed to load config from script tag, ${error.message}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
} else if (
|
||||
runtimeConfigJson !==
|
||||
// Avoiding this string also being replaced at runtime
|
||||
'__app_injected_runtime_config__'.toLocaleUpperCase('en-US')
|
||||
) {
|
||||
try {
|
||||
|
||||
Reference in New Issue
Block a user