nativescript-angular
nativescript-angular copied to clipboard
The Component 'xxx' is declared by more than one NgModule - code sharing errors
Describe the bug I'm working with code sharing project (angular version) and have erros like:
ERROR in src/app/start/error404/error404.component.ts:11:14 - error NG6007: The Component 'Error404Component' is declared by more than one NgModule.
11 export class Error404Component implements OnInit {
~~~~~~~~~~~~~~~~~
src/app/start/start.module.tns.ts:28:34
28 declarations: [LoginComponent, Error404Component, HomeComponent],
~~~~~~~~~~~~~~~~~
'Error404Component' is listed in the declarations of the NgModule 'StartModule'.
src/app/start/start.module.ts:28:34
28 declarations: [LoginComponent, Error404Component, HomeComponent],
~~~~~~~~~~~~~~~~~
'Error404Component' is listed in the declarations of the NgModule 'StartModule'.
src/app/start/home/home.component.tns.ts:8:14 - error NG6007: The Component 'HomeComponent' is declared by more than one NgModule.
8 export class HomeComponent {
~~~~~~~~~~~~~
src/app/start/start.module.tns.ts:28:53
28 declarations: [LoginComponent, Error404Component, HomeComponent],
~~~~~~~~~~~~~
'HomeComponent' is listed in the declarations of the NgModule 'StartModule'.
src/app/start/start.module.ts:28:53
28 declarations: [LoginComponent, Error404Component, HomeComponent],
~~~~~~~~~~~~~
'HomeComponent' is listed in the declarations of the NgModule 'StartModule'.
src/app/start/login/login.component.ts:19:14 - error NG6007: The Component 'LoginComponent' is declared by more than one NgModule.
19 export class LoginComponent implements OnInit, OnDestroy {
~~~~~~~~~~~~~~
src/app/start/start.module.tns.ts:28:18
28 declarations: [LoginComponent, Error404Component, HomeComponent],
~~~~~~~~~~~~~~
'LoginComponent' is listed in the declarations of the NgModule 'StartModule'.
src/app/start/start.module.ts:28:18
28 declarations: [LoginComponent, Error404Component, HomeComponent],
~~~~~~~~~~~~~~
'LoginComponent' is listed in the declarations of the NgModule 'StartModule'.
The errors apper:
- when I use relative import paths and app is starting.
- when I use aliases (@src/app...) and save some changes in component.ts file (not when app is starting).
StartModule- ts
import { NgModule, NO_ERRORS_SCHEMA } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { SharedModule } from '../shared/shared.module';
import { Error404Component } from './error404/error404.component';
import { LoginComponent } from './login/login.component';
const routes: Routes = [
{
path: '',
pathMatch: 'full',
redirectTo: 'login',
},
{
path: 'login',
component: LoginComponent,
},
];
@NgModule({
declarations: [LoginComponent, Error404Component],
imports: [SharedModule, RouterModule.forChild(routes)],
schemas: [NO_ERRORS_SCHEMA],
})
export class StartModule {}
StartModule - tns.ts
import { NgModule, NO_ERRORS_SCHEMA } from '@angular/core';
import { Routes } from '@angular/router';
import { NativeScriptRouterModule } from '@nativescript/angular';
import { CommonPipesModule } from '../shared/pipes/common/common-pipes.module';
import { SharedModule } from '../shared/shared.module';
import { Error404Component } from './error404/error404.component';
import { HomeComponent } from './home/home.component.tns';
import { LoginComponent } from './login/login.component';
const routes: Routes = [
{
path: '',
pathMatch: 'full',
redirectTo: 'home',
},
{
path: 'home',
component: HomeComponent,
},
{
path: 'login',
component: LoginComponent,
},
];
@NgModule({
declarations: [LoginComponent, Error404Component, HomeComponent],
imports: [SharedModule, NativeScriptRouterModule.forChild(routes), CommonPipesModule],
schemas: [NO_ERRORS_SCHEMA],
})
export class StartModule {}
Any ideas? I'm trying to fix it since 2 days :/
Additional context ---tsconfig.json
{
"compileOnSave": false,
"compilerOptions": {
"outDir": "./dist/out-tsc",
"module": "ESNext",
"target": "es2015",
"moduleResolution": "node",
"sourceMap": true,
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"noEmitOnError": true,
"skipLibCheck": true,
"lib": [
"es2017",
"dom",
"es6"
],
"baseUrl": ".",
"paths": {
"@src/*": [
"src/*.android.ts",
"src/*.ios.ts",
"src/*.tns.ts",
"src/*.web.ts",
"src/*.ts"
],
}
}
}
--- tsconfig.tns.json
{
"extends": "./tsconfig.json",
"compilerOptions": {
"module": "ESNext",
"moduleResolution": "node",
"experimentalDecorators": true,
"skipLibCheck": true,
"baseUrl": ".",
"paths": {
"@src/*": [
"src/*.tns.ts",
"src/*.ts"
]
}
},
"files": [
"src/main.tns.ts"
]
}
--- package.json
"dependencies": {
"@angular/animations": "~10.2.2",
"@angular/cdk": "^10.2.7",
"@angular/common": "~10.2.2",
"@angular/compiler": "~10.2.2",
"@angular/core": "~10.2.2",
"@angular/fire": "^6.0.4",
"@angular/forms": "~10.2.2",
"@angular/material": "^10.2.7",
"@angular/platform-browser": "~10.2.2",
"@angular/platform-browser-dynamic": "~10.2.2",
"@angular/router": "~10.2.2",
"@nativescript/angular": "~10.1.7",
"@nativescript/core": "~7.0.13",
"@nativescript/firebase": "^11.1.2",
"@nativescript/theme": "~3.0.0",
"@ngx-translate/core": "^13.0.0",
"@ngx-translate/http-loader": "^6.0.0",
"core-js": "^3.6.5",
"firebase": "^8.0.0",
"nativescript-gif": "^5.0.0",
"nativescript-sound": "^1.0.4",
"nativescript-texttospeech": "^3.0.1",
"nativescript-toasty": "^2.0.1",
"nativescript-toasty-ns-7": "^14.0.0",
"nativescript-ui-chart": "^8.0.2",
"nativescript-ui-listview": "^9.0.4",
"nativescript-ui-sidedrawer": "9.0.3",
"ngx-custom-validators": "^10.0.0",
"npm-check-updates": "^9.2.4",
"reflect-metadata": "~0.1.13",
"rxjs": "~6.6.3",
"tslib": "2.0.3",
"zone.js": "~0.11.3"
},
"devDependencies": {
"@angular-devkit/build-angular": "~0.1002.0",
"@angular/cli": "~10.2.0",
"@angular/compiler-cli": "~10.2.2",
"@nativescript/android": "7.0.1",
"@nativescript/schematics": "^10.1.0",
"@nativescript/tslint-rules": "~0.0.5",
"@nativescript/webpack": "~3.0.8",
"@types/jasmine": "~3.6.1",
"@types/jasminewd2": "~2.0.8",
"@types/node": "^14.14.6",
"@types/stripe-v3": "^3.1.21",
"codelyzer": "^6.0.1",
"jasmine-core": "~3.6.0",
"jasmine-spec-reporter": "~6.0.0",
"karma": "~5.2.3",
"karma-chrome-launcher": "~3.1.0",
"karma-coverage-istanbul-reporter": "~3.0.3",
"karma-jasmine": "~4.0.1",
"karma-jasmine-html-reporter": "^1.5.4",
"node-sass": "^4.14.1",
"protractor": "~7.0.0",
"ts-node": "~9.0.0",
"tslint": "~6.1.3",
"typescript": "~4.0.5"
}
any update?
@Arystosedes you should use a SharedModule to declare components only ones: solution from here
you should use a SharedModule to declare components only ones
He is actually just declaring it in one module. This is a code sharing project and we use some-file.tns.ts and some-file.ts for the different platforms. Only one of these gets compiled.
Anyone have any temporary fixes like telling the linter to ignore this issue until it gets fixed?? This is a super annoying bug that affects the latest and most up-to-date projects.
Ok so I think I found a fix, but I'm not sure if it's a good long term solution.
In tsconfig.tns.json, in the paths object, remove "src/*.tns.ts" from the array.
I think you only need this if you are importing ".tns" files directly. (usually you won't have the ".tns" in your import statement)
I'm getting error-free builds.
@kennethkeim I am having this issue on a fairly clean scaffold of a nativescript app, I tried your workaround without any luck. Did you ever find anything else?
ERROR in projects/kiosk/src/app/app.component.ts:8:14 - error NG6007: The Component 'AppComponent' is declared by more than one NgModule.
8 export class AppComponent {
~~~~~~~~~~~~
projects/kiosk/src/app/app.module.tns.ts:14:5
14 AppComponent,
~~~~~~~~~~~~
'AppComponent' is listed in the declarations of the NgModule 'AppModule'.
projects/kiosk/src/app/app.module.ts:11:5
11 AppComponent,
~~~~~~~~~~~~
'AppComponent' is listed in the declarations of the NgModule 'AppModule'.
ERROR in projects/kiosk/src/app/home/home.component.ts:8:14 - error NG6007: The Component 'HomeComponent' is declared by more than one NgModule.
8 export class HomeComponent implements OnInit {
~~~~~~~~~~~~~
projects/kiosk/src/app/app.module.tns.ts:15:5
15 HomeComponent,
~~~~~~~~~~~~~
'HomeComponent' is listed in the declarations of the NgModule 'AppModule'.
projects/kiosk/src/app/app.module.ts:12:5
12 HomeComponent,
~~~~~~~~~~~~~
'HomeComponent' is listed in the declarations of the NgModule 'AppModule'.
I think the brutal and clean way of solving this -> is to not use anymore a file with a ".tns.ts" suffix.
You should declare 2 differents src/folders into your projects. One for the web...and another only for mobile. Then in tsconfig.json you exclude the folder for mobile..and tsconfig.tns.json you exclude the folder for web... And refactor all the tns.ts files into regular .ts files.
The usage of a fully shared angular project as NS6 used is definitively broken and over... Already discussed a lot with the core team and they affirmatively don't want to fix that kind of sharing issue. I'm also super disappointed about all of this...but there's no legacy compatible solution.
There was also the webpack build time solution to replace files by another...but I still didn't find any time to work on that.
Good luck.
That's good to know. I will pull those out. I don't mind having two projects one for mobile another for web with some shared libraries. I really am new to this and am using this as my guide https://v7.docs.nativescript.org/angular/code-sharing/migrating-a-web-project
Hey everyone!
I think it's time to clear some things up. Although I can't speak for the NS team about the future, I can shed some light on code sharing.
From my perspective, code sharing with schematics and .tns.* was a mistake from the get-go. While we, as developers, want the minimal amount of duplicated code possible, code sharing introduces so many layers of limitations on a project it's often the wrong solution, and often you just realize it when it's too late.
For example:
- All your modules need to have a NativeScript counterpart due to imports
- So does routing
- many components also need different code because they may change native views
- due to component reuse with page-router-outlet, angular lifecycle hooks will be called in a different way on web and mobile
- most of the time, web view hierarchy will be inefficient in a native environment (https://blog.nativescript.org/nativescript-angular-performance-tips-tricks/)
- if your project isn't perfectly configured, you'll start seeing errors like you're experiencing now. Also tools like VSCode won't allow you to specify a custom tsconfig.json to get rid of these errors.
- you back yourself into a corner by making both your web and native dependencies deeply linked
- many others I probably missed
When I first started with NS code sharing wasn't an option, and when it was all it took was trying to migrate 1 project to it to see it then wasn't an option for me.
So what's the solution then? Well, the solution that has always been there: nx.
A lot of NativeScript core (and community) projects are now using nx:
https://github.com/nativescript/nativescript https://github.com/NativeScript/plugins
Even plugins are coming with it pre-configured:
https://github.com/NativeScript/plugin-seed
Unfortunately, it's hard to say code-sharing without saying monorepo. It allows for creation of many apps with varying degrees of dependency between them. Everything that can be shared can be put into their own libraries that can get bundled with each application in the end. It's how big projects with multiple apps (native and mobile) are structured across most communities and companies.
I personally don't see the nativescript schematics as a bad thing for generating components and modules from the command line, but everything code-sharing related in it just adds confusion and complexity to projects.
Code sharing with .tns.ts was a very ambitious ideia for "automagically" build native and web projects. My kudos to who took their time to develop it and make sure it worked as well as it did, which in itself is a huge achievement. But we all know that behind all "magic" in tech there's a lot of development work on building and maintaining it. When the magic involves constantly fighting against linters, the angular compiler, best practices, and others, it just becomes unsustainable and frustrating for both the teams maintaining and using it.
In sum: migrate to nx, it's probably the best tool for the job at the moment. I've written a small script that should help with splitting your projects into 2 different projects (it copies files to 2 different directories and removes the .tns extension from the native directory)
https://github.com/edusperoni/ns-codesharing-migration/tree/master
Lots of good information there, Thanks.
I have spent the afternoon playing with nx, with limited success.
Can I have an nx workspace with an angular web app and a nativescript app? I fully agree with the idea that I need to write two clients for two different paradigms, but would like to be able to share some pure ts code.
Can I achieve that with NX, and any recommended guides. I have tried, but can't get it to let me create a workspace with both angular and nativescript together.
I have an existing angular code base, no nativescript code yet, so the migration provided by edusperoni won't be useful, I think.
Thanks
@kennethkeim I am having this issue on a fairly clean scaffold of a nativescript app, I tried your workaround without any luck. Did you ever find anything else?
@marbletravis No I didn't do any more work on this issue.
@marbletravis You most likely are running into some of the pain with the Angular 12 updates of recent which latest Nx 12.3 give you out of the box. We have a lot coming for Angular 12 and detailing some additional test cases before we release the final (which @nativescript/nx and xplat updates will follow shortly after).
In the meantime though we would recommend using this to generate your Nx workspace with the proper versions to lead you to success:
npx [email protected]
Recommended to choose empty at the prompt after naming your workspace.
That will create a Nx workspace which is bound against Angular ~11.2.0 when generating apps which would work with latest versions of @nativescript/nx and xplat (whichever you decide).
We anticipate our Angular 12 support being released next week and will make an announcement and post with the details on NativeScript Twitter so can be on lookout there to hear the latest.
You can then generate web apps, NativeScript apps and anything you want.
Thanks!. I ended up getting this working (I waited till 12 was released).
For others, I ended up creating an angular workspace, with my web portion and a shared lib
nx generate @nrwl/angular:app myapp
https://nx.dev/latest/angular/cli/generate
then I added a nativescript project
npm install --save-dev @nativescript/nx
npx nx g @nativescript/nx:app <app-name> [...options]
https://github.com/NativeScript/nx
And it seems to work. I do have some head scratchers about the nested package.json in the nativescript app... but it works so for now just gonna run with it.