As of Angular 14, ng-packagr 14.4.0 supports watching for changes in all of a library’s entry points, primary and secondary, with npm-link.
- Run
ng build --watch <project-name>
to build the library, and rebuild it when changes are made. - Run
cd dist/<project-name> && npm link
. - In a workspace to link, modify
tsconfig.json
as outlined in the section “TSConfig Paths for npm Link” below. - In the workspace to link, run
npm link <package-name>
wherepackage-name
is the library’s package name.- Note, running
npm install
will replace the link.
- Note, running
- In the workspace to link, run
ng build --watch <application-name>
whereapplication-name
is a dependent application or library.
The library and then application will be rebuilt automatically when changes are made. Developers are can perform library development without copying the library after every change and build. Libraries can be linked together, and multiple libraries can be developed at once.
TSConfig Paths for npm-link
Step three will require adding TSConfig path configurations to the linked workspace’s tsconfig.json
- quite a few more than alternatives. A linked package is a symlink to a workspace with a separate node_modules
directory. Node.js will resolve packages in the current and linked workspace resulting in various errors. Configuring skipLibChecks as true
does not resolve the issue. In testing, adding the paths to an application’s tsconfig.app.json
or library’s tsconfig.lib.json
did not work. The root tsconfig.json
was required.
The necessary paths will be those of packages installed in both workspaces and the library itself if there internal imports of entry points. The build errors are clues, but it is recommended to start with Angular. Add paths until the build succeeds. Only one wildcard can be used in each path, so multiple paths will be needed for libraries with multiple entry points and directories.
"paths": {
"@angular/*": ["node_modules/@angular/*"],
"@angular/common/*": ["node_modules/@angular/common/*"],
"rxjs": ["node_modules/rxjs"],
"@third-party-scope/third-party-lib": ["node_modules/@third-party-scope/third-party-lib"]
}
Examples
The following are examples of errors solved with a path configuration.
- Angular localization results in a redeclared global function.
error TS2451: Cannot redeclare block-scoped variable '$localize'.
- RxJS results in a type mismatch.
error TS2322: Type 'Observable<ArrayBuffer>' is not assignable to type 'Observable<WorkspaceCollection>'.
- In certain cases, the downstream build will modify the library’s
node_modules
and result in an upstream build failure.error NG6002: 'MyModule' does not appear to be an NgModule class.
Peer Dependencies
npm may not install all of a library’s peer dependencies, e.g. @angular/elements
.
error TS2307: Cannot find module '@angular/elements' or its corresponding type declarations.
Take the following steps to ensure the package is installed in subsequent runs.
- Delete
package-lock.json
. - Run
npm install <package-name>
. - Delete the newly added dependency from
package.json
. - Start at step three above to re-establish the link.
Alternatives
Linking is used for performing library development across workspaces. As outlined in SO#59356732, an alternative is to add a library’s output directory to an application’s TSConfig paths which has a similar result. In testing it required fewer path configurations but only supports TypeScript resources. Linking with npm supports changes to assests and resulted in less rebuilds in the dependent workspace on Windows.
For a single workspace, paths to a library’s output directory are added to the TSConfig of the workspace. It is not recommended to import from a library’s source, because the build output is different from source.
History
Prior to 14, watching for changes in libraries with npm-link was limited to the primary entry point, because webpack assumes that packages in node_modules
are only managed by a package manager. It remains that webpack only considers the package name and version when watching for changes to packages. Secondary entry points don’t have a package file. As of PR#2379, ng-packagr will update the primary entry point when changes are made to a secondary.