Skip to content

Commit b451380

Browse files
authored
refactor: experimental embed-as-dependencies option for the backend (#1418)
Experimental `embed-as-dependencies` option... Signed-off-by: David Festal <[email protected]>
1 parent 1295ff1 commit b451380

File tree

9 files changed

+1080
-128
lines changed

9 files changed

+1080
-128
lines changed

packages/cli/package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,8 @@
8787
"webpack": "^5.89.0",
8888
"webpack-dev-server": "^4.15.1",
8989
"yml-loader": "^2.1.0",
90-
"yn": "^4.0.0"
90+
"yn": "^4.0.0",
91+
"is-native-module": "^1.1.3"
9192
},
9293
"devDependencies": {
9394
"@backstage/backend-common": "0.21.3",

packages/cli/src/commands/export-dynamic-plugin/backend.ts renamed to packages/cli/src/commands/export-dynamic-plugin/backend-embed-as-code.ts

Lines changed: 34 additions & 109 deletions
Original file line numberDiff line numberDiff line change
@@ -15,17 +15,14 @@
1515
*/
1616

1717
import { BackstagePackageJson, PackageRoleInfo } from '@backstage/cli-node';
18-
import { ConfigReader } from '@backstage/config';
19-
import { loadConfig } from '@backstage/config-loader';
2018

2119
import { getPackages } from '@manypkg/get-packages';
2220
import { OptionValues } from 'commander';
2321
import fs from 'fs-extra';
2422
import { InteropType, rollup } from 'rollup';
25-
import * as semver from 'semver';
2623

2724
import { execSync } from 'child_process';
28-
import path, { basename } from 'path';
25+
import path from 'path';
2926

3027
import { Output } from '../../lib/builder';
3128
import { makeRollupConfigs } from '../../lib/builder/config';
@@ -35,11 +32,15 @@ import { readEntryPoints } from '../../lib/entryPoints';
3532
import { productionPack } from '../../lib/packager/productionPack';
3633
import { paths } from '../../lib/paths';
3734
import { Task } from '../../lib/tasks';
35+
import {
36+
addToDependenciesForModule,
37+
addToMainDependencies,
38+
} from './backend-utils';
3839

3940
export async function backend(
4041
roleInfo: PackageRoleInfo,
4142
opts: OptionValues,
42-
): Promise<void> {
43+
): Promise<string> {
4344
if (!fs.existsSync(paths.resolveTarget('src', 'dynamic'))) {
4445
console.warn(
4546
`Package doesn't seem to provide dynamic loading entrypoints. You might want to add dynamic loading entrypoints in a src/dynamic folder.`,
@@ -166,46 +167,15 @@ export async function backend(
166167
rollupConfig.plugins?.push(
167168
embedModules({
168169
filter: filter,
169-
addDependency(embeddedModule, dependencyName, newDependencyVersion) {
170-
const existingDependencyVersion = dependenciesToAdd[dependencyName];
171-
if (existingDependencyVersion === undefined) {
172-
dependenciesToAdd[dependencyName] = newDependencyVersion;
173-
return;
174-
}
175-
176-
if (existingDependencyVersion === newDependencyVersion) {
177-
return;
178-
}
179-
180-
const existingDependencyMinVersion = semver.minVersion(
181-
existingDependencyVersion,
182-
);
183-
if (
184-
existingDependencyMinVersion &&
185-
semver.satisfies(existingDependencyMinVersion, newDependencyVersion)
186-
) {
187-
console.log(
188-
`Several compatible versions ('${existingDependencyVersion}', '${newDependencyVersion}') of the same transitive dependency ('${dependencyName}') for embedded module ('${embeddedModule}'): keeping '${existingDependencyVersion}'`,
189-
);
190-
return;
191-
}
192-
193-
const newDependencyMinVersion = semver.minVersion(newDependencyVersion);
194-
if (
195-
newDependencyMinVersion &&
196-
semver.satisfies(newDependencyMinVersion, existingDependencyVersion)
197-
) {
198-
dependenciesToAdd[dependencyName] = newDependencyVersion;
199-
console.log(
200-
`Several compatible versions ('${existingDependencyVersion}', '${newDependencyVersion}') of the same transitive dependency ('${dependencyName}') for embedded module ('${embeddedModule}'): keeping '${newDependencyVersion}'`,
201-
);
202-
return;
203-
}
204-
205-
throw new Error(
206-
`Several incompatible versions ('${existingDependencyVersion}', '${newDependencyVersion}') of the same transitive dependency ('${dependencyName}') for embedded module ('${embeddedModule}')`,
207-
);
208-
},
170+
addDependency: (embeddedModule, dependencyName, newDependencyVersion) =>
171+
addToDependenciesForModule(
172+
{
173+
name: dependencyName,
174+
version: newDependencyVersion,
175+
},
176+
dependenciesToAdd,
177+
embeddedModule,
178+
),
209179
}),
210180
);
211181

@@ -267,33 +237,19 @@ export async function backend(
267237
f => !f.startsWith('dist-dynamic/'),
268238
);
269239

270-
for (const dep in dependenciesToAdd) {
271-
if (!Object.prototype.hasOwnProperty.call(dependenciesToAdd, dep)) {
272-
continue;
273-
}
274-
pkgToCustomize.dependencies ||= {};
275-
const existingVersion = pkgToCustomize.dependencies[dep];
276-
if (existingVersion === undefined) {
277-
pkgToCustomize.dependencies[dep] = dependenciesToAdd[dep];
278-
continue;
279-
}
280-
if (existingVersion !== dependenciesToAdd[dep]) {
281-
const existingMinVersion = semver.minVersion(existingVersion);
282-
283-
if (
284-
existingMinVersion &&
285-
semver.satisfies(existingMinVersion, dependenciesToAdd[dep])
286-
) {
287-
console.log(
288-
`The version of a dependency ('${dep}') of an embedded module differs from the main module's dependencies: '${dependenciesToAdd[dep]}', '${existingVersion}': keeping it as it is compatible`,
289-
);
290-
} else {
291-
throw new Error(
292-
`The version of a dependency ('${dep}') of an embedded module conflicts with main module dependencies: '${dependenciesToAdd[dep]}', '${existingVersion}': cannot proceed!`,
293-
);
294-
}
295-
}
240+
// We remove scripts, because they do not make sense for this derived package.
241+
// They even bring errors, especially the pre-pack and post-pack ones:
242+
// we want to be able to use npm pack on this derived package to distribute it as a dynamic plugin,
243+
// and obviously this should not trigger the backstage pre-pack or post-pack actions
244+
// which are related to the packaging of the original static package.
245+
pkgToCustomize.scripts = {};
246+
247+
const pkgDependencies = pkgToCustomize.dependencies || {};
248+
addToMainDependencies(dependenciesToAdd, pkgDependencies);
249+
if (Object.keys(pkgDependencies).length > 0) {
250+
pkgToCustomize.dependencies = pkgDependencies;
296251
}
252+
297253
if (pkgToCustomize.dependencies) {
298254
for (const monoRepoPackage of monoRepoPackages.packages) {
299255
if (pkgToCustomize.dependencies[monoRepoPackage.packageJson.name]) {
@@ -376,10 +332,13 @@ export async function backend(
376332
}
377333

378334
if (opts.install) {
379-
const version = execSync('yarn --version').toString().trim();
335+
const yarn = 'yarn';
336+
const version = execSync(`${yarn} --version`).toString().trim();
380337
const yarnInstall = version.startsWith('1.')
381-
? `yarn install --production${yarnLockExists ? ' --frozen-lockfile' : ''}`
382-
: `yarn install${yarnLockExists ? ' --immutable' : ''}`;
338+
? `${yarn} install --production${
339+
yarnLockExists ? ' --frozen-lockfile' : ''
340+
}`
341+
: `${yarn} install${yarnLockExists ? ' --immutable' : ''}`;
383342

384343
await Task.forCommand(yarnInstall, { cwd: target, optional: false });
385344
await fs.remove(paths.resolveTarget('dist-dynamic', '.yarn'));
@@ -393,39 +352,5 @@ export async function backend(
393352
minify: Boolean(opts.minify),
394353
});
395354

396-
if (opts.dev) {
397-
const appConfigs = await loadConfig({
398-
configRoot: paths.targetRoot,
399-
configTargets: [],
400-
});
401-
const fullConfig = ConfigReader.fromConfigs(appConfigs.appConfigs);
402-
403-
const dynamicPlugins = fullConfig.getOptional('dynamicPlugins');
404-
if (
405-
typeof dynamicPlugins === 'object' &&
406-
dynamicPlugins !== null &&
407-
'rootDirectory' in dynamicPlugins &&
408-
typeof dynamicPlugins.rootDirectory === 'string'
409-
) {
410-
await fs.ensureSymlink(
411-
paths.resolveTarget('src'),
412-
path.resolve(target, 'src'),
413-
'dir',
414-
);
415-
const dynamicPluginsRootPath = path.isAbsolute(
416-
dynamicPlugins.rootDirectory,
417-
)
418-
? dynamicPlugins.rootDirectory
419-
: paths.resolveTargetRoot(dynamicPlugins.rootDirectory);
420-
await fs.ensureSymlink(
421-
target,
422-
path.resolve(dynamicPluginsRootPath, basename(paths.targetDir)),
423-
'dir',
424-
);
425-
} else {
426-
throw new Error(
427-
`'dynamicPlugins.rootDirectory' should be configured in the app config in order to use the --dev option.`,
428-
);
429-
}
430-
}
355+
return target;
431356
}

0 commit comments

Comments
 (0)