When you do a web search for “new Angular library” you’ll get to the Angular docs for Creating libraries. If you’re not familiar with Angular concepts like Workspaces and Projects, you will probably want to skim read the Angular docs about folder structure before proceeding with this post. The important point is that an Angular library is a project in a workspace. If you want to make a totally new library, you’ll need to make a new workspace and then create a project in the workspace. The Creating libraries doc guides you through that process.

However, the steps in that document assume:

  1. you have Angular installed globally (npm i -g @angular/cli)
  2. you do not have an initialized git repository

If those assumptions work for you, then you don’t need this post – the Angular docs will meet your needs. On the other hand, if you also find the two supposed downsides listed below to be real downsides, you may find the steps in this post to be useful.

Downside 1: unnecessary subdirectory

When you run the ng generate library triumphant-elephant command inside your git repository, it creates a directory and puts all the new stuff in it. If you do that from an existing git repository, you’ll end up with something like this:


my-git-repo/
my-git-repo/README.md
my-git-repo/package.json
my-git-repo/myOtherStuff.whatever
my-git-repo/triumphant-elephant/
my-git-repo/triumphant-elephant/package.json
my-git-repo/triumphant-elephant/README.md
my-git-repo/triumphant-elephant/everythingElseThatNgGenerateCreates.whatever

It’s like there is a whole repo under “triumphant-elephant”, even though our repository root is one level higher. There are two READMEs and package.jsons, and even if we delete one of them we would still have a superfluous subdirectory with everything hidden inside it. It would be nicer to have all our top level stuff in our repository root instead.

Downside 2: requires global Angular CLI install

This also relies on having the Angular CLI installed globally, which is inconvenient if you want to use different versions of the Angular CLI for different repositories, or if you want to include the Angular CLI in your package.json (to indicate to other developers what version of the CLI to use).

The following process expands on the one provided by Angular in the Creating libraries doc to use a locally installed Angular CLI and avoid the extra top-level directory.

Alternative: local Angular CLI

Prepare for using the Angular CLI

In your repo, create a package.json if you don’t have one already. The Angular doc has guidance on naming and other considerations for publishing your library.


npm init

Install the Angular CLI


npm i --save-dev @angular/cli

Running the locally installed Angular CLI

NPM packages may optionally include executables that are added to your path. Common examples are the TypeScript package which provides tsc for compiling, and testing packages like Jest which provide test running executables (e.g. jest for running the tests). Angular CLI uses this feature of NPM to provide the ng command. (You can see it defined in the Angular CLI package.json file in the bin section on GitHub.)

The Angular docs direct us to invoke ng new my-library --no-create-application, which leads to an error because the ng command is not found. Had we installed the Angular CLI globally, NPM would have added the Angular CLI executable ng to our path, and the command would be found. Instead, since we installed it in the node_modules of this repo through our package.json, the ng executable is in the node_modules/.bin folder.

There are two ways to invoke the local ng:

  1. Invoke ./node_modules/.bin/ng instead invoking ng
  2. Use npx (i.e. npx ng ...)
    • npx is a command provided by npm to run executables from the node_modules/.bin directory.

Create the workspace without the top level directory

Create the workspace as directed by the Angular docs, but with npx.


npx ng new triumphant-elephant --no-create-application

This creates a bunch of stuff in ./triumphant-elephant that we want to be in the current working directory instead. Let’s move the files up to the current directory (first removing the files we don’t want to copy). Before we do the copy, we make a git commit which will let us do a diff later to merge our existing package.json with the one generated by Angular.


git add -A
git commit -m "Create a new workspace with Angular CLI"
rm package.json # we want to use the Angular-generated package.json
rm package-lock.json
rm -rf node_modules # we'll reinstall after we move stuff
mv triumphant-elephant/* .
rmdir triumphant-elephant

This clobbered our existing package.json, but we don’t want it fully clobbered. Before doing a git commit, compare the new package.json with the old one can copy over anything you want to keep (like the package name, author name, license, etc.). Make sure you keep the dependency on @angular/cli.

Make sure that merge went well:


npm install
npx ng version

You should now have all the Angular generated stuff in the top level directory of your repo. You’ll also still have the Angular CLI installed as a dev dependency in your package.json. This is a good time to commit again to version control.

Create your new library

Now, we take the final step from the Angular docs: generate our library.


npx ng generate library tusk-widgets

Check that it worked

From your top level directory, execute npm test – the output should indicate that the auto-generated first test for your new library is being executed.