Share modules between apps - architecture


#1

Hi,

I’m pretty sure I have seen a similar topic in the past but I cannot find it using any search method, so I’ll ask it again:

Is there ANY advice how to share modules between apps? I have structured my apps in mainly generic modules which are meant to be reused in other apps. But I do not want to copy & paste any changes around for multiple apps. So how can I easily reuse such modules in multiple apps? Is there any advice/tutorial/documentation about this? I think this is a core issue for using ionic in companies, as they always will have modules generic enough to be reused to reduce costs.

If it helps: I’m using a private Git server, so if there is a way using this it would also be ok.

Greetings


Deal with shared files... make library or package?
#2

That’s a super interesting question, I would love to hear it solved too, that would help me too, thx for posting it :wink:

My guess, I would go for a component library build with the Angular CLI (see tutorial link here under). Then, if you could publish it to npm as open source project, publish it and check it out from there. If you could not publish it, you could just build your library locally and install it from there.

But like I said just a thought I planned to apply, but maybe it’s not the good way to go. If someone got a proper better idea, I would love to hear it that would help me too!

Create and build a library with the help of the Angular Cli: https://medium.com/@nikolasleblanc/building-an-angular-4-component-library-with-the-angular-cli-and-ng-packagr-53b2ade0701e

Build locally the lib and install it in your project:

  1. In the library

    cd /your-project-root-path/
    npm run packagr
    cd dist
    npm pack

  2. Then in your project

    npm install /your-project-root-path/dist/your-project-0.0.0.tgz


#3

Use symbolic links to one generic file?

Could work on unix…


#4

@reedrichards
Hm that looks like it will make it overly complicated… but maybe a clean solution if it works. did you try it out yet?

@Tommertom
Using windows, but also windows has symlinks… But not sure how the ionic build tools behave with symlinks?


#5

Proof of the pudding is in the eating!!


#6

That may be, but you can’t have any pudding if you don’t eat your meat. Soooo…


#7

I think it should be “You can’t have any desert if you don’t eat your vegetables” :slight_smile:


#8

We could start a separate topic for people to vote on that one, but I have a feeling it would be considered ‘irrelevant’ to Ionic.

We’ll have to agree to disagree!
Pink Floyd agrees with me though. I have proof


#9

@Rasioc see:

And:

And:


#10

@Rasioc yes and no :wink:

no I don’t use it yet to share components and providers across projects. Like I said, I would be super interesting to know a clean or proper solution and this would only be my spontaneous first thought

