diff --git a/.changeset/chatty-coats-thank.md b/.changeset/chatty-coats-thank.md new file mode 100644 index 0000000000..17faf43d87 --- /dev/null +++ b/.changeset/chatty-coats-thank.md @@ -0,0 +1,5 @@ +--- +'@backstage/cli': patch +--- + +Fix the build for packages with multiple entry points to avoid duplicated modules. diff --git a/packages/cli/src/lib/builder/config.ts b/packages/cli/src/lib/builder/config.ts index 3e61dd113a..7bd10cfcc3 100644 --- a/packages/cli/src/lib/builder/config.ts +++ b/packages/cli/src/lib/builder/config.ts @@ -75,117 +75,126 @@ export async function makeRollupConfigs( const distDir = resolvePath(targetDir, 'dist'); const entryPoints = readEntryPoints(targetPkg); - for (const { path, name, ext } of entryPoints) { - if (!SCRIPT_EXTS.includes(ext)) { - continue; - } + const scriptEntryPoints = entryPoints.filter(e => + SCRIPT_EXTS.includes(e.ext), + ); - if (options.outputs.has(Output.cjs) || options.outputs.has(Output.esm)) { - const output = new Array(); - const mainFields = ['module', 'main']; + if (options.outputs.has(Output.cjs) || options.outputs.has(Output.esm)) { + const output = new Array(); + const mainFields = ['module', 'main']; - if (options.outputs.has(Output.cjs)) { - output.push({ - dir: distDir, - entryFileNames: `${name}.cjs.js`, - chunkFileNames: `cjs/${name}/[name]-[hash].cjs.js`, - format: 'commonjs', - sourcemap: true, - }); - } - if (options.outputs.has(Output.esm)) { - output.push({ - dir: distDir, - entryFileNames: `${name}.esm.js`, - chunkFileNames: `esm/${name}/[name]-[hash].esm.js`, - format: 'module', - sourcemap: true, - }); - // Assume we're building for the browser if ESM output is included - mainFields.unshift('browser'); - } - - configs.push({ - input: resolvePath(targetDir, path), - output, - onwarn, - preserveEntrySignatures: 'strict', - // All module imports are always marked as external - external: (source, importer, isResolved) => - Boolean(importer && !isResolved && !isFileImport(source)), - plugins: [ - resolve({ mainFields }), - commonjs({ - include: /node_modules/, - exclude: [/\/[^/]+\.(?:stories|test)\.[^/]+$/], - }), - postcss(), - forwardFileImports({ - exclude: /\.icon\.svg$/, - include: [ - /\.svg$/, - /\.png$/, - /\.gif$/, - /\.jpg$/, - /\.jpeg$/, - /\.eot$/, - /\.woff$/, - /\.woff2$/, - /\.ttf$/, - /\.md$/, - ], - }), - json(), - yaml(), - svgr({ - include: /\.icon\.svg$/, - template: svgrTemplate, - }), - esbuild({ - target: 'es2019', - minify: options.minify, - }), - ], + if (options.outputs.has(Output.cjs)) { + output.push({ + dir: distDir, + entryFileNames: `[name].cjs.js`, + chunkFileNames: `cjs/[name]-[hash].cjs.js`, + format: 'commonjs', + sourcemap: true, }); } + if (options.outputs.has(Output.esm)) { + output.push({ + dir: distDir, + entryFileNames: `[name].esm.js`, + chunkFileNames: `esm/[name]-[hash].esm.js`, + format: 'module', + sourcemap: true, + }); + // Assume we're building for the browser if ESM output is included + mainFields.unshift('browser'); + } - if (options.outputs.has(Output.types) && !options.useApiExtractor) { - const typesInput = paths.resolveTargetRoot( - 'dist-types', - relativePath(paths.targetRoot, targetDir), - path.replace(/\.ts$/, '.d.ts'), - ); + configs.push({ + input: Object.fromEntries( + scriptEntryPoints.map(e => [e.name, resolvePath(targetDir, e.path)]), + ), + output, + onwarn, + preserveEntrySignatures: 'strict', + // All module imports are always marked as external + external: (source, importer, isResolved) => + Boolean(importer && !isResolved && !isFileImport(source)), + plugins: [ + resolve({ mainFields }), + commonjs({ + include: /node_modules/, + exclude: [/\/[^/]+\.(?:stories|test)\.[^/]+$/], + }), + postcss(), + forwardFileImports({ + exclude: /\.icon\.svg$/, + include: [ + /\.svg$/, + /\.png$/, + /\.gif$/, + /\.jpg$/, + /\.jpeg$/, + /\.eot$/, + /\.woff$/, + /\.woff2$/, + /\.ttf$/, + /\.md$/, + ], + }), + json(), + yaml(), + svgr({ + include: /\.icon\.svg$/, + template: svgrTemplate, + }), + esbuild({ + target: 'es2019', + minify: options.minify, + }), + ], + }); + } - const declarationsExist = await fs.pathExists(typesInput); + if (options.outputs.has(Output.types) && !options.useApiExtractor) { + const input = Object.fromEntries( + scriptEntryPoints.map(e => [ + e.name, + paths.resolveTargetRoot( + 'dist-types', + relativePath(paths.targetRoot, targetDir), + e.path.replace(/\.ts$/, '.d.ts'), + ), + ]), + ); + + for (const path of Object.values(input)) { + const declarationsExist = await fs.pathExists(path); if (!declarationsExist) { - const declarationPath = relativePath(targetDir, typesInput); + const declarationPath = relativePath(targetDir, path); throw new Error( `No declaration files found at ${declarationPath}, be sure to run ${chalk.bgRed.white( 'yarn tsc', )} to generate .d.ts files before packaging`, ); } - - configs.push({ - input: typesInput, - output: { - file: resolvePath(distDir, `${name}.d.ts`), - format: 'es', - }, - external: [ - /\.css$/, - /\.scss$/, - /\.sass$/, - /\.svg$/, - /\.eot$/, - /\.woff$/, - /\.woff2$/, - /\.ttf$/, - ], - onwarn, - plugins: [dts()], - }); } + + configs.push({ + input, + output: { + dir: distDir, + entryFileNames: `[name].d.ts`, + chunkFileNames: `types/[name]-[hash].d.ts`, + format: 'es', + }, + external: [ + /\.css$/, + /\.scss$/, + /\.sass$/, + /\.svg$/, + /\.eot$/, + /\.woff$/, + /\.woff2$/, + /\.ttf$/, + ], + onwarn, + plugins: [dts()], + }); } return configs;