Skip to content

Unbundle mode does not emit reachable transitive facade module #927

@amanmahajan7

Description

@amanmahajan7

Reproduction link or steps

This description is generated using codex. I thought I created an issue but I cannot find it so this may be a duplicate.

I am trying to use tsdown with unbundle: true for a package that has an aggregate entry file and separate public subpath/facade entry files.

The simplified setup looks like this:

packages/
  ui/
    index.js
  card/
    index.js
    components/
      card.js
      content-card.js

The aggregate entry is packages/ui/index.js:

export * from '../card';

The card package has its own public facade file at packages/card/index.js:

export { default as Card } from './components/card.js';
export { BigCard } from './components/content-card.js';

The package export map points ./card at the generated facade path:

{
  "exports": {
    ".": "./dist/packages/ui/index.mjs",
    "./card": "./dist/packages/card/index.mjs"
  }
}

I have attached a sample project

tsdown-unbundle-facade-repro.zip

What is expected?

With unbundle: true, I expected tsdown to transform the reachable module graph while preserving file-level public entry/facade modules. In this case, I expected the build output to include:

dist/packages/ui/index.mjs
dist/packages/card/index.mjs
dist/packages/card/components/card.mjs
dist/packages/card/components/content-card.mjs

The important file is dist/packages/card/index.mjs. I expected it to preserve the public facade exports

What is actually happening?

Instead, tsdown emits the aggregate root and the implementation files, but does not emit the transitive facade module:

dist/packages/ui/index.mjs
dist/packages/card/components/card.mjs
dist/packages/card/components/content-card.mjs

The generated root file directly imports the implementation modules:

import Card from "../card/components/card.mjs";
import { BigCard } from "../card/components/content-card.mjs";
export { BigCard, Card };

So the root package import works but the subpath export is broken because dist/packages/card/index.mjs does not exist:

import { Card } from 'tsdown-unbundle-facade-repro/card';

Any additional comments?

This is surprising because packages/card/index.js is directly reachable from the aggregate entry and is also a public package facade/subpath target. Since unbundle mode is described as focusing on code transformation without combining files, I expected the reachable facade module to remain present in the output rather than being bypassed.

The workaround is to add packages/card/index.js as an explicit entry, but that does not scale well for a package that has many public facade/subpath modules reachable from a single aggregate entry.

Metadata

Metadata

Assignees

No one assigned

    Type

    Priority

    None yet

    Effort

    None yet

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions