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
@@ -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,