Sharing Code in Angular2 + Ionic2 Apps

NOTE: Whilst this approach works, the approach I've actually adpoted is way simpler. Details of this can be found here:

Building apps with ionic2, angular2, andngRx is just brilliant! Sure, the learning curve is steep, but if you keep at it, you‘ll be rewarded with the ability to write iOS, Andriod, and Windows mobile apps, all at once, and all with javascript (well typescript)!

Where I struggled initially was with code sharing between ionic2 apps. In javascript, creating and sharing modules is trivial with the help of npm. It seems, however, that the process is slightly more involved when using typescript. There are examples out there on how to do this. One by the ionic team (here), and the other by Benoit Hediard (here). Whilst useful, neither unfortunately allow you to npm link to your shared module(s)…which is a problem for your development workflow.

What follows is my attempt at cracking this particular nut via an example. The solution I propose is definitely (in my opinion) workable, but, is by no means a perfect…

A simple example (see code on Github)

We’re going to create two ionic2 apps, and one shared-code module that both apps will consume. To make it slightly more realistic, our shared-code module will contain some ngRx code and a test ‘shared’ component. This makes sense as separating this stuff into a a reusable module should come in pretty handy (for both current & future apps).

For simplicities sake, all our node modules will live in the same git repo. So, we want to end up with something like:

And, here are the steps we’ll take to get there:

  1. Create two ionic2 apps
  2. Create a shared-code module & add test ngRx code
  3. Install/Link the shared-code module to our Ionic2apps
  4. Consume code from the shared-code module in our apps
  5. Configure ionic to watch ‘shared-code’ for changes

Lets get started:

1. Create two ionic2 apps

In the terminal, create our ionic apps, and check that they run:

// Create a new directory for our example
// and move to it...
mkdir share-code-with-ionic-2 && cd share-code-with-ionic-2
// Create two 'blank' ionic2 apps...
ionic start ionic-app-one —-template blank --v2
ionic start ionic-app-two —-template blank --v2
// Check our apps work
cd ionic-app-one && ionic serve
// [Ctrl+C] once your done, then..
cd ../ionic-app-two && ionic serve
// ...

2. Create a shared-code module & add test ngRx code

Create and initialise our shared-code module (from the terminal) :

// from /share-code-with-ionic-2...
// ..create our shared code module
mkdir shared-code && cd shared-code && npm init && cd ..

Ad main, types, scripts anddependencies topackage.json:

"main": "./dist/index.js",
"types": "./dist/index.d.ts",
"scripts": {
"build": "ngc",
"watch": "rm -rf aot dist && npm run ngc"
"dependencies": {},
"devDependencies": {
"@angular/common": "2.4.5",
"@angular/compiler": "2.4.5",
"@angular/compiler-cli": "2.4.5",
"@angular/core": "2.4.5",
"@angular/http": "2.4.5",
"@angular/forms": "2.4.5",
"@angular/platform-browser": "2.4.5",
"@ionic/storage": "1.1.7",
"ionic-angular": "2.0.1",
"ionic-native": "2.4.1",
"ionicons": "3.0.0",
"@ngrx/core": "1.2.0",
"@ngrx/effects": "2.0.0",
"@ngrx/store": "2.2.1",
"@types/node": "6.0.58",
"babel-polyfill": "^6.23.0",
"rxjs": "5.0.3",
"tslint": "4.3.1",
"typescript": "2.0.10",
"zone.js": "0.7.4"

NOTE: If we really wanted to nail this module down, we could use peerDependencies . For simplicities sake, this example leaves it out.

Now we’ll add a simple ‘test’ ngrx action and reducer to shared-code (and expose them via theindex.ts barrel file). We’ll also add a simple ‘test’ component, that we’ll wrap up in an angular module (see github for details).

After that we need to configure typescript viatsconfig.json:

"compilerOptions": {
"module": "es2015",
"target": "es5",
"moduleResolution": "node",
"sourceMap": true,
"declaration": true,
"noImplicitAny": false,
"experimentalDecorators": true,
"lib": ["dom", "es2015"],
"outDir": "./dist",
"types": [
"exclude": [
"angularCompilerOptions": {
"genDir": "aot"

3. Install/Link the ‘shared-code’ to our ionic2 apps

To install our shared-code module, we’re going to add it as a file dependency in our ionic2 apps. In package.json, that should look something like this:

"dependencies": {
"shared-code": "file:../shared-code"

Once done, we need to re-run npm i. Now we’ve successfully installed our shared-code. We do want to do more however as developing with this setup would involve a lot of npm update's. To ease this pain, we’re going to use npm link to create a symbolic link between our modules. In the terminal, setting this up would look something like this:

shared-code > npm link
shared-code > tsc // compile the code
shared-code > cd ../ionic-app-one
ionic-app-one > npm i && npm link shared-code
ionic-app-one > cd ../ionic-app-two
ionic-app-two > npm i && npm link shared-code

For convenience, let’s also add the npm link to the ionic serve script:

// Snippet from 'ionic-app-one'..
"scripts": {
"ionic:serve": "npm link shared-code && ionic-app-scripts serve"

4. Consume our ‘shared’ code from our ionic apps

First, we’ll compose a new ngrx module from ‘shared-code’ in our ionic apps:

import { NgModule }      from '@angular/core';
import { StoreModule } from '@ngrx/store';
import { StoreDevtoolsModule } from '@ngrx/store-devtools';
import { TestActions, testReducer, TestEffects } from 'shared-code';
import { EffectsModule } from '@ngrx/effects';
exports: [],
imports: [,
test: testReducer
providers: [
export class AppStateModule { }
export interface IAppState {
test: any

Import this into the main app, along with our ‘shared’ components angular module:

import { NgModule, ErrorHandler } from '@angular/core';
import {
IonicErrorHandler } from 'ionic-angular';
import { MyApp } from './app.component';
import { HomePage } from '../pages/home/home';
import { AppStateModule } from './app.state.module';
import { SharedComponentsModule } from 'shared-code';
declarations: [
imports: [
bootstrap: [IonicApp],
entryComponents: [
providers: [{provide: ErrorHandler, useClass: IonicErrorHandler}]
export class AppModule {}

Then use this in our app:

import { Component } from '@angular/core';
import { Store } from '@ngrx/store';
import { NavController } from 'ionic-angular';
import { IAppState } from '../../app/app.state.module';
import { TestActions } from 'shared-code';
selector: 'page-home',
templateUrl: 'home.html'
export class HomePage {
    constructor(public navCtrl: NavController,
private store: Store<IAppState>,
private testActions: TestActions) {;

…and use the ‘shared’ component in the ‘home’ pages template:

Ionic App Two
<ion-content padding>
If you get lost, the <a href="">docs</a> will be your guide.

5. Configure the watchers in our Ionic2 apps to watch our ‘shared-code’

This is just a ‘cherry on top’ really. It’ll allow you to hook into livereload when you make changes to your shared-code module. To configure these watchers, we create a watch.config.js file in a config directory:

// the contents of 'watch.config.js'...
module.exports = {
srcFiles: {
paths: [
options: {
ignored: [
callback: watch.buildUpdate
copyConfig: copy.copyConfigToWatchConfig()

For this config to work, we need to wire this up in our ionic apps package.json :

"config": {
"ionic_watch": "config/watch.config.js"

We’re Done!

So, when developing for ionic-app-one (for example), we need to open two terminal windows and kick of ionic serve in our app, and npm run watch in our shared-code module. It should look something like this:

As I mentioned earlier, this by no means a perfect solution. It is a start however, and achieve’s what I wanted to do. Please check out the code on github and let me know what you think in the comments.