How to write a reusable private library for Angular 2+ - node.js

I have created a generic framework for creating dashboards which consists of multiple modules using Angular-CLI.
Some modules are completely independent. Developers who are using this library can add the modules on their project on demand. I had a previous version of this framework created in Angular Js 1.0, in this I have delivered as javascript min files.
What are the things I have to take care to create this Library as private not for public or is there any way to package my modules as separate and deliver without NPM?

This question boils down to two independent tasks: Creating the library package and publishing it internally.
Create the library package
In order to create a library with AOT support, you need to compile it using ngc -p src/tsconfig-aot.json.
tsconfig-aot.json is a copy of tsconfig.json with an additional section:
"files": [
"./app/index.ts"
],
"angularCompilerOptions": {
"annotateForClosureCompiler": true,
"genDir": "../dist/out-lib-tsc",
"skipMetadataEmit" : false,
"skipTemplateCodegen": true,
"strictMetadataEmit": true,
"flatModuleOutFile": "libname.js",
"flatModuleId": "libname"
}
I need to fix the directory structure by moving the files from src/app to the root of the output directory. Then you copy src/app and src/asserts to the output directory.
There are several detailed guides out there. For example Distributing an Angular Library - The Brief Guide
Publish the library package
There are several options to publish private libraries:
reference a branch in a git repository Note: It is probably a good idea to use different repositories for developing (without compiler output) and publishing
npm offers private repositories for a fee
you can setup a local registry (for example Artifactory or Sinopia)

Related

How to: git repository with default NPM modules and its configs

I would like to have repository with default NPM modules and its configs for all future NPM projects.
For now the configs consists of tsconfig.json, tslint.json, .prettierrc.
The goal is to have a simple way for creating new project with custom defaults and also have possibility of changing configs for all of these projects from one place.
I tried to create my own NPM module with package.json containing dependencies I want to have in all my new projects and its configs in root. The problem is obvious - if I install this package into new project, modules (and configs) are scoped to my custom module and not to my newly created project.
Does anyone has any idea how to deal with this?
You are basically making a boilerplate. Do develop it, I see two possible approcches:
Publish the boilerplate as NPM module.
Build and publish the boilerplate on your repository provider (Github, Bitbucket etc) and use it as starting project to be forked for every new project you build.
I will suggest you to follow the second approach, that's easier to achieve.
You are instead tryng to follow the first approch that's more tricky. To generate a starting project you should build a CLI (Command line interface). So you will build an NPM module that should be globally installed and that you will use with a set of commands like:
myawesomecli generate my-new-starting-project
And the myawesomecli module will generate a my-new-starting-project folder containing your boilerplate. You could optionally ask to the user for settings to be selected in an interactive session. That's what famous framework like React, Vue.js, Angular etc. are doing.
You can follow this tutorial to build a CLI that generates boilerplates. Keep in mind that the inquier module is the key module for such scopes.

is it possible to share same node modules between multiple projects?

As of now I am installing node modules every time for the new angular project. Is it possible to use one projects node modules to other project by configuring any file(like changing the path in any file so it can use that modules)?
From Angular 6, you can generate multiple application in a single Angular project.
https://angular.io/cli/generate#application-command
applications generated by Angular cli command stay in same workspace and share node_modules.
For example, if you want to generate app my-project:
ng generate application my-project
If its dependencies are not different from previous one, you can use --skipInstall=true option with ng generate command.
And ng serve it with --project option:
ng serve --project=my-project
First off I was shocked to see that this is actually a thing that some people are doing - see: https://github.com/nodejs/help/issues/681
However I would advise against it.
The idea behind each project having its own node_modules folder (and package.json) is that each of your projects should specify its own dependencies (including specific versions) which is a good thing for stability, predictability, reproducibility, etc. of your various projects. Here's a pretty good write-up on the node dependency model: https://lexi-lambda.github.io/blog/2016/08/24/understanding-the-npm-dependency-model/
Now if you're talking about a local module (that you created yourself), you can have a look at https://docs.npmjs.com/cli/link.html

Vue - Better to publish .vue file or a compiled component?

