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:
- you have Angular installed globally (
npm i -g @angular/cli
) - 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.json
s,
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
:
- Invoke
./node_modules/.bin/ng
instead invokingng
- Use
npx
(i.e.npx ng ...
)-
npx
is a command provided bynpm
to run executables from thenode_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.