100 days of Angular 2 - Day 10: Update Angular and Remove Typings
Yesterday I tried to update the back end (which is just three files of Express.js related code) from JavaScript to TypeScript.
I then went to build the front end (the Angular 2 code) and everything went to hell. Depending on the environment I used to build the code with Webpack, it failed for different reasons.
On the server
90% optimize assets
Error in bail mode: [default] /home/stephen/apps/100-days-of-angular2/client/app.component.ts:5:14
Cannot find name 'require'.
and in my local environment
90% optimize assets
Error in bail mode: [default] C:\Users\stephen\git\100-days-of-angular2\client\day-001-vegetables\vegetable.service.ts:30:22
Cannot find name 'Promise'.
I'm guessing that because I'm getting different TypeScript Type information from two sources (one from the npm @types packages, the other from typings.json
) a component of the build process is getting confused.
Goodbye typings
The Angular 2 documentation and quickstart doesn't use the typings.json
file anymore, so my plan of attack for today is as follows:
- Update Angular from 2.0.1 to 2.2.0
- Remove the typings dependency and the
typings.json
file - Install the TypeScript type information using npm @types
To update Angular, I just incremented the version in my package.json
and then ran an npm install
.
$ npm install
+-- @angular/common@2.2.1
+-- @angular/compiler@2.2.1
+-- @angular/core@2.2.1
+-- @angular/forms@2.2.1
+-- @angular/http@2.2.1
+-- @angular/platform-browser@2.2.1
+-- @angular/platform-browser-dynamic@2.2.1
+-- @angular/router@3.2.1
`-- @angular/upgrade@2.2.1
Next I deleted the typings dependency and the typings.json
file. I didn't run npm uninstall
or anything, since once I commit my changes I'll eventually wipe out the entire project directory, perform a git clone
and a new npm install
to confirm I have a consistent environment down the road.
Then I ran the following two commands
$ npm install @types/core-js --save-dev
$ npm install @types/node --save-dev
I could have copied the versions that the Angular Quickstart recoomends, but I wanted to which version would show up in my package.json
relative to what the quickstart uses. There was just a patch version difference for @types/node
so I was happy with that.
Will it work?
Well, time to give it a shot. Here's what I got trying to perform the Webpack build.
$ npm run build
> angular-quickstart@1.0.0 build C:\Users\stephen\git\100-days-of-angular2
> rimraf dist && webpack --config config/webpack.prod.js --progress --profile --bail
843366ms1163ms optim141ms emit
Hash: 7d3462b07dfb3b3c8530
Version: webpack 1.13.3
Time: 16339ms
Asset Size Chunks Chunk Names
app.7d3462b07dfb3b3c8530.js 99.3 kB 0 [emitted] app
polyfills.7d3462b07dfb3b3c8530.js 97.9 kB 1 [emitted] polyfills
vendor.7d3462b07dfb3b3c8530.js 925 kB 2 [emitted] vendor
app.7d3462b07dfb3b3c8530.js.map 558 kB 0 [emitted] app
polyfills.7d3462b07dfb3b3c8530.js.map 740 kB 1 [emitted] polyfills
vendor.7d3462b07dfb3b3c8530.js.map 6.08 MB 2 [emitted] vendor
index.html 539 bytes [emitted]
+ 637 hidden modules
WARNING in app.7d3462b07dfb3b3c8530.js from UglifyJs
Condition always true [./~/angular2-template-loader!./client/main.ts:7,4]
Condition always true [./~/@angular/forms/bundles/forms.umd.js:7,0]
WARNING in polyfills.7d3462b07dfb3b3c8530.js from UglifyJs
Condition always true [./~/angular2-template-loader!./polyfills.ts:4,4]
Dropping unreachable code [./~/angular2-template-loader!./polyfills.ts:8,2]
Condition always true [./~/zone.js/dist/zone.js:9,0]
Non-strict equality against boolean: == false [./~/zone.js/dist/zone.js:1394,0]
... etc
Dropping unreachable code [./~/@angular/router/bundles/router.umd.js:825,0]
Declarations in unreachable code! [./~/@angular/router/bundles/router.umd.js:825 ,0]
Child html-webpack-plugin for "index.html":
+ 1 hidden modules
$
Looks promising. Can I get everything running in my development environment? Remember, that's three terminals:
tsc server/*.ts --watch
npm run backend
which callsnodemon --watch server ./server/bin/www
npm start
which callswebpack-dev-server --inline --progress --port 8085
In picture form it looks like this:
It works! Hooray!
Looks removing typings was a good idea. Now I need to make sure things look good in a production environment. I'll commit my changes and push to GitHub. On the server (one of my virtual machines that's running 24/7), I'll follow these steps:
git clone https://github.com/netinstructions/100-days-of-angular2 100-days-take-3
cd 100-days-take-3
npm install
npm run build
export NODE_ENV=production
tsc server/*.ts
forever start --uid="100days" --append ./server/bin/www
Note that I clone the project into a brand new directory (named 100-days-take-3
since it's my third attempt). I want to make sure I have a reproducible build an deployment process and that any lingering dependencies or files are not hanging around.
A quick note - I use forever
to keep the node.js process running for forever. I give it a process ID and also tell it to append to the existing log file located at ~/.forever/100days.log
which is left over from running the app previously.
All of the commands above worked perfectly on the server. Hooray! I gave the website a quick smoke test, clicking around and making sure things worked, and am happy with the results.
I think I'll take a break soon. There's a few things left to do down the road.
- Simplify the development process. Running three different commands in three different terminals is less than ideal.
- Finish up the server side conversion to TypeScript. Currently only
app.js
has been converted toapp.ts
but it still usesroutes/api.js
that could be converted to TypeScript. - Start exploring Angular Universal.
One of the things I want to figure out is whether Angular Universal will solve one of my routing problems. Check out this scenario:
- Visitor arrives at the root of the site. In other words, the browser requests
index.html
which loads Angular and everything else likeapp.[hash].js
. - The user then clicks on a link, such as
/tour-of-vegetables
. Angular 2 routing detects this and displays that page. No network requests actually occur to switch to that page since it already was bundled withapp.[hash].js
. The URL looks likehttp://100daysofangular2.internetuproar.com/tour-of-vegetables
Contrast that to a different scenario:
- The user enters in
http://100daysofangular2.internetuproar.com/tour-of-vegetables
to the browser's address bar. In other words, the browser requestsindex.html
from a route such as/tour-of-vegetables
which isn't defined on the server in the Express app. - User receives a 404 not found.
It's pretty easy to show by just navigating to a linked page and refreshing the page.
There's a nice discussion on URL styles with Angular 2 and on StackOverflow here, but the HashBang approach isn't the appropriate solution for me, since it doesn't preserve the option to do server-side rendering at a later point. The default HTML 5 style produces URLs that are easier for users to understand as well.
I'll need to see how or if Angular Universal has any solutions to this, since I'd like to have server side rendering anyways for other reasons (that I'll discuss tomorrow) and the server will need to be made aware of the routes and URLs in order to achieve that.
You can see the full code on GitHub here and the live website here, since it's up and running again.
Go to day 11 here.