How to set up an Angular 2 Component Library

 

What is a library good for?

Creating a library for very generic components which are used throughout an app makes total sense when you think about reusability, versioning, separate maintainability or even making it public to support the community. These are the reason we decided to build a HQ Component Library for our apps where we are including components and generic controls which we are reusing relatively often throughout the app. These are e.g. grids, certain types of buttons, modals, tooltips, alerts, menus etc.
For creating a component library we had several requirements to suit our quality and production build need. These are:

  • Availability on npm to make the automated build process (CI) as lean and easy as possible as well as for handling the versioning
  • Automated tests to ensure a high quality standard
  • Creating stylesheets with sass to benefit from the advantages of mixins, a clear syntax and global variables
  • An automated production build process which compiles the whole package at once including all the needed typescript and sass compilation
  • Linting the css and the typescript code to ensure a high standard of code quality

We haven’t finishes all of the requirements yet, but here ist how we started.

Creating the library

An example project can be found here on GitHub.

The content of the final library looks something like this:

— index.js
— index.d.ts
— lib
—- index.js
—- index.d.ts
—- library.module.js
—- library.module.d.ts
—- library.module.js.map
—- library.module.d.ts.map
—– components
——- componentA.component.js
——- componentA.component.d.ts
——- componentA.component.js.map
——- componentA.component.d.ts.map
— packages.json

It mainly includes an index file which is being accessed by the apps and exposes the modules and components. In the lib folder on the top most level you can find the library module. The module exposes all components and therefore needs to be imported in certain modules of the app later. Once imported, every component of it can be used in the templates of the components of our app.

In the components folder all the components/controls are located. The *.d.ts files are declaration files of TypeScript so we get the TypeScript benefits of static type checking while still using a pure JS library. The *.js.map files are source map files that let tools map between the emitted JavaScript code and the TypeScript source files that created it. These files aren’t created by a normal TypeScript build. You need to tell the TypeScript compiler to do so.

As you can see, there are no *.css and *.html files located at our components. That’s because our build task writes the templates and styles inline to avoid any kind of reference problems and 404 errors.

Lastly there is the package.json file, which exposes which node_modules are needed by the library.

Our library source code looks more like this:

— index.ts
— src
—- index.ts
—- tsconfig.json
—- library.module.ts
—– components
——- componentsA.component.html
——- componentsA.component.ts
——- componentsA.component.scss
— node_modules
— examples
— packages.json
— gulpfile.ts
— .npmignore
— .gitignore

The structure is quite similar but instead of the lib, we have a src folder and all files are uncompiled (sass, ts). We additionally have an example folder where a small Angular app is located to test the components directly when creating them.

There is a gulp-file which contains our build steps to get to the compiled library. We have an ignore-file for our git repository and for npm. In the src folder we have a tsconfig file where the configuration of our TypeScript compiler is made. That’s basically it! What currently cannot be found are the linting and testing files. But we are working on that at the moment.

How to compile the source?

After we created our base library containing the exposing ngModule and a simple component, we set up a sequence of tasks to automatically do the TypeScript compilation of the source files and the other necessary files with gulp. For our first library build we need to make the TypeScript compilation into our lib folder, to compile the scss to css, move the templates and styles inline and clean the lib folder at the very beginning of the build process.

We do so by setting up a gulp task.

1. Installing gulp

First we need to install the necessary gulp tasks for our build steps. To make the gulp task sequence a little more easy, we use run-sequence to just create an array of separate gulp tasks which are run during the build.

So we installed gulp-install to use gulp, run-sequence for running task sequences, gulp-typescript for TypeScript compilation, gulp-sourcemaps for source map creation, gulp-sass for sass compilation, gulp-minify-css to minify our css, gulp-inline-ng2-template to embed styles and templates into the components and child_process to execute a simple cleanup of the library folder.

For all of them we used

to create local dev dependencies to these packages, because we only need them to build the library and not to consume it.

2. Create tasks in the gulp file

In the root folder of our library we have to create the gulpfile.ts. In that gulp file, we had to require all the gulp packages we just installed and then build a task for every step. The main build task, which we named build, only runs a sequence of all the created gulp tasks.

Our typings file, which is loaded via the tsc.createProject in the build steps, looks like this. With this configuration, our library is consumable by an Angular CLI app out of the box.

3. Create a script in the package.json

To run the the gulp file, we created a scripts section in our package.json. We named our script build which then executes gulp build. When running npm run build in our package manager console, it automatically starts the gulp task build which does the whole build process of our library.

Publishing the library at npm

After creating the library and making a running build of it, we want to publish in on npm to make it easily consumable for our app. Therefore, we need to create an account at npm. No big deal. In our package manager console we then have to log in with our newly created credentials with

npm provides a specified versioning of the packages. Our first version is something like 0.1.0 or can be even something like 1.0.0. Every time something is being fixed and no larger changes have been made, we just call

in the console to increase the very last patch number of our version. You can look up the versioning system in the npm docs.

After building and versioning our library, we can publish it to npm. If you are using git on your repository, make sure you committed everything, otherwise npm will ask you to. To publish your library just type

in your console, and the upload will automatically start. The library is now ready to be consumed!

Consuming the library

To install the dependency of the library from npm, just type

in your angular application. This will install the package automatically and add it to your package.json.

Angular recommends to manually add the typings if the library doesn’t have typings available at @types in the typings.d.ts of your Angular app:

If you want to publish the @types of your library too on npm, you can figure out how to do that in the Typescript docs

To use the library, you have to import the library module in your ngModule which declares the components. Just import the module like this:

You can now use all the library components within your components. In the components itself you do not need to import the whole module, you can also import single components only if your need them in your TypeScript code.

A small hint when using continuous integration

When you want to consume a private library via npm on a build server, you do not have to log in the server itself. Instead, you can set up a task in your CI steps like

where XYZ is your authentication token, which can be found in your local npmrc file once you are logged in on your development machine.

And that’s it! We created our first Angular library.


Btw, we’re hiring 😉 Join our Angular team!
Front-End Jobs
Back-End Jobs


Get Angularity updates

 

Es gibt schon 3 Kommentare

  • Mathias
    Antworten

    Hi Lucas,

    thanks for sharing this!
    One comment, within package.json, the name property must not contain spaces. I could not install any dependency like that.

    Cheers, Mathias

  • Timofeysie
    Antworten

    Hi Lucas,
    Do you have some sample code on how to use the my-notification.component in another project after importing the library? This would help improve this post!

  • Lucas
    Antworten

    Hi Timo,

    currently not, but I will take care of that.
    You basically have to include the library to your package.json,
    declare the library in your typings.d.ts,
    import the library in the your module and then you can use it in your templates with the given selector like .

    Cheers
    Lucas

Schreibe den ersten Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.