-
Notifications
You must be signed in to change notification settings - Fork 52
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
[Question] How to use it for shared code #275
Comments
@csimpi Hi, When coming from @nativescript/schematics (or nativescript-schematics) there's a few important things to understand on the surface: In @nativescript/schematics (or nativescript-schematics) you might have something like this:
With Nx+xplat it would look like this:
The above uses a unique option
This allows any app in the Nx workspace to simply consume that component however it needs. For example, given you have 1 web app and 1 nativescript app in your workspace (created using
Each of those apps can import the component from the specific location cleanly: For apps/web-myapp, it could import that component like this:
For apps/nativescript-myapp, it could import that component like this:
Same component name, no custom file extensions, natural folder organization for code, clarity in what you are dealing with (what platform is this thing?) leading to no custom file extension loaders, no overhead in maintenance and natural webpack handling. There's more I can share later but that's one of biggest things to understand to start with. |
When using the
That would auto annotate the app's routing and auto configure a route by that name The key thing about the above
This creates:
Giving you the ability to immediately start working with your new cross platform feature.
This is a great question and easily the most often confused notion of xplat. Since xplat is about sharing code in general and Nx is all about sharing code, the notion of "SharedModule" loses it's meaning in the scope of shared code alone like "libs" since everything in libs is "shared", whether it's called SharedModule or not. So xplat makes a distinction here by naming those "shared SharedModule's" UIModule because in reality that is what they are. UIModule is a sharable module housing ui counterparts that can be imported/exported from any other modules that need to consume those ui pieces (components, directives or pipes). Each app has it's own "SharedModule" which auto imports the corresponding platform UIModule by default allowing you to just use the generators to begin rapidly building out code while the generators auto annotate the UIModule for you and thus since each app already imports UIModule from the respective correct platform shared code (xplat/web or xplat/nativescript) you can just start using that stuff - with the confidence that there will be no platform bleed or interference because they are neatly isolated and organized already. The default behavior of the component, directive, pipe generators is to target the
That I highly recommend using Nx Console with VS Code as it provides a visual interaction tool to all the options the schematics provide (even outside of xplat) so it's insanely helpful in understanding generators, their options, and given it executes in Hope that helps clarify a few things. |
The other thing worth mentioning is core vs. features. This concept goes back to a widely talked about topic with regards to Angular specifically - CoreModule vs. SharedModule. A well known and fascinating topic with Angular in general and you can find even more references to this concept. With xplat, the understanding of core vs. feature runs strong as it uses each for the same reasons discussed widely in those references. CoreModule is imported once into a module stack of an app and used for singleton services and used most often for runtime configuration of various services. xplat specifically uses them to that advantage to configure services for the various platform runtimes, you can see that at play in xplat/web/core -> CoreModule and xplat/nativescript/core -> CoreModule respectively. They both configure shared code for the bottom lowest layer of the architecture xplat/core which is a central location of widely used services across the whole spectrum of cross platform work you may build in a Nx + xplat workspace. This allows developers to use 1 service api with confidence that each platform CoreModule configures that service appropriately for the target runtime in which the app is running, be it web, ios or android. Everything that's not core is generally a feature and typically organized as such since features are the often optional lazy loaded (or not) portions of code that certainly play a role in any app deployed from the workspace but may not be central to the core operation of any given app. For example, an http interceptor that controls all aspects of every app's interaction with your organizations backend api's would be considered core to all apps within the workspace whereas a |
@NathanWalker Thank you for the answers, it's clearer now, and I see what is the approach. What I'd still need to know how to organize features to directories. I understand you recommend using I'd propose something here: Similarly to the I've tested this and since Angular can handle
UPDATE - WorkaroundI didn't test it through but I think adding the below lines to
Result:
|
@csimpi that makes sense yeah - if you want to post a PR of the branch mention there I could run some tests here and we could try to get out in a patch update. I just need to check it against a few flows. |
@NathanWalker Thank you, PR sent. |
This is a great question with great answers! I was just wondering the same thing. I am just getting into Xplat, seems you have really been thinking when you did the design, great job! You should post these examples on your web @NathanWalker, including the use case with the directories. Thanks for this! |
Thanks @s0l4r - lemme know if you've encountered any other questions past couple days. There's been a lot of evolution with Nx since xplat started and they have a @nrwl/devkit now which is super nice and we're in process of adhering to the new devkit sometime in 2022 which will help streamline more. We're also planning to swap some under hood processes to use other established packages (like @nxtend for ionic handling). |
@NathanWalker Is there any advice on how to use Nativescript platform specific files (aka. .android.ts and .ios.ts)? the build fails with current default configurations: |
Hi NS team, I'm also currently doing my best to finally migrate all my big codebase to brand new nx workspace... To be honest, it's a bit hard ... I don't know where to define yet all my old NS6 big shared core modules and split into features, core etc... Previously with shared code project on NS6... I used to create helpers files with and without the tns.ts suffix in a very top shared modules.... so it was easy to share an helper for web and another for mobile and inject the proper runtime one into another class constructor etc... But now I'm a bit stucked with them. I'm searching how I can achieve the same kind of injection behavior but within Nx Workspace between a xplat/web/core/src/lib/helpers/... and xplat/nativescript/core/src/lib/helpers/... I should find a solution to be able to inject the correct helper into code that is upper than the ns/helpers and web/helpers for instance from features or even xplat/core. I hope there is an easier solution than create all helperBase abstract classes and uses some kind of InjectionToken stuffs... If you have advices to handle the helpers files ... ; ) Thanks in advance. |
Hi @lostation could you provide an example of one of your helpers? Seeing how you had them setup may help me provide better guidance. Each platform has a CoreModule which configures services per platform which is where you can provide platform specific behavior. An example of that is provided in the xplat/web/core and xplat/nativescript/core whereby window and language are configured. |
Hi Nathan, Thanks for your fast answer. I appreciate it. So for instance with one of my helper so called app.service.ts with a single method called getElementById for the sake of simplicity. As you know previously with NS6:I was using a shared core module that holds an helper's folder where we could find files like app.service.tns.ts and app.service.ts and a lot of others...Then in any component constructor, injecting AppService or other, was easy and the right one was selected during compile time. Thanks to suffix .tns for that. I had to only be sure both files contain the same function signatures with the right specific implementation. Now with NS8 + xPlat architecture:From xplat/nativescript/core/src/lib/helpers/app.service.ts
From xplat/web/core/src/lib/helpers/app.service.ts
Then I have a file used in a shared way, either used by nativescript and web helpers: visual-element.ts
Where should I put this visual-element.ts file to be shared between folders xplat/nativescript and xplat/web to avoid to duplicate it ? How import the right helper implementation ? From xplat/features or xplat/core ? Those places are indeed the shared places between xplat/nativescript and xplat/web...but then again how to import AppService from visual-element.ts as it is only defined, a step lower, from within xplat/nativescript/helpers/xxx and web/helpers/xxx specific folders ? I have a lot a shared files like that between mobile app and web where I used to import my helpers and NS was gently using the correct one. Thanks for your time. |
Is the NativeScriptConfig and shared attribute is still functioning with NS8 ? And can be use to retrieve the auto .tns.ts suffix discrimination ? between app.service.tns.ts and app.service.ts event from an xplat architecture... ? Then if so, I could maybe (re)merge all my helpers from within a single xplat/core/helpers folder and if the "Shared" is still functioning NS will do the rest, like NS6 ? |
Very nice thanks, this is what I would do: Create the broad workspace service helper you will use everywhere
Make sure that's exported from the
Now just provide each platform's CoreModuleNativeScript
Web
Now enjoy using AppService everywhere
It's the same thing you had but with bit better separation of concerns not prone to evolutionary changes to static analysis with Angular's compiler or webpack hoopla. Note: this makes use of Angular 14's new/fantastic inline |
Ok thanks ! I was also thinking to go into the XplatWindow direction. Then perfect, I'll go to this injection token best practices. Indeed add tokens + factories to each modules to use specific file is great solution. The drawback is maybe that we lost types, for that I will add some interfaces to implement in the services from the core modules. I have 2 more questions...if you ok.
Thanks again. |
Great questions sure thing.
You can add modules to either - which one you add to is dependent upon that ^^ most often (follows the same coremodule vs sharedmodule discussion noted above). Furthermore that is the base level guidance with the architecture - you are free to generate additional Nx libraries in/around xplat architecture as you see fit. We do this in practice, we build our foundation within bounds of xplat architecture which helps delineate the cross platform concerns without worries and then have other nx libraries in/around it for different purposes from project to project as it scales.
That shows several things:
Invoked like this:
That would debug iOS using the UAT configuration which would have the following set (all from project.json):
Same configs can be built for release mode as follows:
|
As far as
With Nx, each app can consume/use everything from libs so each app just becomes a shell/deploy target to give it unique id/resources for what you're wanting. |
Lastly keep in mind with latest you can also use this strategy which is also another approach that works well within Nx for various environment level handling: |
There's so many options here I keep recalling more 😁 You can also have multiple
|
Hi Nathan, Ok ;) thanks a lot for all your advices! I'm not building yet the apps ui part or env stuffs because I'm still dispatching specific and shared stuffs into xplat architecture... I'm starting to well know this new way of handling files...and start to appreciate it finally! I'll let you know any further things if any, thanks a lot anyway for all your appreciated help. |
Re Nathan, mmm sorry to bother you again... I've got weird errors from Webpack :( So now everything should be setup and ready to go for the mobile part ... I've added a npm script to run from global package.json -> "android:br:dev": "npx nx run nativescript-app:android:br-dev" From nativescript-app/project.json
From nativescript-app/ns-br.config.ts
So, it starts my "webpack-custom.config.js" then it means that correct NativeScriptConfig from "flags": "--config=..." is selected and running. That already great! From "webpack-custom.config.js", I'm just doing some files copy, selected brand resources into the App_Resources and also some version build number update.
So my current errors are:
But I have a src folder into nativescript-app/... from --env.verbose printed infos, I can see that mode is declared in Webpack
If I remove the attribute webpackConfigPath from NativeScriptConfig... The warning and error disappear... ??? Can we still use custom webpackConfigPath within Webpack and NS8 ? Or maybe I missed something...probably. Thanks for your precious help. |
No in fact even without webpackConfigPath from NativeScriptConfig... The warning and error are still there... Module not found: Error: Can't resolve './src' in '/Volumes/Data/project/apps/nativescript-app' I don't really know why ./src is not resolvable.... And even WTH is that Field 'browser' doesn't contain a valid alias configuration Please help, if you have any hint... |
Waw... It took me days to find out what happened... !!! async keyword is breaking all webpack build process and it probably takes then the by default webpack config ... as the async is not yet resolved. In that webpack.config.js, previously with NS6 and the custom config path (now from NativeScriptConfig), that was working and I was able to make some files maintenance, set versions, clean and copy stuffs...before the real webpack was called. So from nativescript-app/webpack.config.js:
I have also changed a bit the chainWebpack based from the webpack docs
Hope this help someone else... |
About local plugins to handlefrog nx and app... I wonder what is the best practices with local npm custom nativescript plugins. Should I put that plugin folder inside the nativescript app level or workspace level ? I've tried to link all the plugins index.d.ts from the workspace references.d.ts...but that doesn't seem to work. I've also seen that there is "@brfrontend/xplat-scss": "file:libs/xplat/scss/src" from workspace package.json dependencies... Maybe should I do the same for the local plugins located at ns app level ? What is the best way to handle that from nx point of view @NathanWalker ? Thanks |
Ah and I tried with that plugins folder from the workspace root...but then some defined java flies are not compiled correctly and I've got some static error with interface declared inside the java class package name... But not from the ns app level, that seem to compile java to byte code as it was before....So seems better to put that custom things inside ns app level...It has the benefit to not pollute the root folder. |
@lostation when possible might drop in Discord: |
Hi,
our app is an {N} Angular / Web + Android hybrid app and has been upgraded to NativeScript 8. It stopped working. On Discord I've got the info the schematics are not supported anymore and I have to use xplat if I want to maintain the shared code.
I've created a new workspace added xplat and now I'm stuck because:
nx g lib --parentModule=xy
doesn't work, and when I add a library with--routing
and--lazy
the routes don't appear in the parent project--project=main-ui
), I'm getting error reports about I have to use platform prefix which I don't understandCan I get some support here? I just need an example where I can see how the code sharing works between nativescript and web (angular) project.
Another questions:
ng g component
andng g feature
?nx g feature
doesn't have--directory
parameter? I would like to organize my features, for example, pages would go into thepages
folder.shared.module
for? Why UI module has been wrapped into shared.module? Why not importing UI module itself directly?The text was updated successfully, but these errors were encountered: