⬆️ ⬇️

We are testing the creation of a component library for Angular with the help of a new command for Angular / Cli - library



When projects become a little more than one, there is a need to somehow reuse not only individual modules with code, but also the UI components themselves. There are many options for solving the problem - from the traditional copy-paste, to setting up a separate project with tests, documentation, and even blackjack.



The problem is that the second option requires considerable effort to prepare and each such project is unique - with its own tools in which each new developer needs to be dealt with anew. At the end of July, the Angular team offered its own, integrated solution to this problem by adding a new library creation command to angular / cli.



Let's see what came of it.



For the tests, the freshest of the stable versions of angular / cli is taken - 6.1.5 (09/04/2018)



Perfect world



In a perfect world, everything should be comfortable. So, for the library component, I would highlight three important points.





So let's start from the start



In order to create our own library, we need to take two steps - to create a new project and add a library to it. First, create a new project:



npx @angular/cli@latest new mylibapp 


npx

I use npx to not install cli globally and avoid npm run constructs. If you have npm version 5.2 or newer, try it. Read more here.



After executing the command, we will see a standard (for 6 angular, which differs from the 5th version) project in which two sub-projects will be created - the main mylibapp and mylibapp-e2e. The angular project itself is now described in angular.json.





Libraries, as we see, not yet.



And here he is the first nuance. Our name is already taken up with the main project, and it’s no longer possible to name the library. Therefore, if you want to call the library my-super-library, you first need to create a project that should be called something different. For example, my-super-library-project. And only then, create a library with the desired name.



Now we will create the third sub-project and generate the library.



 cd mylibapp npx ng generate library mylib --prefix mlb 


It is not necessary to specify the prefix, but it is very desirable not to intersect with other libraries.





As you can see, now our third library has been added to the third sub-project. It has its own separate package.json, tsconfig and karma.conf.js, which allows you to customize it without fear of offending other projects. By the way, if you wish, we can add another library and it will also be a separate subproject. But that is why the library could not be identified as a completely separate project (as for example in .Net) I do not know. And if e2e project is not difficult to remove with your hands, then the main project is no longer. As a result, an extra code appears in the repository, which is not very good.



Now let's see what tools we get right away. This is a bunch of tslint + codelyzer, karma + jasmine and protractor for e2e. Those. a standard set of angular project, nothing specific for the library was given to us. This is a little strange, since some tool for viewing components and rendering them to the documentation (for example, a storybook ) is just a must have. But okay, we will assume that here we just left room for maneuver.



Let's run the tests and the linter to make sure everything works.



 npm test mylib npx ng lint mylib 


Everything went smoothly for me, but Chrome was used for testing, which is also strange. I have nothing against him, but on the build servers it will not be 90%. Why not use the same Puppeteer - is not clear.



Let's sum up:



pros





Minuses





So far, nothing critical, we continue to dig further.



Development



We already have some components out of the box, let's look at them. Since we have no special tools, we will use the main project (here it turns out why we need it). To do this, we need to bring down the library, import the library module and launch the main project.



some code
 npx ng build mylib 


 import { MylibModule } from "mylib"; ... @NgModule({ declarations: [ AppComponent, ], imports: [ BrowserModule, MylibModule ], providers: [], bootstrap: [AppComponent] }) 


 npm start 


After everything is executed, we will see our component from the library. But again there is a nuance - the watch mode for the library has not yet been done, do you need to run the library build on your own each time? Watch will appear only in angular / cli 6.2+. And not out of the box, for this you have to add a new flag in tsconfig.json



tsconfig.json



 "angularCompilerOptions": { "enableResourceInlining": true, } 


And then run the build with the watch flag:



 ng build mylib --watch 


If, for some reason, you use cli under 6.2, you have to build it yourself, which, frankly, is bad.



Now let's add a new component. To do this, run the standard command generate component. Due to the fact that the library is not our main project, we have to use the project flag, which is also a bit annoying (but if the library were an independent decision ...).



 npx ng generate component some-nice-image --project mylib 


Now, under mylib / src, we will create the assets folder, add a picture and rebuild the library again to see the result. And here we are waiting for another surprise - no pictures. It turns out that the resources used in the library do not fall into the build automatically, they need to be copied independently (or like this ). And it seems to be not scary, but still somehow not right.



On the other hand, tree-shaking should work out of the box. Let's create another component in the library but do not use it in the main project. We collect the main project in the production mode



 npx build --prod 


And we see that the size of the bundle has not changed. Tree-Shaking with libraries really works!



Now it would be nice to try to put some kind of dependency. Since each project has its own package.json, we need to first go to the library folder and run the npm install command



 npm i -D @drag13/when-do npm i @drag13/round-to 


I deliberately put them in different ways to check how the packer would deal with it later. Everything is put without problems. We try to collect and get a warning



Distributing npm packages with 'dependencies' is not recommended. Please consider adding drag13 / round-to to 'peerDependencies'or remove it from' dependencies

Distribution of npm packages with dependencies is not desirable. Please consider adding drag13 / round-to dependency to peerDependencies or removing it from dependencies altogether.



and, then, and the error:



Dependency drag13 / round-to must be explicitly whitelisted

Drag13 / round-to dependency must be explicitly added to the white list



This is already interesting, by design, the library does not want to have direct dependencies. We try to move our dependency to the peerDependencies section and get together again - voila, everything works. But this means the order of installing third-party libraries is now different. First, we set the dependency on the main module, then, with pens, add to the peerDependencies section of the library.



The rest works the same as in the usual Angular project.



Briefly summarize:



Pros:





Minuses:





And finally, proceed to the publication



Publication



Here everything is right well. For publication, angular / cli uses the already well-proven ng-packgr, which independently compiles our code into a suitable for publishing npm package leaving the package.json file setting (and this is not small), minification, packaging in different formats (for example, in UMD) .



To publish your package (or see what's inside) you need to execute three commands.



 npx ng build --prod cd dist/mylib npm publish 


If you don't want to publish, replace the publish command with pack.



As a result, I got the following:





First, let's take a look at package.json, which does not look like the original package.json of our library.





As you can see, packagr did not delete our devDependencies, although some do. In addition, the number of formats that are described in package.json is theoretically good (even if I don’t know half of them).



Inside the package contains a minified and non-minified bundle in UMD format, and a few more bundles of the internal angular format (fesm5, fesm2015). But, most importantly, now this will not hurt the head of the developers that is just great.



Let's go to the conclusions



Pros:





Total



The solution was interesting, but raw. Starting and publishing is very convenient, but there are still questions to develop. It is particularly disturbing that now the library is not an independent project by design, but rather an addition to the main project with the possibility of publication.



On the other hand, a large piece of work has been done, the functionality is constantly evolving, and I am sure that over time we will get a great tool for development.



')

Source: https://habr.com/ru/post/422051/



All Articles