First coding week
The first week of GSoC 2016 coding period has ended. I started upgrading Jangouts from Angular 1.x to Angular 2. I completed all tasks within the deadline and hope to maintain this pace next week.
I'm following the upgrade guide from official Angular docs, which has two main blocks:
- Preparation
- Upgrading with The Upgrade Adapter
I just finished the preparation block. Fortunately, the Jangouts code is clear
and already follows two key preparation requirements: the Angular style guide
and component directives. This left me only two tasks: switch from <script>
tags to a module loader, and migrate from JavaScript to TypeScript. I reversed
the order, migrating to TypeScript first and then switching to a module loader.
This sequence felt more natural for this project.
Migrating to TypeScript
Jangouts has a working gulp build system, so I did not need to worry about
script loading. I focused first on migrating files to TypeScript, then leveraged
the import syntax of TypeScript/ES6.
Migrating code from JavaScript to TypeScript is straightforward: change the
extension from .js to .ts. The existing gulp system does not work with these
changes, so run tsc --watch src/**/*.ts alongside gulp. This command shows
many errors, but if the JavaScript code is correct, these errors relate only to
TypeScript's type checking.
During this migration, I also made the code more modular. Jangouts had all
components registered in a single Angular module janusHangouts. From previous
projects, I learned this causes trouble with unit testing. I now define a
separate module for each component (janusHangouts.componentName) and make it a
dependency of the main module. This has two advantages: easier testing, and
potentially loading components on demand with a module loader.
As mentioned earlier, compiling JavaScript code with tsc shows many errors.
One common error is:
error TS7006: Parameter '$state' implicitly has an 'any' type.
The TypeScript compiler requires a type for all variables. To allow implicit
any types for untyped variables, disable noImplicitAny in tsconfig.json.
Another error we can find when working with HTML elements is:
error TS2339: Property 'muted' does not exist on type 'HTMLElement'.
This error is produced from a code like that:
var video = $("video", element)[0];video.muted = true;
TypeScript is type safe: $('video', element)[0] returns HTMLElement, which
lacks the muted property. The subtype HTMLVideoElement contains muted.
Cast the result to HTMLVideoElement:
var video = <HTMLVideoElement>$('video', element)[0];video.muted = true;
Finally, another common error is:
error TS2339: Property 'id' does not exist on type '{}'.
TypeScript's type validation causes this error in code like:
var room = {};// Some code here...function isRoom(room) {return room.id == roomId;}
Define an interface for the room object to fix this and reduce errors:
interface Room {id?: number; // ? makes the attribute optional}// Some code here ...var room: Room = {};// Some code here...function isRoom(room: Room) {return room.id == roomId;}
Using a Module Loader
Why use a module loader? The Angular site explains:
Using a module loader such as SystemJS, Webpack, or Browserify allows us to use the built-in module systems of the TypeScript or ES2015 languages in our apps. We can use the import and export features that explicitly specify what code can and will be shared between different parts of the application. [...]
When we then take our applications into production, module loaders also make it easier to package them all up into production bundles with batteries included.
I discarded Browserify due to past bad experiences and tried only SystemJS and Webpack.
SystemJS
SystemJS looks clean and simple. Define an entry point (typically the main
application file) and the import syntax handles the rest. With correct
import statements, everything works.
However, this solution requires keeping gulp since SystemJS only handles imports. This means adding the TypeScript compiler to gulp and disabling auto script injection in HTML.
Before rewriting the gulp configuration, I wanted to try Webpack first.
Webpack
Webpack configuration is more complex than SystemJS, but replaces gulp entirely.
Like SystemJS, we define an entry point and specify where index.html is
located for JavaScript file inclusion.
I had initial troubles, but after studying examples, I got a functional version.
Exploring Webpack further, I found what made me choose it: we can import or
require non-JavaScript files. We can require an Angular directive template,
and the build process includes it as a string variable inside the component.
Styles work the same way. This improves performance by bundling all files a
component needs into its JavaScript file, without complicating development.
One more thing
This summer looks exciting with everything I will learn through GSoC. Follow my progress on this blog or through my GitHub contributions. I also published a Trello board with the project planning and tasks (still being updated).