19

I want to write my own library and reuse it in other projects, so I created a new app and generated a library there:

ng new lib-collection
cd lib-collection
ng g library first-lib --prefix va

How to add Angular Material to my library? I wanted to use something like this:

ng add @angular/material --project=first-lib

But I got an error: Could not find the project main file inside of the workspace config (projects/first-lib/src). What's wrong?

vorant94
  • 423
  • 1
  • 5
  • 16

2 Answers2

38

You don't need to add it there.

You need to add it to your primary application:

ng add @angular/material

Then add "@angular/material" to the peerDependencies of the projects/first-lib/src/package.json (just copy a line with @angular/material from your primary package.json).

What you just did:

  1. You installed the library to the primary package.json and can now run your code locally, because locally angular cli would use the primary package.json and node_modules
  2. You set it as a library's dependency and after you publish it and install at another place it will ask you to also install the peerDependencies there (as npm warning)

You can, of course, also add it to dependencies instead of peerDependencies and get it automatically installed with your library, but this is not a good way of managing frontend dependencies (but could be still good for pure node.js packages)

smnbbrv
  • 23,502
  • 9
  • 78
  • 109
  • 1
    do I need also add `@angular/cdk` and `hammerjs` to `peerDependencies`? – vorant94 Nov 18 '18 at 12:16
  • Only if your library depends on them – smnbbrv Nov 18 '18 at 23:29
  • 5
    This doesn't work for me. I still mat-checkbox' is not a known element when I add a checkbox to the form. Do I need to add a reference somewhere else? – Sun Oct 02 '19 at 15:15
  • @Sun you probably did not include MatCheckboxModule into your component's module? – smnbbrv Jun 08 '20 at 09:35
  • 1
    @smnbbrv I did add it, and still the same error. What should I do? – Awais Ashraf Sep 15 '20 at 04:03
  • @smnbbrv Thanks It worked for me, but I don't understand why it didn't worked for me by directly adding material dependencies in primary "package.json" and updating "node_modules" using "npm i". – Bhupendra Kumar Nov 12 '21 at 13:57
  • Seems that it may not work with lazy loaded modules. You can get an injector error if a provider is not found. I had to add the module the library needed directly to the AppModule – squirtgun May 11 '22 at 06:05
  • None of these are working for me. I am using Angular 13. So confusing. – asiby Jul 07 '22 at 14:37
25

Since Angular 7...

Since ng7 and ng CLI 7, we can follow the preferred method of Angular Library development is as follows.

  1. Create a workspace and leverage the --create-application flag set to false.
  2. Create your library within your workspace.
  3. Create a test/sandbox project within your workspace to test your library as you develop it.
  4. Use a git subtree to push your /dist/ folder of your library build out to a seperate repo that you can use as a source for distributing your new Library (either internally or publicly through npm, etc.)

This does a few things. 1. Keeps your library and sandbox project independent and also generates an end to end (e2e) testing project within your workspace. 2. Keeps all of your projects together, but independent.

So what does this change exactly? This is 'mostly' how we've been doing things.

Keep in mind, you will need to add the external schematic/library to your sandbox project, not to your workspace. In ng6, I believe this wasn't the case, as with ng6, you created a workspace and project at the same time and then you had to do some renaming magic. With ng7, you use the --create-application flag set to false and then create your sandbox/dev project. That said, when you use ng add for the purpose of adding an external library/schematic to your sandbox project (like angular material), you will use the --project= flag with the ng add command. Let's run through the steps, now that we've [over]-explained everything.

NOTE: I always create my repo at my origin (gitlab/github/bitbucket/etc) and then clone it to my local before doing anything, I will assume you do the same.

For demo purposes, we will call this library 'Demo Library' and my repo will be named 'demo-workspace'

  1. Run git clone $ssh_url_for_repo_here
  2. CD into your newly cloned workspace repo cd demo-workspace
  3. Use ng new to create your workspace WITHOUT a project and in the same directory ng new demo-workspace --directory=./ --create-application=false
    • This will create an angular workspace. It will look similar to a project, but it won't do anything but fail if you type ng serve
  4. In the same folder (the ROOT of your workspace repo) generate your library, including a desired prefix) with ng generate demo-library or ng g demo-library --prefix=demo.
    • This will create a 'projects' folder inside of your workspace folder. It will place your new library inside your 'projects' folder.
  5. Then you'll run ng build demo-library to run your initial build of your new library, which will create a dist folder in the root of your workspace.
  6. Next you will create your sandbox project that you will use while developing and testing your angular library with the ng generate command and your desired flags, something like this ng g application demo-sandbox --style=scss --routing=false
    • This will generate a normal angular project, following your flag instructions and place the newly generated project in your workspace's projects folder demo-workspace/projects/demo-sandbox
  7. After your project has been generated, you can serve it up with the standard ng serve and it'll appear on port 4200, no need to include the --project= flag for this, it will assume it correctly.
  8. Now you will finally add Angular Material schematic to your sandbox project with ng add command and using the --project= flag to identify which project Angular Material should run in (again, all of this is in your parent workspace directory) ng add @angular/material --project=demo-sandbox
    • You'll notice that your 'demo-sandbox' doesn't actually have a package.json, that's because it leverages the package.json from the workspace. Everything is separated, but not really lol.
  9. Finally add Angular Material as a peer dependency just as @smnbbrv suggested their answer...

Then add "@angular/material" to the peerDependencies of the `projects/demo-library/src/package.json (just copy a line with @angular/material from your primary package.json).

I add the @angular/cdk, @angular/animations and hammerjs dependencies along with the @angular/material personally. I'm big on explicitness, plus you'll notice that in "peerDependencies" it explicitly has both @angular/common and @angular/core, rather than just one and assuming the other.

  1. Once you're done with that, you can then run the ng build command to rebuild your demo-library project, thus creating a new 'dist/' folder in your workspace project, which also triggers your currently served 'demo-sandbox' project to rebuild itself.
anothercoder
  • 563
  • 5
  • 10
  • 12
    fwiw, my co-worker said this is way too much for a stack overflow answer and that I should've created an article and posted it somewhere. IMO, nobody will find my article, but they will find this SO question, so while it's long-winded, at least it's the answer you need. Happy coding! – anothercoder Jun 03 '19 at 20:26
  • I'd agree with your co-worker. SO answers are ideally concise, dealing with the exact problem asked, which here is why is he getting that particular error. Your answer is a whole tutorial on start to finish on cloning a GIT repo, generating an angular project (nicely explaining every step), and adding material. So while it is helpful, it means the question asker needs to figure out which bit is relevant to their issue and discard the rest, or else they need to scrap their project (which in this case is new anyway, but for others it may not be) and start over using your guide. – James Sep 27 '19 at 15:11
  • @anothercoder thank you very much for this guide. One question: How do you install and use the 'demo-library' in the 'demo-sandbox'? Is it correct to just install it with `npm i @namespace/package-name --save` – Alessandro Santamaria Nov 18 '19 at 11:00
  • 1
    @AlessandroSantamaria no need for NPM with workspace strategy. Just do the following... 1. run a build of your lib so it appears in your `/dist` folder - your app will pull from here during `ng serve` and it will import from here during `ng build`. 2. Import your library's module into the app module you want to use it in, and then just import the component in the lib you want to use, just as you normally would. I didn't notice the notification, so I'm sorry if this answer is too late to be helpful for you, my apologies. – anothercoder Jan 08 '20 at 07:31
  • 1
    This is not working in Angular 13. – asiby Jul 07 '22 at 14:39