Full-Stack Engine

Guide to create a project with Sails.js, angular-cli and angular 5

In a previous post I showed you how to create a new project with Sails.js and Angular.io from an existing template. This time I wanted to give a guide to creating a new project with this excellent framework from scratch, so we have the opportunity to dig deeper into the details and get a better insight on how they work together and all they can provide for your next full-stack project!.

You can find the source code for this project in this repository.

Without any delays, let's begin,

First of all, we need to install sails.js,

npm install sails -g

This command installs Sails.js in your computer (you might need to add sudo at the beginning of the line if you're using Linux or macOS). After installing sails globally, you can now use the (default) sails generator to create a brand new project.

Generate a new Project with Sails,

sails generate new sails-angular-webpack-starter

After running this command a new folder or directory is created with the basic directory tree, a Gruntfile.js for Grunt tasks and a package.json and also installs all npm packages with their dependencies.

sails-app-structure

Please don't change the directory to the new generated sails project yet. We need to create an angular-cli project first, from which we'll extract some components to get angular-cli and sails working hand to hand.

Then, we need to create a separate angular project with angular-cli and then copy the generated contents into our assets directory inside the sails generated by the project.

Now please install angular cli globally as we did with Sails,

npm install -g @angular/cli

Thus, we can use angular-cli to create a new Angular project.

Run this command,

ng new angular-app

Then, copy the contents inside angular-app/scr to sails-angular-webpack-starter/assets/app directory. These files are the sources of our Angular application, or the client side part of the project, as such, they go into assets directory.

Also, copy file tsconfig.json to the root of sails-angular-webpack-starter folder. This file is responsible for telling the typescript compiler how to "transpile" all files with .ts extension into .js (commonly into ES5 code).

Now, let's modify the index.html, we'll need just the head and body sections. (Since we're just adding this contents into homepage.ejs in Sails. We'll see how this works in just a moment),

<head>
  <base href="/">
  <title>Angular 5 With Webpack</title>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
</head>

<body>
  <app-root></app-root>
</body>

We can clean all the contents from homepage.ejs and just load the previous index.html file as a partial, as follows,

<!DOCTYPE html>
<html>

<!-- webpack generate html -->
<%- partial('../assets/dist/index.html') %>

</html>

Moreover, as we are not using server render pages more than homepage.ejs as the serving page for angular, we can get rid of layout.ejs, just leaving the following line,

<%- body %>

Now, let's take a break, prepare a cup of coffee and come back in 5 minutes. (Just kidding, but you can take a rest if you like ;-) ).

The next step is to copy and modify the file "angular-cli.json" from angular project's folder to sails project folder,

{
  "$schema": "./node_modules/@angular/cli/lib/config/schema.json",
  "project": {
    "name": "test-cli"
  },
  "apps": [
    {
      "root": "assets/app",
      "outDir": "assets/dist",
      "assets": [
        "assets",
        "favicon.ico"
      ],
      "index": "index.html",
      "main": "main.ts",
      "polyfills": "polyfills.ts",
      "test": "test.ts",
      "tsconfig": "tsconfig.app.json",
      "testTsconfig": "tsconfig.spec.json",
      "prefix": "app",
      "styles": [
        "styles.css"
      ],
      "scripts": [],
      "environmentSource": "environments/environment.ts",
      "environments": {
        "dev": "environments/environment.ts",
        "prod": "environments/environment.prod.ts"
      }
    }
  ],
  "e2e": {
    "protractor": {
      "config": "./protractor.conf.js"
    }
  },
  "lint": [
    {
      "project": "src/tsconfig.app.json",
      "exclude": "**/node_modules/**"
    },
    {
      "project": "src/tsconfig.spec.json",
      "exclude": "**/node_modules/**"
    },
    {
      "project": "e2e/tsconfig.e2e.json",
      "exclude": "**/node_modules/**"
    }
  ],
  "test": {
    "karma": {
      "config": "./karma.conf.js"
    }
  },
  "defaults": {
    "styleExt": "css",
    "component": {}
  }
}

As you might notice, the only changes are relative paths to locations in the sails project tree.

Similarly, modify the contents of packages.json in sails project,

{
  "name": "sails-angular-cli-guide",
  "private": true,
  "version": "0.0.0",
  "description": "a Sails application",
  "keywords": [],
  "dependencies": {
    "@angular/animations": "^5.0.0",
    "@angular/common": "^5.0.0",
    "@angular/compiler": "^5.0.0",
    "@angular/core": "^5.0.0",
    "@angular/forms": "^5.0.0",
    "@angular/http": "^5.0.0",
    "@angular/platform-browser": "^5.0.0",
    "@angular/platform-browser-dynamic": "^5.0.0",
    "@angular/router": "^5.0.0",
    "core-js": "^2.4.1",
    "rxjs": "^5.5.2",
    "zone.js": "^0.8.14",
    "ejs": "2.3.4",
    "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": "^1.0.0",
    "rc": "1.0.1",
    "sails": "~0.12.14",
    "sails-disk": "~0.10.9"
  },
  "devDependencies": {
    "@angular/cli": "1.5.0",
    "@angular/compiler-cli": "^5.0.0",
    "@angular/language-service": "^5.0.0",
    "npm-run-all": "^4.1.1",
    "@types/core-js": "^0.9.41",
    "@types/jasmine": "~2.5.53",
    "@types/jasminewd2": "~2.0.2",
    "@types/node": "~6.0.60",
    "angular2-template-loader": "^0.6.2",
    "awesome-typescript-loader": "^3.3.0",
    "codelyzer": "~3.2.0",
    "jasmine-core": "~2.6.2",
    "jasmine-spec-reporter": "~4.1.0",
    "karma": "~1.7.0",
    "karma-chrome-launcher": "~2.1.1",
    "karma-cli": "~1.0.1",
    "karma-coverage-istanbul-reporter": "^1.2.1",
    "karma-jasmine": "~1.1.0",
    "karma-jasmine-html-reporter": "^0.2.2",
    "protractor": "~5.1.2",
    "rimraf": "^2.6.2",
    "sails-hook-autoreload": "^0.14.3",
    "ts-node": "~3.2.0",
    "tslint": "~5.7.0",
    "typescript": "~2.4.2"
  },
  "scripts": {
    "start": "npm-run-all --parallel open:client dev",
    "start:debug" : "npm-run-all --parallel open:client debug",
    "open:client" : "ng serve --open",
    "build": "npm run build:prod",
    "build:dev": "ng build --deploy-url=dist",
    "build:prod": "ng build --prod --deploy-url=dist",
    "build:aot": "ng build --aot --deploy-url=dist",
    "clean": "rimraf assets/dist",
    "prod": "sails lift --prod",
    "dev": "sails lift --dev",
    "debug": "node --inspect app.js"
  },
  "main": "app.js",
  "repository": {
    "type": "git",
    "url": "git://github.com/eduardo/sails-angular-cli-guide.git"
  },
  "author": "sepineda",
  "license": ""
}

Here, of course, we added all the Angular libraries and its dependencies. However, also added some useful scripts:

  • npm run start: Build the project's assets (front-end), starts running sails and open a new window with ng server watching code for updates in real time.
  • npm run start:debug: Similar to start, but also starts node in "inspect" mode. Please take a look to this post for more information for debugging Sails.js back-end code with Chrome's DevTools.
  • npm run build: Builds the project's assets in the development environment. Add build:prod for production and build:aot for ahead of time compilation.
  • npm run dev: Starts running sails in dev environment (run "npm run build:dev before).
  • npm run prod: Runs sails in the production environment. You should use this for deploying to a public server (run "npm build:prod" before).
  • debug: Starts Sails.js in inspect mode to debug back-end code with Chrome's DevTools. Please take at this post for a detailed explanation.

Now, run npm install to get all the packages from both Angular and Sails.js,

npm install

Next, as we're using angular-cli, there's no need for Grunt pipeline running in Sails, so we can disable the built-in grunt hook, by modifying .sailsrc:

// .sailsrc 
{
  "hooks": {
    "grunt": false
  }
}

We can add a nice feature to Sails for live reloading changes in the back-end code, with a hook named sails-hok-autoreload. This package is already present in package.json, so we need just to add a configuration file in "config" folder, this file is called autoreload.js,

// [root-directory]/config/autoreload.js
module.exports.autoreload = {
  active: true,
  usePolling: false,
  dirs: [
    "api/models",
    "api/controllers",
    "api/services",
    "config/locales"
  ],
  ignored: [
    // Ignore all files with .ts extension
    "**.ts"
  ]
};

Now, every time we change something in models, controllers, services or locales, Sails is going to reload the changes we made on the fly.

Finally, we are ready to lift!.

Thanks for reading this post, that's all for today.
Take care, and I'll see you next time. Stay tuned!.

Author image
Costa Rica
Passionate Software Developer with full-stack development experience.