Reputation: 7692
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'
.
Upvotes: 6
Views: 11824
Reputation: 6029
Specifically regarding your concern with bundle size: I suspect Lodash is a major culprit there. Try using lodash-es
instead, and importing from only packages you need. E.g.
import cloneDeep from 'lodash-es/cloneDeep';
That should reduce the amount of lodash
in your bundle substantially, but it still won't be nearly as small as it could be for most use cases. I made a library specifically for this reason called micro-dash
. For example it includes cloneDeep
, which as the docs say adds 397 bytes
to your bundle (roughly - it depends on multiple factors), whereas the lodash version adds 12,289 bytes
.
Ultimately, though, to troubleshoot an oversized bundle you should see exactly how much each library is adding to it. That is the realm of source-map-explorer
. Absolutely run that on your final prod bundles, and address the worst offenders first!
Upvotes: 0
Reputation: 24134
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"
]
}
Upvotes: 13