Skip to content

Creating a Library #179

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
tsonevn opened this issue Jan 3, 2019 · 11 comments
Open

Creating a Library #179

tsonevn opened this issue Jan 3, 2019 · 11 comments

Comments

@tsonevn
Copy link

tsonevn commented Jan 3, 2019

@Lightk3ira commented on Wed Jan 02 2019

Hello I am writing an Angular + Nativescript code sharing project and have realized it would be beneficial to create a Library. I have tried using schematics but I am unable to create a proper library. Any component that get's created within the library only has angular files not typescript.

Steps To reproduce:

  1. Create a Workspace: ng new <project-name> --create-application false
  2. Create a Library: ng generate library library-name
  3. Create a module within the library: ng generate module navigation-module --project=Library
  4. Create a component within the library: ng generate component ran within the module directory
@Lightk3ira
Copy link

@tsonevn Hello Tsoneven, I was wondering why this issue was closed and if this has been implemented yet? A shared library is very important when working on multiple projects.

@NgxDev
Copy link

NgxDev commented Nov 12, 2019

Generating/migrating libraries is really required in the Angular world.
Large apps or monorepos make heavy usage of libraries.
Right now, it involves some manual work:

  1. Generate the library with @angular/schematics instead of @nativescript/schematics
  2. Manually create all the tns files (because migration doesn't work either, it seems that the nativescript schematics doesn't work with anything outside the app folder, no matter how I've tried to "trick" it to take the path to the library's src/lib folder, where the NgModule is)
  3. Edit the library's tslint.json to add "prefer-mapped-imports": false because the lib should use relative paths when importing from itself.
  4. Manually add to the "paths" object in tsconfig.tns.json

And Step 2 is to be repeated each time we add a module or a component to the existing library.

For example:

  1. ng generate @schematics/angular:library @my-namespace/my-lib
CREATE projects/my-namespace/my-lib/karma.conf.js (1038 bytes)
CREATE projects/my-namespace/my-lib/ng-package.json (174 bytes)
CREATE projects/my-namespace/my-lib/package.json (152 bytes)
CREATE projects/my-namespace/my-lib/README.md (987 bytes)
CREATE projects/my-namespace/my-lib/tsconfig.lib.json (555 bytes)
CREATE projects/my-namespace/my-lib/tsconfig.spec.json (252 bytes)
CREATE projects/my-namespace/my-lib/tslint.json (250 bytes)
CREATE projects/my-namespace/my-lib/src/test.ts (670 bytes)
CREATE projects/my-namespace/my-lib/src/public-api.ts (155 bytes)
CREATE projects/my-namespace/my-lib/src/lib/my-lib.module.ts (222 bytes)        
CREATE projects/my-namespace/my-lib/src/lib/my-lib.component.spec.ts (622 bytes)
CREATE projects/my-namespace/my-lib/src/lib/my-lib.component.ts (255 bytes)     
CREATE projects/my-namespace/my-lib/src/lib/my-lib.service.spec.ts (329 bytes)  
CREATE projects/my-namespace/my-lib/src/lib/my-lib.service.ts (134 bytes)       
UPDATE angular.json (7513 bytes)
UPDATE package.json (2747 bytes)
UPDATE tsconfig.json (1198 bytes)
  1. Manually add the following to tsconfig.tns.json paths:
"@my-namespace/my-lib": [
  "projects/my-namespace/my-lib/src/public-api"
],
"@my-namespace/my-lib/*": [
  "projects/my-namespace/my-lib/src/lib/*"
]

Normally, the Angular CLI only adds paths for the built version of the library in the root tsconfig.json, but we also add the above paths so we can work with the libraries without building them (also, really required while actually developing a lib):

"@my-namespace/my-lib": [
  "dist/my-namespace/my-lib", // << added by the CLI
  "projects/my-namespace/my-lib/src/public-api" // << manually added so we can work with the library without building it
],
"@my-namespace/my-lib/*": [
  "dist/my-namespace/my-lib/*", // << added by the CLI
  "projects/my-namespace/my-lib/src/lib/*" // << manually added so we can work with the library without building it
]
  1. Edit the library's tslint.json to add "prefer-mapped-imports": false because the lib must use relative paths when importing anything from itself.

  2. Manually create projects/my-namespace/my-lib/src/lib/my-lib.module.tns.ts

  3. Futher, for creation of additional modules and/or components in a library, we still can't use nativescript schematics. This would be the project's structure:

