Thanks for visiting my blog!
I know this was a “click-bait” post name, but so be it. I’ve been doing some small Angular2 in a recent project (rebuilding the new Atlanta Code Camp website) and I’ve been frustrated with the amount of ceremony. But I may be misunderstanding Angular2 so bear with me.
The problem for me is in the idea of SPA in general. SPA seems to imply monolithic apps but written in client-side web code. For a single, large scale application, Angular2 seems like it is just right…but that’s not what I do.
I want client-side frameworks to fill in the holes for when a website needs rich user interaction. Making every part of a page some sub-element in a huge SPA makes as little sense as the old monolithic Visual Basic 3.0 apps that used to be the norm.
To Be Clear…
Usually when I talk about this topic, I get a flurry of comments telling me to try and other frameworks (usually Aurelia and React). I’ve looked at them and at the moment, I’m trying to understand Angular2 – not pick a framework so those comments aren’t especially helpful to me.
How I Think Angular2 Works
I’m going to use my CoreCodeCamp project as the example since that’s what I’ve been writing there. Angular2 starts out with a simple method of bootstrapping your application, for example (in TypeScript):
// main.ts
import { bootstrap } from '@angular/platform-browser-dynamic';
import { HTTP_PROVIDERS } from '@angular/http';
import { disableDeprecatedForms, provideForms } from '@angular/forms';
import { EventInfoForm } from './eventInfoForm';
import { DataService } from "../common/dataService";
bootstrap(EventInfoForm,
[disableDeprecatedForms(),
provideForms(),
HTTP_PROVIDERS,
DataService]);
This is to bootstrap a single angular project. I need to build this file every time it seems. That’s not a big deal, but the bootstrap takes a component (e.g. EventInfoForm) as the starting component. Since I’m building six of these, I have to repeat this instead of just having components that I’d like to use on different pages (one large module instead of six individual modules). I don’t know that six modules aren’t better, but not having a choice seemed odd.
So here I want to use a shared component (DataService) so I need to pass it into the modules in the bootstrap and then again import it into the main component (EventInfoForm) like so:
// scheduleForm.ts
import { Component } from '@angular/core';
import { DatePipe } from '@angular/common';
import { Response } from '@angular/http';
import { BaseForm } from "../common/baseForm";
import { Observable } from 'rxjs/Rx';
import { DataService } from "../common/dataService";
@Component({
selector: "event-info-form",
templateUrl: "/js/app/eventInfo/eventInfoForm.html"
})
export class EventInfoForm extends BaseForm {
// ...
constructor(private data: DataService) {
super();
this.loadEventInfo();
}
...
So far, I’ve had to reference the DataService four times before I could even use it. But this doesn’t work yet, because the loaders don’t know about it. That’s where SystemJS and/or Webpack come in.
Webpack and SystemJS
Before this works, I have to configure either SystemJS or Webpack to load them. In my case, I had to do both (since I’m using SystemJS to load for development so I don’t have to wait for webpack on every change, but using Webpack for deployment). So for SystemJS I have to configure each of my six modules into loading via a .js file:
// In System.config.js
// Our Components
["users", "speaker", "talks", "sponsors", "schedule", "eventInfo"]
.forEach(function (c) {
map[c] = '/js/app/' + c;
packages[c] = { main: 'main.js', defaultExtension: 'js' };
});
["fileUploadService"].forEach(function (c) {
map[c] = '/js/app/common/';
packages[c] = { defaultExtension: 'js' };
});
And in Webpack I needed to do this similarly to get six different webpacks:
var webpack = require('webpack');
var path = require('path');
module.exports = {
context: path.resolve("./wwwroot/js/app/"),
entry: {
eventInfo: "./eventInfo/main.ts",
speaker: "./speaker/main.ts",
sponsors: "./sponsors/main.ts",
talks: "./talks/main.ts",
schedule: "./schedule/main.ts",
users: "./users/main.ts"
},
...
That’s a lot of work just to get to the first line of actual logic code. Maybe I’m missing something.
I liked the Angular1 notion that including the modules meant I was registering the directives and I could just use them on pages as I wanted. I didn’t need to have an explicit ‘startup’ directive/component.
Modules in Angular2
Another problem has to do with packaging shared code into an insert-able module. This is likely a TypeScript thing more than an Angular2 thing. But I might be missing something. It seems to me folders as modules should just work but I could never get TypeScript to know what it is (even with an index.ts with explicit exports). Packaging seems harder than it should be, please tell me I’m wrong.
Maybe I’m Confused…
There is a lot in Angular2 I do like so I don’t want people to think I’m throwing the baby out with the bathwater. I just am trying to figure out how this can be streamlined so I spend more time writing usable code and less time debugging missing modules and imports. Please tell me I’m wrong and confused.