From abd9decbb2b5b2c2a73ca7c32ce593f4fdfb69ca Mon Sep 17 00:00:00 2001 From: Stan Lewis Date: Wed, 27 Nov 2024 12:40:24 -0500 Subject: [PATCH] feat(cli): add flags to handle native deps (#2567) This change introduces two new flags to the CLI to handle transitive dependencies on packages containing native modules. `--allow-native-package [package-name...]` to selectively allow native packages when exporting a dynamic plugin and allowing it's installation into the exported dynamic plugin and `--suppress-native-package [package-name..]` which replaces the native package with an empty package during export, preventing the native package's inclusion into the exported dynamic plugin's private dependencies. Signed-off-by: Stan Lewis --- .changeset/long-pants-allow.md | 9 +++ .../backend-embed-as-dependencies.ts | 58 ++++++++++++++++--- packages/cli/src/commands/index.ts | 8 +++ 3 files changed, 66 insertions(+), 9 deletions(-) create mode 100644 .changeset/long-pants-allow.md diff --git a/.changeset/long-pants-allow.md b/.changeset/long-pants-allow.md new file mode 100644 index 0000000000..03a8ad64dd --- /dev/null +++ b/.changeset/long-pants-allow.md @@ -0,0 +1,9 @@ +--- +"@janus-idp/cli": patch +--- + +This change adds two new flags to handle native module dependencies. + +- `--allow-native-package [package-name...]`: flag to selectively allow native packages when exporting a dynamic plugin and allowing it's installation into the exported dynamic plugin. + +- `--suppress-native-package [package-name..]`: flag which replaces the native package with an empty package during export, preventing the native package's inclusion into the exported dynamic plugin's private dependencies. diff --git a/packages/cli/src/commands/export-dynamic-plugin/backend-embed-as-dependencies.ts b/packages/cli/src/commands/export-dynamic-plugin/backend-embed-as-dependencies.ts index b0afb4227f..303927c2e1 100644 --- a/packages/cli/src/commands/export-dynamic-plugin/backend-embed-as-dependencies.ts +++ b/packages/cli/src/commands/export-dynamic-plugin/backend-embed-as-dependencies.ts @@ -56,7 +56,10 @@ export async function backend(opts: OptionValues): Promise { ); } + const derivedPackageName = `${pkg.name}-dynamic`; const packagesToEmbed = (opts.embedPackage || []) as string[]; + const allowNative = (opts.allowNativePackage || []) as string[]; + const suppressNative = (opts.suppressNativePackage || []) as string[]; const monoRepoPackages = await getPackages(paths.targetDir); const embeddedResolvedPackages = await searchEmbedded( pkg, @@ -119,6 +122,30 @@ ${ }`, ); + if (suppressNative.length > 0) { + for (const toSuppress of suppressNative) { + await fs.mkdirs(path.join(target, 'embedded', toSuppress)); + await fs.writeFile( + path.join(target, 'embedded', toSuppress, 'package.json'), + JSON.stringify( + { + name: toSuppress, + main: 'index.js', + }, + undefined, + 2, + ), + ); + await fs.writeFile( + path.join(target, 'embedded', toSuppress, 'index.js'), + ` +throw new Error( + 'The package "${toSuppress}" has been marked as a native module and removed from this dynamic plugin package "${derivedPackageName}", as native modules are not currently supported by dynamic plugins' +);`, + ); + } + } + const embeddedPeerDependencies: { [key: string]: string; } = {}; @@ -205,11 +232,14 @@ ${ })(path.join(embeddedDestDir, 'package.json')); } - const embeddedDependenciesResolutions: { [key: string]: any } = {}; - embeddedResolvedPackages.map(ep => { - embeddedDependenciesResolutions[ep.packageName] = - `file:./${embeddedPackageRelativePath(ep)}`; - }); + const embeddedDependenciesResolutions = embeddedResolvedPackages.reduce( + (resolutions, ep) => { + resolutions[ep.packageName] = `file:./${embeddedPackageRelativePath(ep)}`; + + return resolutions; + }, + {} as { [key: string]: `file:./${string}` }, + ); if (opts.build) { Task.log(`Building main package`); @@ -247,7 +277,7 @@ ${ monoRepoPackages, sharedPackages: sharedPackagesRules, overridding: { - name: `${pkg.name}-dynamic`, + name: derivedPackageName, bundleDependencies: true, // 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: @@ -256,7 +286,14 @@ ${ // which are related to the packaging of the original static package. scripts: {}, }, - additionalResolutions: embeddedDependenciesResolutions, + additionalResolutions: { + ...embeddedDependenciesResolutions, + ...suppressNative + .map((nativePkg: string) => ({ + [nativePkg]: path.join('file:./embedded', nativePkg), + })) + .reduce((prev, curr) => ({ ...prev, ...curr }), {}), + }, after(mainPkg) { if (Object.keys(embeddedPeerDependencies).length === 0) { return; @@ -407,9 +444,12 @@ ${ // Check whether private dependencies contain native modules, and fail for now (not supported). const nativePackages: string[] = []; - for await (const n of gatherNativeModules(target)) { - nativePackages.push(n); + for await (const nativePkg of gatherNativeModules(target)) { + if (!allowNative.includes(nativePkg)) { + nativePackages.push(nativePkg); + } } + if (nativePackages.length > 0) { throw new Error( `Dynamic plugins do not support native plugins. the following native modules have been transitively detected:${chalk.cyan( diff --git a/packages/cli/src/commands/index.ts b/packages/cli/src/commands/index.ts index aa74f4099c..ac9b14ff1c 100644 --- a/packages/cli/src/commands/index.ts +++ b/packages/cli/src/commands/index.ts @@ -105,6 +105,14 @@ export function registerScriptCommand(program: Command) { }, {}, ) + .option( + '--allow-native-package [package-name...]', + 'Optional list of native packages names that can be included in the exported plugin', + ) + .option( + '--suppress-native-package [package-name...]', + 'Optional list of native package names to be excluded from the exported plugin', + ) .option( '--no-install', 'Do not run `yarn install` to fill the dynamic plugin `node_modules` folder (backend plugin only).',