-
Notifications
You must be signed in to change notification settings - Fork 2.2k
Description
Release Candidate API Proposal
Please read and leave feedback!
AngularFire2 is almost ready for its first semver release! Before that can happen, a few problems must be addressed.
Removing AngularFire for Modularity
AngularFire2 does not take advantage of the Firebase SDK's modularity. Users who only need authentication receive database code and vice versa. The AngularFire service is a central part of this problem. The class includes each feature whether you are using it or not. Even worse, this cannot be tree-shaken. As the library grows to include more features, this will only become more of a problem.
The way to fix this is to remove the AngularFire service and break up the library into smaller @NgModules.
AngularFireModule(Firebase app only)AngularFireAuthModuleAngularFireDatabaseModuleAngularFireStorageModule(Future release)AngularFireMessagingModule(Future release)
This will allow you to get the code for only what features you need. Below is an example setup:
import { NgModule, Component } from '@angular/core';
import { Observable } from 'rxjs/Observable';
import { AngularFireModule } from 'angularfire2';
import { AngularFireDatabaseModule, AngularFireDatabase } from 'angularfire2/database';
import { AngularFireAuthModule, AngularFireAuth } from 'angularfire2/auth';
const config = { }; // firebase config
@NgModule({
declarations: [ App ],
exports: [ App ],
imports: [
AngularFireModule.initializeApp(config)
AngularFireDatabaseModule,
AngularFireAuthModule,
],
bootstrap[ App ]
})
export class MyModule { }
@Component({
selector: 'my-app',
template: `
<div> {{ (items | async)? | json }} </div>
<div> {{ user.authState | async)? | json }} </div>
`
})
export class App {
user: Observable<any>;
items: Observable<any>;
constructor(auth: AngularFireAuth, db: AngularFireDatabase) {
this.items = db.list('items');
}
}Instead of pulling each feature off the AngularFire service, you now import each feature module.
Breaking: Simplified Authentication API
The goal of AngularFire (1 & 2) is not to wrap the Firebase SDK. This is something I wrote in a blog post way back in 2014 about AngularFire 0.8.
The goal is to provide Angular-specific functionality. We've done this with FirebaseListObservable and its advanced querying techniques, but the current authentication API offers little outside of the Firebase SDK. The Authentication API also requires the most maintenance as it has quirks across different browsers and platforms like Cordova. Wrapping the API puts AngularFire2 in the middle of these changes, make it prone to break.
My solution is to simplify the API. This, however, means breaking changes. Below is the proposed API and an example:
interface AngularFireAuth {
auth: FirebaseAuth;
authState: Observable<firebase.User>;
}import { NgModule, Component } from '@angular/angularfire2';
import { AngularFireModule } from 'angularfire2';
import { AngularFireAuthModule, AngularFireAuth } from 'angularfire2/auth';
const config = {}; // firebase config
@NgModule({
declarations: [ App ],
exports: [ App ],
imports: [
AngularFireModule.initializeApp(config)
AngularFireAuthModule,
],
bootstrap[ App ]
})
export class MyModule { }
@Component({
selector: 'my-app',
template: ` `
})
export class App {
constructor(private afAuth: AngularFireAuth) {
afAuth.authState.subscribe(user => console.log(user));
}
signIn() {
afAuth.auth.signInAnonymously();
}
}The authState observable is the best candidate for Angular-specific functionality. The rest of the methods are removed.
This proposal removes custom methods like .createUser(). Most of the custom authentication methods were simply wrapper calls around the official SDK. Rather than creating more bytes for no value, the Firebase Auth instance is available as a property named auth where the same functionality exists.
Remove pre-configure login
This change also removes pre-configuring login. Pre-configuring is a convenient feature, but this API has introduced a fair amount of complexity into the codebase for fairly low value. This is another decision to forgo minor conveniences for simplicity and less code.
I understand that this is likely the hardest of all the breaking changes, so I am open to suggestions. However, I want to keep to the ideals that AngularFire2 is not a wrapper.
We also have plans for authentication based route guards, but more research is needed before we have an API.
Breaking: FirebaseListFactory and FirebaseObjectFactory only take in a Database Reference
This change only affects a few users who directly use FirebaseListFactory. Most people inject AngularFireDatabase directly or use the AngularFire service.
If you directly use FirebaseListFactory you will no longer be able to pass in a string. **The AngularFireDatabase service will still take paths for .list() and .object(). With the FirebaseApp now easily injectable, you can create a reference while still adhering to DI.
This is a minor change, but again it prioritizes simplicity. It keeps the library from writing check logic at multiple abstractions. This again reduces complexity and maintenance.
Below is an example:
import { FirebaseApp } from 'angularfire2';
import { FirebaseListFactory, FirebaseObjectFactory, AngularFireDatabase } from 'angularfire2/database';
@Component({
selector: 'app',
template: ``
})
export class App {
list: Observable<any>;
constructor(app: FirebaseApp, db: AngularFireDatabase) {
const listRef = app.database.ref('things');
const list = FirebaseListFactory(listRef);
const obj = FirebaseObjectFactory(listRef.child('thing_1'));
// const list = FirebaseListFactory('things'); <- no longer valid
// const obj = FirebaseObjectFactory('things/thing_1'); <- no longer valid
const list2 = db.list('things'); // still valid
const obj2 = db.object('things/thing_1'); // still valid
}
}Semver: AngularFire2 4.0
Let's talk about naming. AngularFire2 is the second AngularFire. It's not "AngularFire" for Angular 2. Now, I'll admit, this isn't ideal for a name. However, we can't rename the original AngularFire to AngularFireJS. There are many people with AngularFire apps in production and we do not have to cause a problem over vanity.
When we release the semver version will be AngularFire2 4.0.
When the breaking changes are implemented, AngularFire2 will enter version rc0. Once enough adoption and feedback have been received (and bugs fixed), will release to 4.0.
We are investigating scoped packaging to get @angularfire/core, @angularfire/database, @angularfire/auth, and etc. However, there are draw backs to maintaining several scoped packages, such as handling several version mismatches.
Post 4.0
After 4.0 we'll focus on features. Here are the items on the docket:
- Cloud Storage for Firebase (with a snazzy directive too!)
- Firebase Cloud Messaging
- Authentication Route Guards
- A real documentation site
- Lazy loading of Firebase Feature Modules (independent of router)
- Angular Universal Integration
Conclusion: Sticking to a principle
This is a big change. But this change brings several new benefits, and most importantly a guiding principle for AngularFire2. AngularFire2 is not a wrapper around the Firebase SDK. AngularFire2 integrates Firebase into Angular-specific features. If the solution is a simple function wrap, then it doesn't fit the principle.
Your feedback is not only welcome, but it is necessary in making AngularFire2 the best Firebase and Angular experience possible.