Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor(cli): new --in-place/--no-in-place option to the export-dynamic-plugin CLI command to allow exporting to dist-dynamic (when value is false). #1584

Merged
merged 1 commit into from
Apr 30, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -600,7 +600,7 @@ function checkWorkspacePackageVersion(
);
}

function customizeForDynamicUse(options: {
export function customizeForDynamicUse(options: {
embedded: ResolvedEmbedded[];
monoRepoPackages: Packages | undefined;
sharedPackages?: SharedPackagesRules | undefined;
Expand Down
10 changes: 6 additions & 4 deletions packages/cli/src/commands/export-dynamic-plugin/command.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ import chalk from 'chalk';
import { OptionValues } from 'commander';
import fs from 'fs-extra';

import path from 'path';

import { paths } from '../../lib/paths';
import { getConfigSchema } from '../../lib/schema/collect';
import { Task } from '../../lib/tasks';
Expand All @@ -28,9 +30,9 @@ import { backend as backendEmbedAsDependencies } from './backend-embed-as-depend
import { applyDevOptions } from './dev';
import { frontend } from './frontend';

const saveSchema = async (packageName: string, path: string) => {
const saveSchema = async (packageName: string, destination: string) => {
const configSchema = await getConfigSchema(packageName);
await fs.writeJson(paths.resolveTarget(path), configSchema, {
await fs.writeJson(paths.resolveTarget(destination), configSchema, {
encoding: 'utf8',
spaces: 2,
});
Expand All @@ -53,10 +55,10 @@ export async function command(opts: OptionValues): Promise<void> {
} else {
targetPath = await backendEmbedAsCode(roleInfo, opts);
}
configSchemaPath = 'dist-dynamic/dist/configSchema.json';
configSchemaPath = path.join(targetPath, 'dist/configSchema.json');
} else if (role === 'frontend-plugin') {
targetPath = await frontend(roleInfo, opts);
configSchemaPath = 'dist-scalprum/configSchema.json';
configSchemaPath = path.join(targetPath, 'dist-scalprum/configSchema.json');
} else {
throw new Error(
'Only packages with the "backend-plugin", "backend-plugin-module" or "frontend-plugin" roles can be exported as dynamic backend plugins',
Expand Down
71 changes: 68 additions & 3 deletions packages/cli/src/commands/export-dynamic-plugin/frontend.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,20 +16,28 @@

import { PackageRoleInfo } from '@backstage/cli-node';

import { getPackages } from '@manypkg/get-packages';
import chalk from 'chalk';
import { OptionValues } from 'commander';
import fs from 'fs-extra';

import path from 'path';

import { buildScalprumPlugin } from '../../lib/builder/buildScalprumPlugin';
import { productionPack } from '../../lib/packager/productionPack';
import { paths } from '../../lib/paths';
import { Task } from '../../lib/tasks';
import { customizeForDynamicUse } from './backend-embed-as-dependencies';

export async function frontend(
_: PackageRoleInfo,
__: OptionValues,
opts: OptionValues,
): Promise<string> {
const {
name,
version,
scalprum: scalprumExternal,
files,
} = await fs.readJson(paths.resolveTarget('package.json'));

let scalprum = scalprumExternal;
Expand All @@ -54,7 +62,63 @@ export async function frontend(
);
}

await fs.remove(paths.resolveTarget('dist-scalprum'));
const distDynamicRelativePath = 'dist-dynamic';
const target = opts.inPlace
? path.resolve(paths.targetDir)
: path.resolve(paths.targetDir, distDynamicRelativePath);

if (!opts.inPlace) {
Task.log(
`Packing main package to ${chalk.cyan(
path.join(distDynamicRelativePath, 'package.json'),
)}`,
);

if (opts.clean) {
await fs.remove(target);
}

await fs.mkdirs(target);

await productionPack({
packageDir: paths.targetDir,
targetDir: target,
});

Task.log(
`Customizing main package in ${chalk.cyan(
path.join(distDynamicRelativePath, 'package.json'),
)} for dynamic loading`,
);
if (files && Array.isArray(files) && !files.includes('dist-scalprum')) {
files.push('dist-scalprum');
}
const monoRepoPackages = await getPackages(paths.targetDir);
await customizeForDynamicUse({
embedded: [],
monoRepoPackages,
overridding: {
name: `${name}-dynamic`,
// We remove scripts, because they do not make sense for this derived package.
// They even bring errors, especially the pre-pack and post-pack ones:
// we want to be able to use npm pack on this derived package to distribute it as a dynamic plugin,
// and obviously this should not trigger the backstage pre-pack or post-pack actions
// which are related to the packaging of the original static package.
scripts: {},
files,
},
})(path.resolve(target, 'package.json'));
}

const resolvedScalprumDistPath = path.join(target, 'dist-scalprum');

Task.log(
`Generating dynamic frontend plugin assets in ${chalk.cyan(
resolvedScalprumDistPath,
)}`,
);

await fs.remove(resolvedScalprumDistPath);

await buildScalprumPlugin({
writeStats: false,
Expand All @@ -65,7 +129,8 @@ export async function frontend(
version,
},
fromPackage: name,
resolvedScalprumDistPath,
});

return paths.targetDir;
return target;
}
10 changes: 9 additions & 1 deletion packages/cli/src/commands/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -123,8 +123,16 @@ export function registerScriptCommand(program: Command) {
)
.option(
'--embed-as-dependencies',
'Include embedded packages as private dependencies, instead of merging the with the generated code. Experimental for now, but expected to become the default.',
'Include embedded packages as private dependencies of backend plugins, instead of merging them with the generated code. Experimental for now, but expected to become the default.',
false,
)
.option('--no-embed-as-dependencies', undefined, true)
.option(
'--in-place',
'Adds the frontend dynamic plugin assets to the `dist-scalprum` folder of the original plugin package. When value is `false` (using `--no-in-place`), it produces the assets in a distinct package located in the `dist-dynamic` sub-folder, as for backend plugins. `true` by default for now, it is expected to become `false` by default.',
true,
)
.option('--no-in-place', undefined, false)
.action(lazy(() => import('./export-dynamic-plugin').then(m => m.command)));

command
Expand Down
5 changes: 4 additions & 1 deletion packages/cli/src/lib/builder/buildScalprumPlugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,12 @@ interface BuildScalprumPluginOptions {
configPaths: string[];
pluginMetadata: PluginBuildMetadata;
fromPackage: string;
resolvedScalprumDistPath: string;
}

export async function buildScalprumPlugin(options: BuildScalprumPluginOptions) {
const { targetDir, pluginMetadata, fromPackage } = options;
const { targetDir, pluginMetadata, fromPackage, resolvedScalprumDistPath } =
options;
await buildScalprumBundle({
targetDir,
entry: 'src/index',
Expand All @@ -23,5 +25,6 @@ export async function buildScalprumPlugin(options: BuildScalprumPluginOptions) {
args: [],
fromPackage,
})),
resolvedScalprumDistPath,
});
}
32 changes: 22 additions & 10 deletions packages/cli/src/lib/bundler/bundlePlugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,23 +23,35 @@ function applyContextToError(error: string, moduleName: string): string {
}

export async function buildScalprumBundle(
options: BundlingPathsOptions & DynamicPluginOptions,
options: BundlingPathsOptions &
DynamicPluginOptions & {
resolvedScalprumDistPath: string;
},
) {
const paths = resolveBundlingPaths(options);
const config = await createScalprumConfig(paths, {
...options,
checksEnabled: false,
isDev: false,
baseUrl: resolveBaseUrl(options.frontendConfig),
});
const config = await createScalprumConfig(
{
targetScalprumDist: options.resolvedScalprumDistPath,
...paths,
},
{
...options,
checksEnabled: false,
isDev: false,
baseUrl: resolveBaseUrl(options.frontendConfig),
},
);

const isCi = yn(process.env.CI, { default: false });

const previousFileSizes = await measureFileSizesBeforeBuild(
paths.targetScalprumDist,
options.resolvedScalprumDistPath,
);
await fs.emptyDir(paths.targetScalprumDist);
await fs.emptyDir(options.resolvedScalprumDistPath);

// TODO(davidfestal): ask @tumido or @Hyperkid123if this still makes sense here for dynamic plugins.
// That seems strange since the public assets are not copied to `dist-scalprum`,
// which is the place from where the dynamic plugin assets will be served
if (paths.targetPublic) {
await fs.copy(paths.targetPublic, paths.targetDist, {
dereference: true,
Expand All @@ -56,7 +68,7 @@ export async function buildScalprumBundle(
printFileSizesAfterBuild(
stats,
previousFileSizes,
paths.targetScalprumDist,
options.resolvedScalprumDistPath,
WARN_AFTER_BUNDLE_GZIP_SIZE,
WARN_AFTER_CHUNK_GZIP_SIZE,
);
Expand Down
1 change: 0 additions & 1 deletion packages/cli/src/lib/bundler/paths.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,6 @@ export function resolveBundlingPaths(options: BundlingPathsOptions) {
targetPath: resolvePath(targetDir, '.'),
targetRunFile: runFileExists ? targetRunFile : undefined,
targetDist: resolvePath(targetDir, 'dist'),
targetScalprumDist: resolvePath(targetDir, 'dist-scalprum'),
targetAssets: resolvePath(targetDir, 'assets'),
targetSrc: resolvePath(targetDir, 'src'),
targetDev: resolvePath(targetDir, 'dev'),
Expand Down
2 changes: 1 addition & 1 deletion packages/cli/src/lib/bundler/scalprumConfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ export const sharedModules = {
};

export async function createScalprumConfig(
paths: BundlingPaths,
paths: BundlingPaths & { targetScalprumDist: string },
options: DynamicPluginOptions,
): Promise<webpack.Configuration> {
const { checksEnabled, isDev } = options;
Expand Down
Loading