cli: switch config injection to index.html

Signed-off-by: Patrik Oldsberg <poldsberg@gmail.com>
This commit is contained in:
Patrik Oldsberg
2024-11-16 21:58:18 -07:00
parent 44b82da79a
commit a2f0559024
3 changed files with 95 additions and 15 deletions
+9
View File
@@ -0,0 +1,9 @@
---
'@backstage/cli': patch
---
When using the experimental Rspack flag the app build and dev server now injects configuration via a `<script type="backstage.io/config">...</script>` tag in `index.html` rather than the `process.env.APP_CONFIG` definition, which will now be defined as an empty array instead.
This requires the app to be using the config loader from the 1.31 release of Backstage. Make sure your app is using at least that version if you are upgrading to this version of the CLI.
If you have copied the implementation of the `defaultConfigLoader`, make sure to update it to the new implementation. In particular the config loader needs to be able to read configuration from `script` tags with the type `backstage.io/config`.
@@ -0,0 +1,55 @@
/*
* Copyright 2024 The Backstage Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { AppConfig } from '@backstage/config';
import HtmlWebpackPlugin from 'html-webpack-plugin';
export class ConfigInjectingHtmlWebpackPlugin extends HtmlWebpackPlugin {
readonly name = 'ConfigInjectingHtmlWebpackPlugin';
readonly #getFrontendAppConfigs: () => AppConfig[];
constructor(
options: HtmlWebpackPlugin.Options,
getFrontendAppConfigs: () => AppConfig[],
) {
super(options);
this.#getFrontendAppConfigs = getFrontendAppConfigs;
}
apply: HtmlWebpackPlugin['apply'] = compiler => {
super.apply(compiler);
compiler.hooks.compilation.tap(this.name, compilation => {
const hooks = HtmlWebpackPlugin.getCompilationHooks(compilation);
hooks.alterAssetTagGroups.tap(this.name, ctx => {
if (ctx.plugin !== this) {
return ctx;
}
return {
...ctx,
headTags: [
...ctx.headTags,
HtmlWebpackPlugin.createHtmlTagObject(
'script',
{ type: 'backstage.io/config' },
`\n${JSON.stringify(this.#getFrontendAppConfigs(), null, 2)}\n`,
),
],
};
});
});
};
}
+31 -15
View File
@@ -37,6 +37,7 @@ import { version } from '../../lib/version';
import yn from 'yn';
import { hasReactDomClient } from './hasReactDomClient';
import { createWorkspaceLinkingPlugins } from './linkWorkspaces';
import { ConfigInjectingHtmlWebpackPlugin } from './ConfigInjectingHtmlWebpackPlugin';
const BUILD_CACHE_ENV_VAR = 'BACKSTAGE_CLI_EXPERIMENTAL_BUILD_CACHE';
@@ -182,19 +183,35 @@ export async function createConfig(
);
if (options.moduleFederation?.mode !== 'remote') {
plugins.push(
// `rspack.HtmlRspackPlugin` does not support object type `templateParameters` value, `frontendConfig` in this case
new HtmlWebpackPlugin({
meta: {
'backstage-app-mode': options?.appMode ?? 'public',
},
template: paths.targetHtml,
templateParameters: {
publicPath,
config: frontendConfig,
},
}),
);
const templateOptions = {
meta: {
'backstage-app-mode': options?.appMode ?? 'public',
},
template: paths.targetHtml,
templateParameters: {
publicPath,
config: frontendConfig,
},
};
if (rspack) {
// With Rspack we inject config via index.html, this is both because we
// can't use APP_CONFIG due to the lack of support for runtime values, but
// also because we are able to do it and it lines up better with what the
// app-backend is doing.
//
// We still use the html plugin from WebPack, since the Rspack one won't
// let us inject complex objects like the config.
plugins.push(
new ConfigInjectingHtmlWebpackPlugin(
templateOptions,
options.getFrontendAppConfigs,
),
);
} else {
// Config injection via index.html doesn't work across reloads with
// WebPack, so we rely on the APP_CONFIG injection instead
plugins.push(new HtmlWebpackPlugin(templateOptions));
}
plugins.push(
new HtmlWebpackPlugin({
meta: {
@@ -284,8 +301,7 @@ export async function createConfig(
new bundler.DefinePlugin({
'process.env.BUILD_INFO': JSON.stringify(buildInfo),
'process.env.APP_CONFIG': rspack
? // FIXME: see also https://github.com/web-infra-dev/rspack/issues/5606
JSON.stringify(options.getFrontendAppConfigs())
? JSON.stringify([]) // Inject via index.html instead
: bundler.DefinePlugin.runtimeValue(
() => JSON.stringify(options.getFrontendAppConfigs()),
true,