yes I do use this way to build and publish the open-source library ionic-swing (https://github.com/peterpeterparker/ionic-swing) and use it in my project (private repo)


#11

@robinyo
Thanks for the links, but unfortunately I think you miss the point here. I am not talking about sharing modules WITHIN an app. I am talking about sharing modules between multiple apps. None of these links cover this topic as far as I can see.

@reedrichards
Ok I will look into it, thanks!


#12

@Rasioc cool, looking forward to the results of your test, hope you gonna find the simpliest cleanest way to share these modules :slight_smile:


#13

@Rasioc I think you may be missing my point, that being it is easier to ‘share code between multiple Ionic Apps’ if each App adopts a standardised project structure (see this guide and this post).

You can ‘share code between multiple Ionic Apps’ by:

  • cutting and pasting (not recommended)
  • using a Cordova plugin
  • using a Node module (packaged using npm) as @reedrichards described (BTW, the npm registry also supports private packages)

You can use links (during development):

  • ln -s EXISTING_FILE_OR_DIRECTORY SYMLINK_NAME
  • cordova plugin add --link ../PLUGIN_NAME
  • npm link

See: Best way to share components etc. between multiple apps?

“Library support — Today the CLI can produce UMDs optimized for the browser, and CommonJS bundles optimized for the server. What if the CLI could help you produce a bundle that could be consumed by other Angular applications?”

See:

I found a few more topic-related posts:


#14

Hi @robinyo,
seems I misunderstood partly - sorry! I already have my apps structured in separate (kind of) standalone modules - which I want to share now by not using copy & paste.
I would prefer not to publish to npm (also not using private repos). But the last links you provided seem like what I was looking for.
Thanks for these hints and I will take a look which seems more suitable to my use case.


#15

@Rasioc I should have included some comments and not just the links, sorry :slight_smile:

If you are working as a part of a team then you can store your projects on your private Git server and reference them in your App’s package.json using URLs: https://docs.npmjs.com/files/package.json#git-urls-as-dependencies

JFrog also has an Npm Registry: https://www.jfrog.com/confluence/display/RTF/Npm+Registry


#16

Ok so let me summarize my first analysis (without trying out yet):

  1. NPM packages:
    Seems the cleanest solution so far and includes versioning, but also contains quite some effort. Using NPM Link sounds good for development, but not sure how to utilize this while I need to be able to checkout the repository of each app on a MAC build pc to build the apple app. I could install from GIT URls, which would help with the multi-platform issue, but I guess using npm LINK at the sime time will not work well?

  2. Symlinks:
    According to Best way to share components etc. between multiple apps? the build system doesn’t play too nice with symlinks. Also I would always need some setup script which adds the symlinks after checkout (e.g. for mac)

  3. Cordova Plugin
    Doesn’t seem too right for me for this

  4. The approach from @onderceylan in Best way to share components etc. between multiple apps? looks interesting but still too hacky and also setup for multiple apps at the sime time would be strange as far as I understand it.

  5. The approach from https://medium.com/@blewpri/sharing-code-in-angular2-ionic2-apps-simply-without-npm-5203048ec1e1 seems the most promising one when you do not need versioning for each component - at least from reading it. But when you look at the comments in the blog, there seem to be unresolved issues with production builds.

Sooo… At the moment I think it would be best to try the npm solution and figure out if I somehow can still use linking while also use github repos for installation on different platform. Would be nice if the CLI would provide an easy way for such requirement in future, but looks like right now there is no better way of doing it.


#17

A realllllllllly dirrrrrrtty way would be to setup a script that copies the files from a common lib to your project lib at specific moments…

like (pseudo)

xcopy /s /e /sharedlib/* /myproject/src/sharedlib

But then you are left with the detection of changes…


#18

Hmm ok I started by trying out this tutorial for npm packages which also covers linking: https://medium.com/@blewpri/sharing-logic-between-ionic2-apps-f06feaf51fad
But it doesn’t really work well yet:

As the linked module contains his own node_modules folder, I start seeing random errors about type mismatches. For example if I use some class of the shared code, which returns an observable. Then I try calling .pipe() on this observable and passing in first() method as argument:

Error:(152, 38) TS2345: Argument of type ‘UnaryFunction<Observable, Observable>’ is not assignable to parameter of type ‘UnaryFunction<Observable, Observable>’.
Types of parameters ‘source’ and ‘source’ are incompatible.
Type ‘Observable’ is not assignable to type ‘Observable’. Two different types with this name exist, but they are unrelated.
Property ‘source’ is protected but type ‘Observable’ is not a class derived from ‘Observable’.

I guess it’s because the shared code references its own node_modules folder for the Observable, while the app uses the other node_modules folder for the first() reference (import { first } from ‘rxjs/operators’;). Not sure how to solve this yet.

Edit:
Ok it seems I am running into this particular known angular/npm problem, which is (and will probably stay) unresolved: https://github.com/angular/angular-cli/issues/1514#issuecomment-240910842
Seems like linking via NPM is NOT a valid solution :frowning:

Edit2:
Still no solution. Only working solution is deleting node_modules and dist/node_modules in the library folder, but this requires another “npm i” whenever you want to rebuild the library, so this is also not a solution :frowning:

Edit3:
Ok seems like this will not be my way. I can’t sacrifize development experience that much, I need to develop the modules as part of the apps.
See also https://github.com/ionic-team/ionic-app-scripts/issues/635 for an existing github issue from ionic team regarding support of linked modules…


#19

As I am running out of time to solve this, I’m taking the shorter path now. I think I got it working with symlinks as follows:

  1. Moved out an exemplary shared module to some shared folder
  2. Created a symlink (windows, admin CMD required): cd …\src\modules && mklink /D shared …\ …\ …\ …\SharedModules\shared (hint: be aware that the forum modifies the target path somehow strangely)
  3. Add ./config/watch.config.js:
const watchConfig = require('@ionic/app-scripts/config/watch.config');

// add symlinked paths manually to enforce them being watched - even though they are in src/ folder they will otherwise be ignored
watchConfig.srcFiles.paths.push('{{SRC}}/modules/shared/**/*.(ts|html|s(c|a)ss)');

module.exports = watchConfig;
  1. Add ./config/webpack.config.js:
const webpackConfig = require('@ionic/app-scripts/config/webpack.config');
// When using symlinks for modules this must be set to FALSE, otherwise compile issues will be shown
// yes this sounds counter intuitive...
webpackConfig.dev.resolve.symlinks = false;
webpackConfig.prod.resolve.symlinks = false;

module.exports = webpackConfig;
  1. Add to package.json to use our new config files
  "config": {
    "ionic_watch": "config/watch.config.js",
    "ionic_webpack": "config/webpack.config.js"
  }

This seems to work, including ionic serve, live reload and production build.
If somebody else has some spare time and can go on with my results to investigate better options, I would be glad…
All I need now is some kind of setup script which initializes the symlinks after checkout on all platforms.

edit: does somebody know a cross-platform solution for adding symlinks, e.g. via npm “postinstall” script which does not require admin privileges on windows?


#20

@Rasioc

You should also try posting your questions on Ionic Worldwide: https://ionicworldwide.herokuapp.com/