I’ve written previously about how to deploy an Angular CLI Webpack project without Rails.
I’ve also written about how to deploy an Angular 2/Rails 5 project, but not one that uses Angular CLI Webpack.
Following are instructions for deploying a Rails 5 app with an Angular 2 front-end that was generated with Angular CLI, Webpack version. (Specifically, Angular CLI version 1.0.0-beta.11-webpack.8.)
Create the Rails App
First, create an API-only Rails application.
Create the Angular App
Before you create the Angular app, make sure you have the following versions of the following things installed:
Angular CLI: 1.0.0-beta.11-webpack.8
NPM: 3.10.6
Node: 6.5.0
Then, just like I had us do in the Angular-only version of this post, we’ll create an Angular app with the silly name of bananas
.
In this case it’s important that we call the Angular directory client
. Don’t worry about why right now. I’ll explain shortly.
$ ng new bananas
$ mv bananas client
And also just like in the Angular-only version, we’ll want to make sure we can run ng-build
without problems.
$ cd client
$ ng build
If you try it and it doesn’t work (which is very likely), just refer to the other post for how to fix it.
Modify package.json
We need to do a few things to package.json
. Don’t worry if you don’t understand every item. I’ve shared my package.json
below which you can just copy and paste if you want.
We want Heroku to do an ng build
for us after the build. So we need to add this line:
"heroku-postbuild": "ng build",
We also need to move our devDependencies
into dependencies
because we need some of them in production.
We’ll want to remove the "start": "ng serve"
script because it doesn’t apply.
Lastly, an absence of node-gyp
will cause error messages to appear. So we’ll add this line:
"preinstall": "npm install -g node-gyp",
Following is what my package.json
looks like.
{
"name": "bananas",
"version": "0.0.0",
"license": "MIT",
"angular-cli": {},
"scripts": {
"lint": "tslint \"src/**/*.ts\"",
"test": "ng test",
"pree2e": "webdriver-manager update",
"e2e": "protractor",
"preinstall": "npm install -g node-gyp",
"heroku-postbuild": "ng build"
},
"private": true,
"dependencies": {
"@angular/common": "2.0.0-rc.5",
"@angular/compiler": "2.0.0-rc.5",
"@angular/core": "2.0.0-rc.5",
"@angular/forms": "0.3.0",
"@angular/http": "2.0.0-rc.5",
"@angular/platform-browser": "2.0.0-rc.5",
"@angular/platform-browser-dynamic": "2.0.0-rc.5",
"@angular/router": "3.0.0-rc.1",
"core-js": "^2.4.0",
"rxjs": "5.0.0-beta.11",
"ts-helpers": "^1.1.1",
"zone.js": "0.6.12",
"@types/jasmine": "^2.2.30",
"angular-cli": "1.0.0-beta.11-webpack.8",
"codelyzer": "~0.0.26",
"jasmine-core": "2.4.1",
"jasmine-spec-reporter": "2.5.0",
"karma": "0.13.22",
"karma-chrome-launcher": "0.2.3",
"karma-jasmine": "0.3.8",
"karma-remap-istanbul": "^0.2.1",
"protractor": "4.0.3",
"ts-node": "1.2.1",
"tslint": "3.13.0",
"typescript": "2.0.0"
},
"devDependencies": {
}
}
Create public symlink
When someone visits /index.html
in the browser, the file they’ll actually be served is Rails’ public/index.html
. We can do a little trick where we symlink the public
directory to client/dist
. That way when someone visits /index.html
they’ll be served client/dist/index.html
, thus loading the Angular app.
Let’s kill the public
directory and replace it with a symlink.
$ rm -rf public
$ ln -s client/dist public
Create the Heroku app
I’m assuming you have a Heroku account and you have Heroku CLI installed.
$ heroku create
Specify the buildpacks
Lastly, we’ll tell Heroku to use two certain buildpacks:
$ heroku buildpacks:add https://github.com/jasonswett/heroku-buildpack-nodejs
$ heroku buildpacks:add heroku/ruby
Remember when I said we needed to call our Angular directory client
? The reason is because of my custom Node buildpack. I’ve modified Heroku’s Node buildpack to look for package.json
in client
rather than at the root. This is what allows us to nest an Angular app inside of a Rails app and still have Heroku do what it needs to do with each.
Deploy the app
Make sure your code is all committed and do a git push
.
$ git push heroku master
When it’s done, open the app. You should see “app works!”.
$ heroku open
If you want, I have a full repo with the code used in this example.