When writing custom components is it better to publish the .vue file directly or to publish a compiled version using webpack/other-bundling-tool ?
Bonus: Is there an official document regarding conventions to follow when publishing custom components?
EDIT: What are the pros and cons of either method?
I've published a few open source projects and from experience I can say that it's better to publish your code - or rather, set the main entry point - as a compiled distributable for a few reasons:
Firstly, by outputting a UMD module you are creating a distributable that works across all environments (webpack, browserify, CDN, AMD) and it's as simple as adding the following to your webpack config:
output: {
...
library: 'MyPackageName',
libraryTarget: 'umd',
umdNamedDefine: true
},
Secondly, most developers using webpack will exclude babel-loader from compiling scripts in their node_modules folder by doing something like:
{
test: /\.js$/,
loader: 'babel-loader',
exclude: /node_modules/
}
So, if developers need to compile your code themselves and you have anything in your project that is not a .vue file that uses ES2015 (e.g. a mixin) then you would need to tell developers to apply babel-loader to your project folder in their webpack config.
As for browserifydevelopers having to compile your project, you would need to add vueify and babelify as transforms to package.json (they actually can't set this up themselves) and tell those developers that those are dependencies and get them to set up an appropriate .babelrc file.
All that setup can be a nightmare for devs, many will have little knowledge about their build process, so won't know about excludes, they won't know about transforms, they will just get a bunch of errors and either remove your package or create issues on your repo.
And that's just for the two most common build processes, you will still probably want a CDN and you will still want to allow those using AMD modules to use your package, so a UMD module is the way to go.
That said, you should still distribute the .vue files themselves, which will also allow devs to compile your project if they have advanced configuration requirements.

Dockering a nodejs application with external dependencies

We are building Node.js microservices. For some reusable components we have created a utils folder. This folder is outside the actual microservices package. When we run the microservices, we can refer to that code using require(../../utils/logger) and it works like a charm.
However when trying to create the docker image for my microservices
project the container gives me an error saying:
Error: Cannot find module '../../Utils/logger
which makes a lot of sense as we are building the docker image inside the microservice project.
There are few architectural decisions which needs to be taken here:
We move the utils code into each microservice as required.
Pro: Microservice remains self sustained completely and no code level dependency on any other package.
Cons: Maintenance of cross cutting concerns and the changes would be cumbersome.
2.Create a private npm module and inject dependency into the microservice package.json file. Not sure if that would work.
Any suggestions on this are highly appreciated.
Best,
- Vaibhav
Don't use require(../../utils/logger), use npm packages
You should avoid using same files for microservice with symlink or requiring from one folder, because it destroys Loose coupling.
Loose coupling is a design goal that seeks to reduce the
inter-dependencies between components of a system with the goal of
reducing the risk that changes in one component will require changes
in any other component. Loose coupling is a much more generic concept
intended to increase the flexibility of a system, make it more
maintainable, and makes the entire framework more "stable".
Simply put, you can't have different version of your logger file, but you can have different version of your logger npm package.
Implementation details for using npm modules as reusable components for Node.js microservices:
Chose naming convention for packages. My advice is scoped packages. Example: #vaibhav/logger
Chose npm registry. There are such options:
2.1. npmjs.com and public packages. It's free, but your packages should have only universal code without any business-valuable details.
2.2 npmjs.com with private packages. It's fast, but not free.
2.3 verdaccio your own npm registry server. It's free simple Node.js solution, which should be install as server in your infrastructure.
2.4 nexus. Universal private registry with npm and docker support.
If you use 2.3 or 2.4 solution, then you need to choose ip or link for your server. My advice is use link. Example https://your-registry.com
If you use 2.3 or 2.4 solution, the you need to chose install approach in your .npmrc file inside your microservice. There are two options:
install all required packages from your registry. The .npmrc file will looks like registry=https://your-registry.com. Your registry should be able to cache public packages.
install only your package from your registry, install other packages from public registry. The .npmrc file will looks like #vaibhav:registry=https://mycustomregistry.example.org
Define processes for package development, publishing and updating the package version in microservice package-lock.json file. In our projects we define processes in this way:
We use GitHub flow for package development. There are only master branch for publishing and feature branches for development. Master branch can be updated only with pull requests from developers or commits from CI server.
We use Jenkins as continues integration server for autoupdating version and publish after merging pull request. Jenkins runs npm version command for update version, then publishes new commit to master branch and then publishes to npm registry. Jenkins checks some our rules and use npm version with patch or minor param. Updating major version is breaking change, which we do manualy.
We don't have 100% automated process for updating the package version in microservices. We automate only opening pull requests with new package version in package-lock.json file. Developers should check build status and press merge button manually.
Its not part of your question to elaborate how to deal with shared libraries in Microservice-Ecosystems and what to avoid there, but if you like, you should read this up to get you at least a list for pros and cons of "sharing".
Beside that, you can create a library container which only offers this library to be mounted.
version: "2"
services:
shared:
image: me/mysharelib
m1:
volume_from:
- shared:ro
m2:
volume_from:
- shared:ro
while your mysharedlib image looks more or less like this
FROM busybox
COPY bin/busyscript.sh /usr/local/bin/busyscript
WORKDIR /your/lib/folder
VOLUME /your/lib/folder
CMD ["busyscript"]
and your busyscript is just a dummy like this
#!/bin/sh
#set -x
pid=0
# SIGTERM-handler
term_handler() {
if [ $pid -ne 0 ]; then
kill -SIGTERM "$pid"
wait "$pid"
fi
exit 143; # 128 + 15 -- SIGTERM
}
# setup handlers
# on callback, kill the last background process, which is `tail -f /dev/null` and execute the specified handler
trap 'kill ${!}; term_handler' SIGTERM
echo "Started DW php code"
# wait forever
while true
do
tail -f /dev/null & wait ${!}
done
As you see, m1/m2 ... m10 mount the library which and it is truly shared across all microservices.
Alternatives:
You can for sure use an private NPM packages or simply package the shared lib into the microservice m1..m10 during image build time.
What describe above especially suits you well when you want to replace the shared library in the stack with very little overhead and want to ensure the library is in-sync for all container instancs

file organization in node.js project

When creating a node.js project (express based if it matters),
what is the recommended way to store the different files building up the project?
More specifically, dependent external models (being declared as dependencies in package.json) are downloaded to ./node_modules, so where should I place my "locally" created modules ?
Thanks
See nodejs-express-mongoose-demo. It has the perfect file structure.
the standard is to use a local lib directory.
see the node.js libraries on git, there are a million examples.
Cradle Git
Node2XML Git
Express Source on Git

Resources