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.
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.
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.
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.
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.