Writing in the front

To give the Angular library more scope, Angular proposes a package format called: Angular Package Format includes FESM2015, FESM5, UMD, ESM2015, ESM5, and ES2015 formats, which can be used in different environments (Angular Cli, Webpack, SystemJS, and so on).

The traditional approach requires packaging each of these formats one by one, an example of packaging script writing. This is specific to the configuration of different projects and is difficult to maintain unless you understand the nature of these formats; The community has since implemented the nG-packagr class library based on the APF specification, and you can package your class library into the APF specification format with simple configuration.

Since V6, the Angular Cli has implemented another @angular-devkit/build-ng-packagr application builder based on ng-packagr.

How to use

Now that ng-packagr is built into the Angular Cli, it further simplifies the cost of producing a library in APF specification format. Use ng G Library in Angualr Cli to create a library template, for example in a new Angular application:

ng g library <library name>
Copy the code

And packaging, then:

ng build <library name>
Copy the code

Finally, upload the generated files in the dist/ directory to the corresponding package management server (for example, NPM) for others to use.

Configuration instructions

Most of the library templates generated by the Angular Cli are the same as Angular applications, with an additional ng-package.json configuration file (ng-package.prod.json for production environments). It is a configuration file specific to ng-packagr, which, like angular.json, is based on JSON Schema format, so you can access ng-package.schema.json for all the details, with highlights described below.

whitelistedNonPeerDependencies

By default, ng-packagr uses the peerDependencies listing in package.json to determine the dependencies needed by the library. These dependencies are not packaged into the library.

However, this property is required when the dependent package does not exist in the peerDependencies node.

lib/entryFile

Specify the entry file.

lib/umdModuleIds

The UMD format is rollup packed, and when libraries need to reference unguessed UMD identifiers, you need to manually map those identifiers.

"umdModuleIds": {
    "lodash": "_"
}
Copy the code

angular.json

The Angular Cli configuration file angular.json adds a build configuration named . Most of these configurations are identical to normal Angular applications, except that the Builder node is:

"builder": "@angular-devkit/build-ng-packagr:build"
Copy the code

The secondary entrance

Sometimes a library may contain multiple secondary entries, just as the @angular/core library contains an @angular/core/testing module that is only used for testing, so you don’t want to include testing code when you introduce @angular/core into your project. But this secondary import is very important when both are the same functionality.

Others, such as NGX-Bootstrap, @angular/ CDK/Ally, provide secondary module imports for better volume optimization.

For all intents and purposes, the Angular Cli’s simple file organization enables further packaging of primary and secondary libraries.

The structure generated by ng G library looks like this:

< libary name > ├ ─ ─ the SRC | ├ ─ ─ public_api. Ts | └ ─ ─ lib / * ts ├ ─ ─ ng - package. Json ├ ─ ─ ng - package. Prod. Json ├ ─ ─ package. The json ├ ─ ─ tsconfig. Lib. Json └ ─ ─ tsconfig. Spec. JsonCopy the code

If the root directory contains readme. md and LICENSE files, they will be automatically copied to the dist directory. Npm stipulates that the readme. md file must be included; otherwise, an error message will be displayed indicating that the description file is not found when accessing the published class library page.

To create a sub-entry for /testing, just create a testing directory under the root of :

< libary name > ├ ─ ─ the SRC | ├ ─ ─ public_api. Ts | └ ─ ─ lib / * ts ├ ─ ─ ng - package. Json ├ ─ ─ ng - package. Prod. Json ├ ─ ─ package. The json ├ ─ ─ tsconfig. Lib. Json ├ ─ ─ tsconfig. Spec. The json └ ─ ─ testing ├ ─ ─ the SRC | ├ ─ ─ public_api. Ts | └ ─ ─ * ts └ ─ ─ package. The jsonCopy the code

The core is to provide a package.json file that is as simple as grandma’s house.

{
    "ngPackage": {}}Copy the code

Finally, using ng build again produces a secondary import module.

summary

At this point, the Angular Cli is basically a quick way to build Angular libraries that can be published in Npm, and more complex ones like ngX-Bootstrap and @angular/ CDK /*.

Custom build

The Angular Cli provides a very convenient environment, but it can be a bit verbose in complex environments like the Delon library (ng-Alain Infrastructure series), which contains multiple libraries and secondary imports. In particular, the angular.json configuration for each class library. In fact, @angular-devkit/build-ng-packagr is very simple. If we simplify it further, the entire implementation is roughly equivalent to:

const path = require('path');
const ngPackage = require('ng-packagr');

const target = path.resolve(__dirname, './projects/<libary name>');

ngPackage
  .ngPackagr()
  .forProject(path.resolve(target, `ng-package.prod.json`))
  .withTsConfig(path.resolve(target, 'tsconfig.lib.json'))
  .build()
  .then((a)= > {
      // Do something after the build is complete
  });
Copy the code

Put the above code in./build.js and execute:

node scripts/build.js
Copy the code

The result completion is equivalent.

Build () returns a Promise object, meaning you can make sure you do a little extra before and after the build starts.

conclusion

Ng-packagr greatly simplifies Angular libraries. The ng-packagr is packaged as an APF specification recommendation. Although it starts with ng-, it doesn’t have to be used in Angular per se, but can also be used in React and VUE.