From ba673bbcb28e8783a107852cb780d81ad2b119bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Burzy=C5=84ski?= Date: Tue, 5 May 2026 23:16:01 +0200 Subject: [PATCH 1/2] Fix UMD alias resolution for multi-entrypoint package subpaths --- .changeset/tall-comics-kick.md | 5 ++ packages/cli/src/build/__tests__/build.ts | 67 +++++++++++++++++++++++ packages/cli/src/build/rollup.ts | 18 ++++-- packages/cli/test-utils/index.ts | 34 ++++++++---- 4 files changed, 108 insertions(+), 16 deletions(-) create mode 100644 .changeset/tall-comics-kick.md diff --git a/.changeset/tall-comics-kick.md b/.changeset/tall-comics-kick.md new file mode 100644 index 00000000..1865a63f --- /dev/null +++ b/.changeset/tall-comics-kick.md @@ -0,0 +1,5 @@ +--- +"@preconstruct/cli": patch +--- + +Fix UMD alias resolution for multi-entrypoint package subpaths diff --git a/packages/cli/src/build/__tests__/build.ts b/packages/cli/src/build/__tests__/build.ts index d24bdd3c..a7610587 100644 --- a/packages/cli/src/build/__tests__/build.ts +++ b/packages/cli/src/build/__tests__/build.ts @@ -428,6 +428,73 @@ test("monorepo umd with dep on other module", async () => { `); }); +test("monorepo umd with dep on multi-entrypoint module subpath", async () => { + let tmpPath = await testdir({ + "package.json": JSON.stringify({ + name: "monorepo-umd-subpath-alias", + main: "index.js", + workspaces: ["packages/*"], + + preconstruct: { + packages: ["packages/*"], + }, + }), + "packages/pkg-a/package.json": JSON.stringify({ + name: "pkg-a", + main: "dist/pkg-a.cjs.js", + "umd:main": "dist/pkg-a.umd.min.js", + + preconstruct: { + umdName: "pkgA", + }, + + dependencies: { + "pkg-b": "1.0.0", + }, + }), + "packages/pkg-a/src/index.js": js` + import thing from "pkg-b/stuff"; + + export default thing; + `, + "packages/pkg-b/package.json": JSON.stringify({ + name: "pkg-b", + main: "dist/pkg-b.cjs.js", + module: "dist/pkg-b.esm.js", + + preconstruct: { + entrypoints: ["index.js", "stuff.js"], + }, + }), + "packages/pkg-b/stuff/package.json": JSON.stringify({ + main: "dist/pkg-b-stuff.cjs.js", + module: "dist/pkg-b-stuff.esm.js", + }), + "packages/pkg-b/src/index.js": js` + export default "wrong entrypoint"; + `, + "packages/pkg-b/src/stuff.js": js` + export default "right entrypoint"; + `, + "node_modules/pkg-b": { + kind: "symlink", + path: "packages/pkg-b", + }, + }); + + await build(tmpPath); + + expect(await getFiles(path.join(tmpPath, "packages", "pkg-a"), ["dist/*umd*"])) + .toMatchInlineSnapshot(` + ⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ dist/pkg-a.umd.min.js ⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ + !function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):(e="undefined"!=typeof globalThis?globalThis:e||self).pkgA=t()}(this,(function(){"use strict";return"right entrypoint"})); + //# sourceMappingURL=pkg-a.umd.min.js.map + + ⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ dist/pkg-a.umd.min.js.map ⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ + {"version":3,"file":"pkg-a.umd.min.js","sources":["../../pkg-b/src/stuff.js"],"sourcesContent":["export default \\"right entrypoint\\";"],"names":[],"mappings":"2OAAe"} + `); +}); + test("monorepo single package", async () => { let tmpPath = f.copy("monorepo-single-package"); await initBasic(tmpPath); diff --git a/packages/cli/src/build/rollup.ts b/packages/cli/src/build/rollup.ts index a8fa6085..18b6eb04 100644 --- a/packages/cli/src/build/rollup.ts +++ b/packages/cli/src/build/rollup.ts @@ -228,18 +228,26 @@ export let getRollupConfig = ( function getAliases( project: Project -): { - [key: string]: string; -} { - let aliases: { [key: string]: string } = {}; +): Array<{ find: RegExp; replacement: string }> { + let aliases: Array<{ find: RegExp; replacement: string }> = []; project.packages.forEach((pkg) => { + // pkg.entrypoints are already expanded from the configured entrypoint globs + // and sorted in Package.create() for deterministic package.json#exports + // emission, so we preserve that same stable order here. pkg.entrypoints.forEach((entrypoint) => { - aliases[entrypoint.name] = entrypoint.source; + aliases.push({ + find: new RegExp(`^${escapeForRegex(entrypoint.name)}$`), + replacement: entrypoint.source, + }); }); }); return aliases; } +function escapeForRegex(value: string) { + return value.replace(/[|\\{}()[\]^$+*?.-]/g, "\\$&"); +} + const cjsDynamicImportPlugin: Plugin = { name: "cjs render dynamic import", renderDynamicImport({ format }) { diff --git a/packages/cli/test-utils/index.ts b/packages/cli/test-utils/index.ts index ba628358..da813191 100644 --- a/packages/cli/test-utils/index.ts +++ b/packages/cli/test-utils/index.ts @@ -347,19 +347,31 @@ async function getSymlinkType(targetPath: string): Promise<"dir" | "file"> { export async function testdir(dir: Fixture) { const temp = realFs.realpathSync.native(f.temp()); + const fileEntries: Array<[string, string]> = []; + const symlinkEntries: Array<[string, { kind: "symlink"; path: string }]> = []; + + for (const [filename, output] of Object.entries(dir)) { + if (typeof output === "string") { + fileEntries.push([filename, output]); + } else { + symlinkEntries.push([filename, output]); + } + } + + await Promise.all( + fileEntries.map(async ([filename, output]) => { + await fs.outputFile(path.join(temp, filename), output); + }) + ); + await Promise.all( - Object.keys(dir).map(async (filename) => { - const output = dir[filename]; + symlinkEntries.map(async ([filename, output]) => { const fullPath = path.join(temp, filename); - if (typeof output === "string") { - await fs.outputFile(fullPath, output); - } else { - const dir = path.dirname(fullPath); - await fs.ensureDir(dir); - const targetPath = path.resolve(temp, output.path); - const symlinkType = await getSymlinkType(targetPath); - await fs.symlink(targetPath, fullPath, symlinkType); - } + const dir = path.dirname(fullPath); + await fs.ensureDir(dir); + const targetPath = path.resolve(temp, output.path); + const symlinkType = await getSymlinkType(targetPath); + await fs.symlink(targetPath, fullPath, symlinkType); }) ); return temp; From 06d6b4fa73f03027cbb356ed2652af2aec254c28 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Burzy=C5=84ski?= Date: Tue, 5 May 2026 23:45:43 +0200 Subject: [PATCH 2/2] fmt --- packages/cli/src/build/__tests__/build.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/cli/src/build/__tests__/build.ts b/packages/cli/src/build/__tests__/build.ts index a7610587..e497cc32 100644 --- a/packages/cli/src/build/__tests__/build.ts +++ b/packages/cli/src/build/__tests__/build.ts @@ -484,8 +484,9 @@ test("monorepo umd with dep on multi-entrypoint module subpath", async () => { await build(tmpPath); - expect(await getFiles(path.join(tmpPath, "packages", "pkg-a"), ["dist/*umd*"])) - .toMatchInlineSnapshot(` + expect( + await getFiles(path.join(tmpPath, "packages", "pkg-a"), ["dist/*umd*"]) + ).toMatchInlineSnapshot(` ⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ dist/pkg-a.umd.min.js ⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ !function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):(e="undefined"!=typeof globalThis?globalThis:e||self).pkgA=t()}(this,(function(){"use strict";return"right entrypoint"})); //# sourceMappingURL=pkg-a.umd.min.js.map