keepcalculator

06 Numbers and Powers

Angular Package Format (APF) Explained

Card No. 06·52240 · Updated · Standard formula, shown below

The Angular Package Format (APF) is the official specification that defines how Angular libraries are structured, built, and published to npm. It ensures that a library works seamlessly with the Angular compiler, the Ahead-of-Time (AOT) compiler, and the various build optimizations used in modern Angular applications. In practice, APF dictates the files a library must ship (such as FESM bundles, TypeScript definitions, and metadata), the module formats to use, and the directory layout. This article explains what APF is, why it exists, how it works, and what it means for developers who create or consume Angular libraries.

Background: Why APF Exists

Before APF, Angular libraries were published in a variety of formats, often with inconsistent file structures. This caused problems for the Angular compiler and for bundlers like webpack or Rollup. The Angular team introduced APF to standardize the packaging of libraries, making them compatible with the Angular ecosystem’s tooling. The specification has evolved over time—each major Angular version has updated APF to reflect new compiler features, module formats, and optimization techniques. For example, Angular 13 removed the deprecated View Engine compiler, and APF v13 dropped support for the older metadata format, relying instead on the modern Angular Ivy compiler.

Core Components of APF

An Angular library published according to APF typically includes several key files and directories. The package.json file is central, as it defines entry points and module formats. The main fields are:

  • main: Points to a CommonJS bundle (e.g., bundles/my-lib.umd.js in older versions, or fesm2015/my-lib.js in newer ones).
  • module: Points to an ES2015 module bundle (FESM2015).
  • es2015: Points to the ES2015 module bundle (same as module in recent versions).
  • esm2015: Points to the ES2015 module source files (for debugging and build tools).
  • fesm2015 and fesm2020: Flat ES modules, which are single-file ES module bundles that include all code from the library, with no internal imports.
  • typings: Points to the TypeScript declaration files (.d.ts).
  • metadata: (Deprecated in Ivy) Points to the .metadata.json file used by the View Engine compiler.

For Ivy, APF also requires the compilerOptions in the library’s tsconfig.json to include "angularCompilerOptions": {"enableIvy": true} (though this is now the default). The library must also include the ngcc (Angular Compatibility Compiler) markers, which are files like __ivy_ngcc__ that indicate the library has been processed for Ivy compatibility.

How APF Works: Module Formats and Bundles

APF specifies multiple module formats to support different consumption scenarios. The primary formats are:

  • ESM (ES Modules): The native JavaScript module format. APF requires both ES2015 and ES2020 versions. ES2020 is the modern standard, supporting dynamic imports and top-level await.
  • FESM (Flat ES Module): A single file that contains the entire library’s code in ES module format, with no internal imports. This allows bundlers to tree-shake more effectively.
  • CommonJS: For older Node.js environments and some bundlers. This is provided for backward compatibility.
  • UMD (Universal Module Definition): In older APF versions, this was required for direct script inclusion. It is now deprecated but still present in many existing libraries.

The Angular compiler uses the module and es2015 fields to determine which bundle to use for AOT compilation. The fesm2015 and fesm2020 bundles are used by bundlers to optimize the final application bundle. The TypeScript definitions (.d.ts) are essential for type checking and IDE support.

How to Choose the Right APF for Your Library

If you are publishing an Angular library, you should follow the latest APF version that matches the Angular version you are targeting. For example, if you are using Angular 15 or later, you should target APF v15 or v16. The Angular CLI’s ng-packagr tool automatically generates the correct APF structure when you use ng generate library. You can also manually configure your library’s package.json to match the APF spec. Key decisions include:

  • Whether to ship both ES2015 and ES2020 bundles (recommended for broad compatibility).
  • Whether to include UMD bundles (only if you need to support script tags).
  • Whether to provide partial compilation (Ivy partial) to reduce build times for consumers.

For most libraries, using ng-packagr with the default settings is sufficient. It will generate all necessary files and update package.json automatically.

Common Problems and Misconceptions

One common misconception is that APF is a runtime format. In reality, APF is a build-time specification—it defines how the library is packaged for distribution, not how it behaves at runtime. Another issue is that developers sometimes forget to update the package.json fields when they add new entry points (e.g., a submodule like my-lib/feature). Each entry point needs its own set of fields and files. Additionally, mixing View Engine and Ivy libraries can cause errors. If you are using Angular 13 or later, all libraries must be Ivy-compatible; otherwise, you will see compilation errors.

Another frequent problem is incorrect sideEffects flag in package.json. If your library has side effects (e.g., it modifies global styles), you must set "sideEffects": true to prevent bundlers from tree-shaking them away. Conversely, if your library is pure, set it to false to enable aggressive tree-shaking.

Comparison: APF vs. Other Package Formats

APF is specific to Angular. Other frameworks have their own packaging standards, such as React’s esm and cjs fields, or Vue’s module and main fields. APF is more prescriptive because Angular’s compiler requires specific metadata and module formats to perform AOT and tree-shaking. Unlike generic npm packages, Angular libraries must include Angular-specific files like .d.ts and (historically) .metadata.json. APF also mandates the use of ngcc for Ivy compatibility, which is unique to Angular.

Costs and Benefits of Following APF

Following APF has a learning curve, but it provides significant benefits:

  • Compatibility: Ensures your library works with Angular’s toolchain and future versions.
  • Optimization: Enables tree-shaking and AOT, reducing bundle size.
  • Developer Experience: Provides TypeScript definitions and clear entry points, improving IDE support.

The main cost is the initial setup and the need to keep up with APF changes across Angular versions. However, using ng-packagr automates most of the work, so the cost is minimal for most developers.

Safety and Best Practices

When publishing an Angular library, always test it with the minimum supported Angular version and the latest one. Use the ng-packagr tool to generate the build, and verify the output with npm pack and a local test application. Avoid shipping source maps in production to reduce package size, but include them in the npm package if you want to support debugging. Also, ensure your library’s peerDependencies correctly list Angular packages, so consumers get the right versions.

Frequently Asked Questions

What is the difference between FESM2015 and FESM2020?

FESM2015 is a flat ES module bundle using ES2015 syntax, while FESM2020 uses ES2020 syntax. The latter is more modern and allows features like optional chaining and nullish coalescing. Modern bundlers prefer FESM2020 for better optimization, but FESM2015 is still needed for older tooling.

Do I need to manually create the APF structure?

No. The Angular CLI’s ng-packagr generates the APF structure automatically when you create a library with ng generate library. You can customize the output by modifying the ng-package.json file.

What is the metadata.json file used for?

It was used by the View Engine compiler to store metadata for AOT compilation. Since Angular 13, View Engine is deprecated, and Ivy uses the TypeScript definitions directly. Therefore, metadata.json is no longer required in new libraries.

Can I publish an Angular library without following APF?

Technically, you can publish any npm package, but it will not work with Angular’s AOT compiler or the CLI’s build optimizations. Consumers would likely encounter errors or be unable to use the library. Following APF is essential for a smooth experience.

What is partial Ivy compilation?

Partial Ivy compilation is a feature introduced in Angular 12 that allows libraries to be compiled to a partial format, which the application’s build then completes. This reduces build times for consumers and is the default for libraries created with Angular 13 and later.

How do I add a submodule to my Angular library?

You need to create a separate entry point in your library’s ng-package.json and build it with ng-packagr. This generates a separate set of APF files for the submodule, and you must update the library’s package.json exports field to include it.

Related

Method: the standard formula for this calculation, rounded as each result states. See how the calculators work or report an error.

More cards in this drawer

The whole Numbers and Powers drawer →