Integrate Angular 2 Google Maps into Ionic 2

UPDATE 11/12/2016: The following post is in reference to Ionic RC1. However, in RC2 they removed the rollup dependency and moved back to webpack - hence, a custom "config" section for rollup is no longer required.

Angular2 Google Maps (AGM) is a great component for integrating Google Maps into Angular 2 apps. There were several ways you could do this with Angular 1.x apps, but Angular2 Google Maps is the best way I've seen of doing with with Angular 2 apps. There is minimal code required and it is super easy to get started, in large part due to solid documentation on its Getting Started page.

I've previously incorporated this into regular Angular 2 web apps running in a browser, as well as Ionic 2 mobile apps. However, in the course of recording my latest Pluralsight course, Ionic 2 (which had been in the final beta) dropped the Ionic 2 Release Candidate. This was a significant release as Ionic 2 was updated to take a dependency on Angular 2 final. When this happened, not only did the previous implementation with AGM break, but even following the instructions on the AGM Getting Started page don't exactly work for an Ionic 2 app. This blog post will document how you can get up and running quickly with AGM in an Ionic 2 app.

First thing's first, let's generate our initial Ionic 2 app. If you haven't already, make sure the Ionic CLI is installed:

npm install -g ionic  

Make sure you're on version 2:

ionic -v  
2.1.0  

Let's create our Ionic 2 project in the usual way:

ionic start ionic2-google-maps-test blank --ts --v2  

Now let's follow the instructions on the AGM Getting Started page by installing AGM into our project:

npm install angular2-google-maps --save  

The Ionic 2 RC now uses the NgModule approach, which allows you to declare your dependencies up front.

Per the AGM guide, we import AgmCoreModule into app.module.ts and add it to our imports list shown on line numbers 6 and 15:

  
import { NgModule } from '@angular/core';  
import { IonicApp, IonicModule } from 'ionic-angular';  
import { MyApp } from './app.component';  
import { HomePage } from '../pages/pages';

import { AgmCoreModule } from 'angular2-google-maps/core';

@NgModule({
  declarations: [
    MyApp,
    HomePage
  ],
  imports: [
    IonicModule.forRoot(MyApp),
    AgmCoreModule.forRoot({ apiKey: '{your-api-key-here}'})
  ],
  bootstrap: [IonicApp],
  entryComponents: [
    MyApp,
    HomePage,
  ],
  providers: []
})
export class AppModule {}  

And of course we'll also put the appropriate mark-up on our desired page per the Getting Started instructions:

  
<sebm-google-map [latitude]="lat" [longitude]="lng">
  <sebm-google-map-marker [latitude]="lat" [longitude]="lng"></sebm-google-map-marker>
</sebm-google-map>

Let's run our Ionic app:

ionic serve  

However, when we do this, we get the following error:

[14:36:28]  bundle dev started ...
[14:36:34]  bundle dev failed:  Module c:\dev\ionic2-google-maps-test\node_modules\angular2-google-maps\core\index.js does not export AgmCoreModule (imported by c:\dev\ionic2-google-maps-test\.tmp\app\app.module.js)
[14:36:34]  bundle dev failed:  Module c:\dev\ionic2-google-maps-test\node_modules\angular2-google-maps\core\index.js does not export AgmCoreModule (imported by c:\dev\ionic2-google-maps-test\.tmp\app\app.module.js)
[14:36:34]  Error: Module c:\dev\ionic2-google-maps-test\node_modules\angular2-google-maps\core\index.js does not export AgmCoreModule (imported by c:\dev\ionic2-google-maps-test\.tmp\app\app.module.js)

"\angular2-google-maps\core\index.js does not export AgmCoreModule"? We followed the instructions perfectly so why is this happening? Our intellisense at design time seemed to have no problem with it - why is Ionic having a problem when it tries to actually run?

It turns out, the answer can be found in the Bundle section in the Ionic App Build Scripts documentation page. For the RC release, Ionic 2 moved from a gulp-based build process to one that uses rollup.js for bundling. Most of the time third-party libraries "just work", but in some cases, additional information needs to be provided to Rollup so that it knows what is being exported. This is the problem happening with AGM.

The get around this, we need to create our own rollup.config.js file in our project. The best way to do that is to find the existing rollup.config.js file in the node_modules/@ionic/app-scripts/config directory local to your project - copy that file - then create a directory called scripts right in the root of your project and paste that file there. In your file, find the plugins() section and add a namedExports property to commonjs() as shown here:

  
plugins: [  
    builtins(),
    commonjs({
      namedExports: {
        'node_modules/angular2-google-maps/core/index.js': ['AgmCoreModule']
      }
    }),
    nodeResolve({
      module: true,
      jsnext: true,
      main: true,
      browser: true,
      extensions: ['.js']
    }),
    globals(),
    json()
  ]

This tells Rollup that yes, angular2-google-maps does in fact export AgmCoreModule. We now need Ionic to know about our custom rollup.config.js file so let's open package.json in our project root. Add a config section that points to your custom file:

  
"config": {
    "ionic_rollup": "./scripts/rollup.config.js"
  },

Now when you run the ionic serve command, everything should work just fine!

Here is a Github repo with the complete working code. My (upcoming) Ionic 2 course on Pluralsight was created with the final beta so a different approach is shown in that video. But for Ionic 2 RC and beyond, this should enable everyone to easily integrate AGM with Ionic 2.