/projects
    /my-namespace
        /my-lib-1
        /my-lib-2
    /my-app

Couldn't trick @nativescript/schematics to do anything outside the my-app folder.
Running ng generate @nativescript/schematics:component my-component --project=@my-namespace/my-lib generates the following error: Failed to find generated component file /my-component.component.css. Please contact the @nativescript/schematics author.
This must be because nativescript schematics doesn't look at the projectType property in angular.json, so it doesn't know it's a "library" and for a library the files are in {newProjectRoot}/{project}/src/lib
So, we have to manually create the tns files each time we add a module/component to a lib. Imagine a library that hosts tenths of shared components, each component also having it's own module.

Yet, the biggest headache I've had was until I've realized that nativescript schematics also adds the paths property to tsconfig.app.json (without nativescript schematics, the paths are only in the root tsconfig.json and generating a library only updates the paths there). But the paths from the root tsconfig.json are overwritten by the paths in tsconfig.app.json. And the IDE wasn't signaling any error when lazy loading the module like loadChildren: () => import('@my-namespace/feature-auth/feature-auth.module').then(m => m.MyFeatureAuthModule), but ng serve/ng build was saying it can't find the module. And it was very confusing, because the IDE was fine with that import path.

Using:
@angular/cli - 8.3.18
@nativescript/schematics - 0.7.3

@juniorschen
Copy link

@MrCroft
Would you have a simple project to demonstrate how the library structure looks?

@Lightk3ira
Copy link

@MrCroft I appreciate you also looking into this. If that works that is great, however seems like a fairly manual process.

@NgxDev
Copy link

NgxDev commented Mar 12, 2020

@Lightk3ira sorry to answer so late, I was without hosting for over a month and switched to a temporary email address for a while, so I wasn't notified about the comment here.
Yes, it is a manual process. I was only describing what I had to do, until the schematics will support it.
Do you still want to see a sample project? (if so, I will do my best to create one this weekend)

@juniorschen
Copy link

@MrCroft
a sample project would help a lot

@juniorschen
Copy link

@MrCroft No sample yet?

@NgxDev
Copy link

NgxDev commented Jul 2, 2020

@juniorschen sorry for the delay, completely forgot about this
Made a sample repo this morning: https://github.com/MrCroft/nativescript-lib-demo (Angular v9, Angular CLI v9)

Made commits for each step of the process (create project, create app, create library, add Nativescript Schematics, the manual steps etc.)

In the auto-generated.component.tns.html I'm using a component from the library 👍

I had to go find this issue to be able to go around an error: #277 (comment)
but you should be fine, with the package-lock.json file I now have in the repository

P. S. Unfortunatelly, live reload doesn't work. So, if you change anything, you have to stop the running app and re-run npm run android/ios. But it's not related to our demo's purpose here. This is the error I'm getting when changing a file:

JS: HMR: The following modules were updated:
JS: HMR:          ↻ ./app/auto-generated/auto-generated.component.ts
JS: HMR:          ↻ ./app/app-routing.module.tns.ts
JS: HMR:          ↻ ./app/app.module.tns.ts
JS: HMR: Successfully applied update with hmr hash ea6f43b0a253cd6e716d. App is up to date.
Refreshing application on device ce031713e8f93c840c...
System.err: An uncaught Exception occurred on "main" thread.
System.err: Calling js method run failed
System.err: Error: View not added to this instance. View: ProxyViewContainer(8) CurrentParent: Page(4) ExpectedParent: AppHostView(1)

@juniorschen
Copy link

@MrCroft thank you so much for taking the time, I really appreciate it

@juniorschen
Copy link

@MrCroft
Do you know if there is a possibility to build the library to use in other apps?
For me the result with ng build library is always only .ts files and not .tns.ts

@NgxDev
Copy link

NgxDev commented Jul 2, 2020

@juniorschen hmm... My only reason was to be able to use libs "internally/locally", without publishing them (I guess I'd only build a lib if I wanted to publish it). I do share them across different apps too, of course, but in a monorepo, where all company apps and libs live under the same repository, under a strict naming convention and structure.
I'm really not sure how would "building/publishing to reuse" a code-sharing library would/should work. I think this raises more questions.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants