Update #6 April 13, 2017: I have updated this post as well as the sample code repo to use Angular 4.0.2.
Update #5 November 23, 2016: I have updated this post as well as the sample code repo to use Angular 2.2.1.
Update #4 September 23, 2016: I have updated this post as well as the sample code repo to use Angular 2.0.0.
Update #3 September 4, 2016: I have updated this post as well as the sample code repo to use Angular 2 RC6.
Update #2 August 6, 2016: I have also set up the sails sample projects here in this repo
Update #1 August 6, 2016: This post has been updated for Angular 2 RC4.
Recently I had a project requirement where I had to work with Sails.js, a full-blown nodejs framework based on Express.js. The client wanted to integrate Angular js as front-end to it.
So, to cut it short, I started researching about some sample Angular and Sails integrations and I found plenty of them. But the thing is, all of those tutorials are for Angular 1.x. And it makes sense because as of writing this post, Angular 2 is still in beta. And I was easily able to get around working with Angular 1 and Sails but I had a hard time integrating Angular 2 within a Sails app.
As you might already know that Angular 2 is based on TypeScript which is a superset of javascript. It makes use of the latest ES6 js engine and is also backward compatible with ES5 and classic javascript constructs.
So, enough of the intro, let’s get down to the real stuff. I will start and go ahead assuming that you have already setup a sails application. If you find yourself lacking there, go ahead and follow the steps over here to set yourself up.
The first order of business would be installing TypeScript as a global node module. Do that like so:
1 | npm install -g typescript |
Now, you will need to add following dependencies to your package.json file.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 | "dependencies": { "@angular/common": "4.0.2", "@angular/compiler": "4.0.2", "@angular/core": "4.0.2", "@angular/forms": "4.0.2", "@angular/http": "4.0.2", "@angular/platform-browser": "4.0.2", "@angular/platform-browser-dynamic": "4.0.2", "@angular/router": "4.0.2", "@angular/upgrade": "4.0.2", "angular-in-memory-web-api": "~0.3.0", "core-js": "^2.4.1", "ejs": "2.3.4", "es6-promise": "^3.0.2", "es6-shim": "^0.33.3", "express": "^4.14.0", "grunt": "1.0.1", "grunt-contrib-clean": "1.0.0", "grunt-contrib-coffee": "1.0.0", "grunt-contrib-concat": "1.0.1", "grunt-contrib-copy": "1.0.0", "grunt-contrib-cssmin": "1.0.1", "grunt-contrib-jst": "1.0.0", "grunt-contrib-less": "1.3.0", "grunt-contrib-uglify": "1.0.1", "grunt-contrib-watch": "1.0.0", "grunt-sails-linker": "~0.10.1", "grunt-sync": "0.5.2", "include-all": "~0.1.6", "rc": "1.0.1", "reflect-metadata": "^0.1.2", "rxjs": "5.0.1", "sails": "~0.12.13", "sails-disk": "~0.10.9", "systemjs": "0.19.40", "zone.js": "^0.8.4" } |
After that run npm install to install the dependencies.
1 | npm install |
Add the following to a new file tsconfig.json which you should place in the sails application root.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | { "compilerOptions": { "module": "commonjs", "target": "es5", "moduleResolution": "node", "sourceMap": true, "emitDecoratorMetadata": true, "experimentalDecorators": true, "lib": [ "es2015", "dom" ], "noImplicitAny": true, "suppressImplicitAnyIndexErrors": true }, "exclude": [ ".tmp", "node_modules", "typings" ] } |
Now, in your layout.ejs file add the following scripts in the head.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 | <script src="node_modules/core-js/client/shim.min.js"></script> <script src="node_modules/zone.js/dist/zone.js"></script> <script src="node_modules/reflect-metadata/Reflect.js"></script> <script src="node_modules/systemjs/dist/system.src.js"></script> <script> /** * System configuration for Angular 2 samples * Adjust as necessary for your application needs. */ (function(global) { // map tells the System loader where to look for things var map = { 'app': 'app', // 'dist', '@angular': 'node_modules/@angular', 'angular2-in-memory-web-api': 'node_modules/angular2-in-memory-web-api', 'rxjs': 'node_modules/rxjs' }; // packages tells the System loader how to load when no filename and/or no extension var packages = { 'app': { main: 'main.js', defaultExtension: 'js' }, 'rxjs': { defaultExtension: 'js' }, 'angular2-in-memory-web-api': { main: 'index.js', defaultExtension: 'js' }, }; var ngPackageNames = [ 'common', 'compiler', 'core', 'forms', 'http', 'platform-browser', 'platform-browser-dynamic', 'router', 'upgrade', ]; // Individual files (~300 requests): function packIndex(pkgName) { packages['@angular/'+pkgName] = { main: 'index.js', defaultExtension: 'js' }; } // Bundled (~40 requests): function packUmd(pkgName) { packages['@angular/'+pkgName] = { main: '/bundles/' + pkgName + '.umd.js', defaultExtension: 'js' }; } // Most environments should use UMD; some (Karma) need the individual index files var setPackageConfig = System.packageWithIndex ? packIndex : packUmd; // Add package entries for angular packages ngPackageNames.forEach(setPackageConfig); var config = { map: map, packages: packages }; System.config(config); System.import('app').catch(function(err){ console.error(err); }); })(this); </script> |
What the above code does is to load the Angular 2 and required ES6 modules. The /app/main is the entry script for angular that we still have to create.
After that, within the body tag of the same file, add the application template tag, like so:
1 2 3 | <body> <my-app>Loading...</my-app> </body> |
The my-app tag above represents the angular app which we still have to build.
But before we move on to that, if you lift the server and see the console you will see many 404 errors for the above scripts we added.
Actually, sails by default does not have a static access entry for the /node_modules folder. We will create one. Add the following code to a new file express.js in config/express.js.
1 2 3 4 5 6 | var express = require('express'); module.exports.http = { customMiddleware: function (app) { app.use('/node_modules', express.static(process.cwd() + '/node_modules')); } }; |
We are basically creating an Express middleware to allow static access to the node_modules folder. Now if you lift the server again you won’t see the 404 errors.
Now, the next step is to move on to the Angular app which we referred to above. For that let’s start with creating a directory named app in assets folder. Let’s create three files in there, app.component.ts, app.module.ts and main.ts.
These are TypeScript files which we will later compile to javascript for our Systemjs config to work. Add the following code to main.ts.
1 2 3 4 | import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; import { AppModule } from './app.module'; platformBrowserDynamic().bootstrapModule(AppModule); |
And add the following in app.component.ts.
1 2 3 4 5 6 | import {Component} from '@angular/core'; @Component({ selector: 'my-app', template: '<h1>My First Angular 2 App</h1>' }) export class AppComponent { } |
Lastly, fill in the module file app.module.ts with the following code.
1 2 3 4 5 6 7 8 9 10 | import { NgModule } from '@angular/core'; import { BrowserModule } from '@angular/platform-browser'; import { AppComponent } from './app.component'; @NgModule({ declarations: [AppComponent], imports: [BrowserModule], bootstrap: [AppComponent], }) export class AppModule {} |
Since this post is just about setting up Angular 2 with Sails, I will let skip what the code is about. It’s just a simple Angular Hello world and you can find it’s explanation on the official site.
Now that we have set up everything correctly, it’s time to compile the TypeScript files. For that let’s navigate to the project directory and run
1 | tsc |
This will transpile .ts files to .js. After that, you can lift the sails server and you should see the “My First Angular 2 App” text somewhere in the page when you browse to it. For the transpiler to compile automatically upon the change in its files run the watcher like so:
1 | tsc -w |
And that’s it!
alexey
Latest posts by alexey (see all)
- WordPress stuck on a “Too many redirects” error loop when using SSL - January 17, 2018
- Sails.js + Passport.js : req.user undefined - December 31, 2017
- “Could not open input file” on running migrations in yii2 - October 27, 2017