Watching config change; update over MessageChannel
Co-authored-by: Jack Palmer <UsainBloot@users.noreply.github.com> Co-authored-by: Patrik Oldsberg <poldsberg@gmail.com> Co-authored-by: Vincenzo Scamporlino <vincenzos@spotify.com> Signed-off-by: Philipp Hugenroth <philipph@spotify.com>
This commit is contained in:
@@ -91,11 +91,16 @@ export async function startFrontend(options: StartAppOptions) {
|
||||
|
||||
checkReactVersion();
|
||||
|
||||
const configChannel = new MessageChannel();
|
||||
|
||||
const { name } = await fs.readJson(paths.resolveTarget('package.json'));
|
||||
const config = await loadCliConfig({
|
||||
args: options.configPaths,
|
||||
fromPackage: name,
|
||||
withFilteredKeys: true,
|
||||
watch(appConfigs) {
|
||||
configChannel.port1.postMessage(appConfigs);
|
||||
},
|
||||
});
|
||||
|
||||
const appBaseUrl = config.frontendConfig.getString('app.baseUrl');
|
||||
@@ -119,6 +124,7 @@ export async function startFrontend(options: StartAppOptions) {
|
||||
const waitForExit = await serveBundle({
|
||||
entry: options.entry,
|
||||
checksEnabled: options.checksEnabled,
|
||||
configChannel,
|
||||
...config,
|
||||
});
|
||||
|
||||
|
||||
@@ -117,12 +117,6 @@ export async function createConfig(
|
||||
}),
|
||||
);
|
||||
|
||||
plugins.push(
|
||||
new webpack.EnvironmentPlugin({
|
||||
APP_CONFIG: options.frontendAppConfigs,
|
||||
}),
|
||||
);
|
||||
|
||||
plugins.push(
|
||||
new HtmlWebpackPlugin({
|
||||
template: paths.targetHtml,
|
||||
@@ -137,6 +131,10 @@ export async function createConfig(
|
||||
plugins.push(
|
||||
new webpack.DefinePlugin({
|
||||
'process.env.BUILD_INFO': JSON.stringify(buildInfo),
|
||||
'process.env.APP_CONFIG': webpack.DefinePlugin.runtimeValue(
|
||||
() => JSON.stringify(options.getFrontendAppConfigs()),
|
||||
true,
|
||||
),
|
||||
}),
|
||||
);
|
||||
|
||||
|
||||
@@ -21,6 +21,7 @@ import openBrowser from 'react-dev-utils/openBrowser';
|
||||
import { createConfig, resolveBaseUrl } from './config';
|
||||
import { ServeOptions } from './types';
|
||||
import { resolveBundlingPaths } from './paths';
|
||||
import { AppConfig } from '@backstage/config';
|
||||
|
||||
export async function serveBundle(options: ServeOptions) {
|
||||
const url = resolveBaseUrl(options.frontendConfig);
|
||||
@@ -32,6 +33,8 @@ export async function serveBundle(options: ServeOptions) {
|
||||
Number(url.port) ||
|
||||
(url.protocol === 'https:' ? 443 : 80);
|
||||
|
||||
let latestFrontendAppConfigs = options.frontendAppConfigs;
|
||||
|
||||
const paths = resolveBundlingPaths(options);
|
||||
const pkgPath = paths.targetPackageJson;
|
||||
const pkg = await fs.readJson(pkgPath);
|
||||
@@ -39,6 +42,9 @@ export async function serveBundle(options: ServeOptions) {
|
||||
...options,
|
||||
isDev: true,
|
||||
baseUrl: url,
|
||||
getFrontendAppConfigs: () => {
|
||||
return latestFrontendAppConfigs;
|
||||
},
|
||||
});
|
||||
|
||||
const compiler = webpack(config);
|
||||
@@ -95,6 +101,13 @@ export async function serveBundle(options: ServeOptions) {
|
||||
});
|
||||
});
|
||||
|
||||
options.configChannel.port2.onmessage = ({
|
||||
data,
|
||||
}: MessageEvent<AppConfig[]>) => {
|
||||
latestFrontendAppConfigs = data;
|
||||
server.invalidate();
|
||||
};
|
||||
|
||||
const waitForExit = async () => {
|
||||
for (const signal of ['SIGINT', 'SIGTERM'] as const) {
|
||||
process.on(signal, () => {
|
||||
|
||||
@@ -22,7 +22,7 @@ export type BundlingOptions = {
|
||||
checksEnabled: boolean;
|
||||
isDev: boolean;
|
||||
frontendConfig: Config;
|
||||
frontendAppConfigs: AppConfig[];
|
||||
getFrontendAppConfigs(): AppConfig[];
|
||||
baseUrl: URL;
|
||||
parallelism?: number;
|
||||
};
|
||||
@@ -32,6 +32,7 @@ export type ServeOptions = BundlingPathsOptions & {
|
||||
frontendConfig: Config;
|
||||
frontendAppConfigs: AppConfig[];
|
||||
fullConfig: Config;
|
||||
configChannel: MessageChannel;
|
||||
};
|
||||
|
||||
export type BuildOptions = BundlingPathsOptions & {
|
||||
|
||||
@@ -19,7 +19,7 @@ import {
|
||||
loadConfig,
|
||||
loadConfigSchema,
|
||||
} from '@backstage/config-loader';
|
||||
import { ConfigReader } from '@backstage/config';
|
||||
import { AppConfig, ConfigReader } from '@backstage/config';
|
||||
import { paths } from './paths';
|
||||
import { isValidUrl } from './urls';
|
||||
import { getPackages } from '@manypkg/get-packages';
|
||||
@@ -33,6 +33,7 @@ type Options = {
|
||||
withDeprecatedKeys?: boolean;
|
||||
fullVisibility?: boolean;
|
||||
strict?: boolean;
|
||||
watch?: (newFrontendAppConfigs: AppConfig[]) => void;
|
||||
};
|
||||
|
||||
export async function loadCliConfig(options: Options) {
|
||||
@@ -80,6 +81,19 @@ export async function loadCliConfig(options: Options) {
|
||||
: undefined,
|
||||
configRoot: paths.targetRoot,
|
||||
configTargets: configTargets,
|
||||
watch: options.watch && {
|
||||
onChange(newAppConfigs) {
|
||||
const newFrontendAppConfigs = schema.process(newAppConfigs, {
|
||||
visibility: options.fullVisibility
|
||||
? ['frontend', 'backend', 'secret']
|
||||
: ['frontend'],
|
||||
withFilteredKeys: options.withFilteredKeys,
|
||||
withDeprecatedKeys: options.withDeprecatedKeys,
|
||||
ignoreSchemaErrors: !options.strict,
|
||||
});
|
||||
options.watch!(newFrontendAppConfigs);
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
// printing to stderr to not clobber stdout in case the cli command
|
||||
|
||||
Reference in New Issue
Block a user