Sharing Code in Angular2 + Ionic2 Apps (Simply + without NPM)

A few weeks ago, I explored how you could share code between Angular2+ Ionic2 apps. Whilst the approach worked, dealing with that code day in, day out was actually pretty painful (multiple terminal windows, npm link playing up, …etc). I couldn’t help but think there had to be a simpler way…

…It turns out there was, and it involved sharing code via tsconig.json, rather than NPM. I’m not saying this approach is 100% better as there are pros and cons with both. What I am saying is, if it suits your requirements, it’s a lot easier to reason and work with. In terms of what I like about switching over to a tsconig.json :

  • We no longer need to npm link our dependencies
  • We no longer need to compile our dependencies
  • We no longer need multiple terminal windows (kind of :o))
  • We still have a ‘module like’ interface to our shared code

How To…

To explain this, I’m going to be referencing an example git repo. The project structure in that is something like:

example-app
|-- packages
|-- ionic-app-one
|-- ionic-app-two
|-- shared-components
|-- shared-ngrx

So, to share code here:

  • Keep your IDE happy, by adding a top level package.json to your repo. This package.json should contain all the dependencies that your shared code requires (as ‘dev’ dependencies) and needs an npm i when you initially grab the code.
  • To get paths and baseUrl in tsconfig.json to work, you need to install the awesome `awesome-typescript-loader` as a dev dependency in your ionic apps: npm i awesome-typescript-loader — save-dev
  • Plug-in the `awesome-typscript-loader`via a custom webpack.config.js. To do this, copy the existing webpack.conf.js file from ionic (node_modules/@ionic/app-scripts/config/webpack.config.js) to your app (eg. ionic-app-one/config/webpack.config.js), and add our loader:
// config/webpack.conf.js in our app(s)
...
var TsConfigPathsPlugin = require('awesome-typescript-loader').TsConfigPathsPlugin;
...
module.exports = {
...
    resolve: {
        ...
        plugins: [
            new TsConfigPathsPlugin(/* { tsconfig, compiler } */)
        ]
...
},
...
}
...
  • This custom webpack.conf.js can then be wired up in package.json:
// package.json in our ionic-app(s)
{
...
"config": {
        "ionic_webpack": "config/webpack.config.js"
    },
...
}
  • In your ionic apps, add references to your shared code in tsconig.json . This is the part that is essentially replacing npm, and we’ll access our shared code via the shared-components and shared-ngrx aliases. Notice that the paths, point to an index.ts file. In our example, this is just a barrel file, that acts as an interface to our shared code.
// tsconfig.json in our apps
...
"paths": {
    "shared-components": ["../shared-components/index"],
    "shared-ngrx": ["../shared-ngrx/index"]
}
...
  • You can now import shared code just as you did before (eg. import { dsds } from 'shared-components')
  • To help in development, we’re also going to update ionics watchers. To do this, copy the existing watch.conf.js file from ionic (node_modules/@ionic/app-scripts/config/watch.config.js) to your app (eg. ionic-app-one/config/watch.config.js), and add our shared code to the watchers:
// config/watch.conf.js
...
module.exports = {
    srcFiles: {
        paths: [
            ...
            '{{SRC}}/../../shared-components/**/*.(ts|html|s(c|a)ss)',
            '{{SRC}}/../../shared-ngrx/**/*.(ts|html|s(c|a)ss)'
            ...
        ],
...
},
...
};
  • Just as with our custom webpack.conf.js above, we’ll wire up this watcher config in package.json:
// package.json in our ionic-app(s)
{
...
    "config": {
        "ionic_watch": "config/watch.config.js",
        "ionic_webpack": "config/webpack.config.js"
    },
...
}

And that’s pretty much it. If the day comes where we need versioning, separate repos, etc… we’ll have to think again. But, until then this serves it’s purpose nicely.