Reputation: 1
UPDATES: Link to Repo
Read a lot of documentation and checking examples, but unfortunately I have the worse combination ever. Lazy loading, dynamic import, absolute path with variable :
I have Angular 15 app with 2 projects, library and application which should refer to library's components using absolute path (because I need library to be used same way from another Angular app). Library has standalone components - secondary entry points. One of the components is tricky. It is creating components in ViewContainerRef container from REST API response. I simplified it in repo, so it works with provided example data.
When I try a relative path it works well
const module = await import(`../../${item.path}/src/${item.path}.component`);
But I need an absolute path here to use from other projects.
I tried thousands ways to resolve it, edited tsconfig to include items, edited package to export items. Always have an errors. Most common is:
./projects/mycompany/sdk/dynamic-container/src/dynamic-container.component.ts:21:31-95 - Error: Module not found: Error: Can't resolve '@mycompany/sdk' in 'C:\Users\yekat\apps\new\our-library\projects\mycompany\sdk\dynamic-container\src'
Please help if you have any ideas how to resolve it. I spent days and nights and have no answer...
I cannot import all components without lazy loading because there could be a lot of them or a few and I don't need to load the whole library.
The following long message it what I started with. Now I have a repo and you can reproduce.
Thank you in advance!!!
OLD QUESTION I have 2 Angular 15 apps which I try to make work together. First one is the library with standalone components - secondary entry points. One of the components is tricky. It is creating components in ViewContainerRef container from API response.
component.module = await import(`../../../${itemPath}/src/${componentName}.component`);
...
this.componentRef = this.containerRef?.createComponent(component.module[component.moduleName]);
In this app I have a sandbox, its module importing my tricky dynamic component relatively.
import { DynamicContainerComponent } from '../../../mycompany/sdk/base-components/dynamic-container/src/dynamic-container.component';
Then it is displaying it in html. It works really good within Library app. Lazy loading works as expected, building process creating folder dist with
esm2020/...
fesm2015/...
fesm2020/...
....
Serving process looks good, shows the chunks been created:
Initial Chunk Files | Names | Raw Size
vendor.js
.....
| Initial Total | 2.69 MB
.....
Lazy Chunk Files | Names | Raw Size
....
projects_mycompany_sdk_base-components_drop-down-list_src_drop-down-list_component_ts.js | - | 867.52 kB |
....
projects_mycompany_sdk_base-components_plain-html_src_plain-html_component_ts.js | - | 2.26 kB |
It doesn't have my dynamic component because it's been imported by sandbox and included in Initial Chunk Files.
tsconfig.json
{
"compileOnSave": false,
"compilerOptions": {
"resolveJsonModule": true,
"baseUrl": "./",
"outDir": "./dist/out-tsc",
"allowSyntheticDefaultImports": true,
"forceConsistentCasingInFileNames": true,
"strict": true,
"strictPropertyInitialization": false,
"noImplicitOverride": true,
"noPropertyAccessFromIndexSignature": true,
"noImplicitReturns": true,
"noFallthroughCasesInSwitch": true,
"sourceMap": true,
"declaration": false,
"downlevelIteration": true,
"experimentalDecorators": true,
"moduleResolution": "node",
"importHelpers": true,
"typeRoots": [
"node_modules/@types"
],
"paths": {
"@mycompany/sdk/*": [
"projects/mycompany/sdk/*"
],
"@mycompany/sdk": [
"projects/mycompany/sdk"
]
},
"target": "ES2022",
"module": "ES2022",
"useDefineForClassFields": false,
"lib": [
"ES2022",
"dom"
]
},
"angularCompilerOptions": {
"enableI18nLegacyMessageIdFormat": false,
"strictInjectionParameters": true,
"strictInputAccessModifiers": true,
"strictTemplates": true
}
}
angular.json:
"projects": {
"@mycompany/sdk": {
"projectType": "library",
"root": "projects/mycompany/sdk",
"sourceRoot": "projects/mycompany/sdk",
"prefix": "lib",
"schematics": {
"@schematics/angular:component": {
"standalone": true,
"style": "scss"
},
"@schematics/angular:directive": {
"standalone": true
},
"@schematics/angular:pipe": {
"standalone": true
}
},
"architect": {
"build": {
"builder": "@angular-devkit/build-angular:ng-packagr",
"options": {
"project": "projects/mycompany/sdk/ng-package.json"
},
"configurations": {
"production": {
"tsConfig": "projects/mycompany/sdk/tsconfig.lib.prod.json"
},
"development": {
"tsConfig": "projects/mycompany/sdk/tsconfig.lib.json"
}
},
"defaultConfiguration": "production"
},
"test": {
"builder": "@angular-devkit/build-angular:karma",
"options": {
"tsConfig": "projects/mycompany/sdk/tsconfig.spec.json",
"polyfills": ["zone.js", "zone.js/testing"]
}
}
}
},
...
I use Verdaccio to publish this library and it works well. When I import simple components from this library into another app, they work well. But when it comes to my dynamic-container, I gen an error. But let me tell first how Application 2 works. app component is similar to what sandbox in App 1 has, but importing from package :
import { DynamicContainerComponent } from '@mycompany/sdk/base-components/dynamic-container';
(When I import other components, they work. But they don't have this lazy import from relative paths.) So DynamicContainerComponent takes a value which is Observable response from API call. DynamicContainerComponent itself decides what component it should load.
I tried to use different path in tsconfig:
"paths": {
"../../../base-components/*" : [
"node_modules/@mycompany/sdk/base-components/*"
],
"../../../base-components" : [
"node_modules/@mycompany/sdk/base-components"
],
"base-components": [
"node_modules/@mycompany/sdk/base-components"
],
"@mycompany/sdk/*": [
"node_modules/@mycompany/sdk/*"
],
"./base-components": [
"node_modules/@mycompany/sdk/base-components"
]
}
angular.json:
...
"projects": {
"test-lib": {
"projectType": "application",
"schematics": {},
"root": "",
"sourceRoot": "src",
"prefix": "app",
"architect": {
"build": {
"builder": "@angular-devkit/build-angular:browser",
"options": {
"outputPath": "dist/test-lib",
"index": "src/index.html",
"main": "src/main.ts",
"polyfills": [
"zone.js"
],
"tsConfig": "tsconfig.app.json",
"assets": [
"src/favicon.ico",
"src/assets"
],
"styles": [
"src/styles.css"
],
"scripts": []
},
"configurations": {
"production": {
"budgets": [
.......
],
"outputHashing": "all"
},
"development": {
"buildOptimizer": false,
"optimization": false,
"vendorChunk": true,
"extractLicenses": false,
"sourceMap": true,
"namedChunks": true
}
},
"defaultConfiguration": "production"
},
....
when building this app, dist folder gets lot of weirdly called files: dist
(lot of these files and they do contain minimized library components.) when serve i can see it is also creating chunks:
Initial Chunk Files | Names | Raw Size
vendor.js | vendor | 2.40 MB |
....
| Initial Total | 2.96 MB
Lazy Chunk Files | Names | Raw Size
...
node_modules_mycompany_sdk_esm2020_base-components_plain-html_src_plain-html_component_mjs.js | - | 2.83 kB |
...
When running in browser i see error: error
I assume I am missing something in App 2 configuration.
If you suggest to replace relative path
../../../${itemPath}/src/${componentName}.component
with @mycompany/sdk/${itemPath}/src/${componentName}.component
)
I tried, and in this case I gen an error on serving library
./projects/mycompany/sdk/base-components/dynamic-container/src/dynamic-container.component.ts:39:31-105 - Error: Module not found: Error: Can't resolve '@mycompany/sdk' in 'C:\Users\yekat\mw10-front-end-components\projects\mycompany\sdk\base-components\dynamic-container\src'
and in App2
./node_modules/@mycompany/sdk/fesm2020/mycompany-sdk-base-components-dynamic-container.mjs:38:31-105 - Error: Module not found: Error: Can't resolve '@mycompany/sdk' in 'C:\Users\yekat\apps\new\test-lib\node_modules\@mycompany\sdk\fesm2020'
Upvotes: 0
Views: 751
Reputation: 1
Solved it by specifying all imports in separate service. In this case webpack is happy and lazy loading still works. I wish I could use dynamic path and lazy loading together without specifying imports for all objects. But it seems to be impossible
Upvotes: 0