Skip to content

22.3.0-next build library change input entries source and output structure #34499

Closed as not planned

Description

@stephan-dum

Command

build

Description

This is meant as early feedback for 22.3.0-next to improve the interface before the final version is release as this is be a breaking change to the existing solution.

input entries source

The current implementation requires developers to add the entry points to package.json exports field.
If the package should now be publish the export will point to the .ts files instead of the actual compiled ones.

There are workaround for this for example

# deploy the dist folder of the angular wrapper that was created by ng-packgr
# npm no longer respects publishConfig.directory => physically replace the original folder with the built dist folder.

script:
    - mv packages/angular-library/dist /tmp/ng-dist
    - rm -rf packages/angular-library
    - mkdir -p packages/angular-library
    - cp -a /tmp/ng-dist/. packages/angular-library

output structure

currently the output structure is similar to ng-packagr:

  • dist
    • fesm2022
      • my-component.mjs
    • my-component
      • package.json
    • .npmignore
    • package.json

this is quite verbose and uses multiple package.json which are only used for development

the tsconfig will also need to be altered to point to the correct path:

{
  "compilerOptions": {
    "paths": {
      "angular-library/*": ["../angular-library/dist/*"]
    }
  }
}

Describe the solution you'd like

input entries source

instead of polluting the package.json an exports option could be added to angular.json build target instead.

{
  "$schema": "./node_modules/@angular/cli/lib/config/schema.json",
  "version": 1,
  "projects": {
    "angular-library": {
      "projectType": "library",
      "root": ".",
      "sourceRoot": "src",
      "architect": {
        "build": {
          "builder": "@angular/build:library",
          "options": {
            "exports": {
               ".": "src/barrel-file.ts",
               "./my-component": "src/lib/my-component.ts"
             }
          }
        }
      }
    }
  }
}

output structure

instead of writing multiple package.json the entry points can be directly written to the package.json exports field. This will result in a flat dist folder layout and no more need to configure tsconfig.

  • dist
    • my-component.mjs

Describe alternatives you've considered

No response

Activity

  1. added this to the needsTriage milestone on Oct 22, 2026
  2. stephan-dum commented on Oct 22, 2026

    @stephan-dum
    Author

    i can work on a PR for this is this is accepted

  3. alan-agius4 commented on Oct 22, 2026

    @alan-agius4
    Collaborator

    Thanks for the feedback! Both parts of the current design are intentional:

    1. Defining entry points via package.json exports

    The package.json in your library's source folder is an input manifest, not the file that gets published directly. When @angular/build:library runs, it generates a transformed package.json in the output directory (dist/<library-name>/package.json) where all TypeScript entry points in exports are automatically rewritten to point to the compiled FESM bundles and type definitions:

    "exports": {
      "./package.json": {
        "default": "./package.json"
      },
      ".": {
        "types": "./types/my-lib.d.ts",
        "default": "./fesm2022/my-lib.mjs"
      },
      "./my-component": {
        "types": "./types/my-lib-my-component.d.ts",
        "default": "./fesm2022/my-lib-my-component.mjs"
      }
    }

    Just like with ng-packagr, publishing should be done from the built output directory (e.g., npm publish dist/<library-name>) rather than the source directory.

    Using the library's package.json exports field as the single source of truth instead of adding a custom exports option in angular.json has several benefits:

    • It follows standard Node.js / package ecosystem conventions rather than introducing framework-specific configuration for package entry points.
    • Non-TypeScript exports (such as stylesheets, Sass partials, or other assets) and custom export conditions can be declared alongside TypeScript entry points in one place and are preserved in the built package.json.

    2. Output structure and Angular Package Format (APF)

    The output structure (fesm2022/, types/, and secondary <subpath>/package.json + .npmignore) follows the Angular Package Format (APF) specification:

    • Separating compiled bundles into fesm2022/ and declarations into types/ prevents naming collisions between entry points, shared code-split chunks, and static assets in the root of dist.
    • When TypeScript resolves imports through compilerOptions.paths in tsconfig.json (the default setup in Angular CLI workspaces without npm/pnpm workspaces), TypeScript does not evaluate exports on the target of a paths mapping it resolves the mapped path as a directory and reads <subpath>/package.json (types/typings). The nested package.json files are required for paths based resolution during development, and .npmignore ensures they are excluded when publishing to npm.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions