I have several apps in my Angular monorepo project. Also there are about 5 libraries I've written to use across the apps.
What I want to know is how to better build/architect these libraries.
The ins are follows:
projects
folder)lodash
and RxJs
What I've done so far:
umdModuleIds
in each library's ng-package.json
.peerDependencies
on external libraries like lodash
and RxJs
prebuild
with about 5 commands ng build lib-name
combined via "&&"import { cloneDeep } from 'lodash'
Now I see that my main.js
chunk is much bigger than it was before extracting some services/components/functions into external libraries. Now main.js
's size on prod build is 2.1 Mb which in my opinion is too big.
Also, I'm not sure whether it's worth making 3 different builds of each library (UMD, FESM2015, FESM5).
I import libraries from dist folder as it recommended in docs following next form import { LibService } from 'lib'
.
Nrwl tools, developed by Angular core contributors, specializes in enterprise architectures, including mono repositories.
The Nrwl nx-examples is a great resource to get started.
I started by using nx
to build a new project. In the end, my project structure ended up as follows:
platform-directory/
|
---apps/
| |
| ---app1/
| |
| ---app2/
|
---library1/
| |
| ---src/
|
---library2/
| |
| ---src/
|
---angular.json
|
---package.json
|
---README.md
|
---tsconfig.json
The top level tsconfig.json
should contain the bulk of the global configuration for the apps and libraries as well as paths
shortcuts if desired.
Path shortcuts may be configured as follows:
{
"compileOnSave": false,
"compilerOptions": {
"outDir": "./dist/out-tsc",
"baseUrl": "./",
"declaration": false,
"downlevelIteration": true,
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"importHelpers": true,
"module": "esnext",
"moduleResolution": "node",
"sourceMap": true,
"target": "es6",
"lib": [
"es2018",
"dom"
],
"paths": {
"@app1*": [
"./apps/app1/src/app*"
],
"@lib1/package1": [
"./lib1/src/package1/public_api.ts"
],
"@lib1/package2": [
"./lib1/src/package2/public_api.ts"
],
...
}
In the applications, library code may be imported directly from the library sources, such as:
import { MyLibraryComponent } from '@lib1/package1'
Since you are not publishing the libraries, there is no need to build them. When you run the Angular compiler on your application code, the library code will be automatically included and optimized as needed.
IMPORTANT: Within each library, do not import files using the path shortcuts, since this causes hard-to-debug circular dependencies. For example, within lib2
it is okay to use:
import { MyLibraryComponent } from '@lib1/package1'
However, if this import were used within lib1
, it would create a circular dependency.
As a side note, each app will have a tsconfig.app.json
and tsconfig.spec.json
such as the following:
{
"extends": "../../tsconfig.json",
"compilerOptions": {
"outDir": "../../dist/out-tsc/apps/app1"
},
"include": [
"src/**/*.ts"
],
"exclude": [
"test.ts",
"**/*.spec.ts"
]
}