Angular: 9.0.0-rc.7
Firebase: 7.6.1
AngularFire: 5.3.0-rc.4
Other (e.g. Ionic/Cordova, Node, browser, operating system):
node v12.3.1
Try to compile and run an Angular Universal app that has a dependency on @angular/fire/firestore. It won't even compile unless you run the ngcc.
If you run ngcc, though, then you will get an error when you run your server like this:
/Users/jeffwhelpley/repos/criticly/frontend/dist/apps/criticly/server/main.js:92536
AngularFirestore.ɵprov = ɵngcc0.ɵɵdefineInjectable({ token: AngularFirestore, factory: function (t) { return AngularFirestore.ɵfac(t); } });
^
TypeError: ɵngcc0.ɵɵdefineInjectable is not a function
at /Users/jeffwhelpley/repos/criticly/frontend/dist/apps/criticly/server/main.js:92536:33
at /Users/jeffwhelpley/repos/criticly/frontend/dist/apps/criticly/server/main.js:92567:6
at /Users/jeffwhelpley/repos/criticly/frontend/dist/apps/criticly/server/main.js:92235:13
at Object.../../node_modules/@angular/fire/bundles/firestore.umd.js (/Users/jeffwhelpley/repos/criticly/frontend/dist/apps/criticly/server/main.js:92237:2)
at __webpack_require__ (/Users/jeffwhelpley/repos/criticly/frontend/dist/apps/criticly/server/main.js:20:30)
When I look at the UMD that is generated for Firestore by ngcc, I see this at the beginning:
(function (global, factory) {
true ? factory(exports, __webpack_require__(/*! rxjs */ "../../node_modules/rxjs/index.js"), __webpack_require__(/*! rxjs/operators */ "../../node_modules/rxjs/operators/index.js"), __webpack_require__(/*! @angular/fire */ "../../node_modules/@angular/fire/bundles/core.umd.js"), __webpack_require__(/*! @angular/core */ "../../node_modules/@angular/core/bundles/core.umd.js"), __webpack_require__(/*! @angular/common */ "../../node_modules/@angular/common/bundles/common.umd.js"), __webpack_require__(/*! firebase/app */ "../../node_modules/firebase/app/dist/index.cjs.js"), __webpack_require__(/*! firebase/firestore */ "../../node_modules/firebase/firestore/dist/index.cjs.js"),__webpack_require__(/*! @angular/core */ "../../node_modules/@angular/core/bundles/core.umd.js")) :
undefined;
}(this, (function (exports,rxjs,operators,fire,core,common,firebase,ɵngcc0) { 'use strict';
I was debugging this code for awhile to try and figure out what is going on until I realized that the call to the factory() function is sending in more input params (9) than there is actually in the function definition (8). he function has exports,rxjs,operators,fire,core,common,firebase,ɵngcc0 which is 8 params, but here is what the factory is sending in:
1. exports
2. __webpack_require__(/*! rxjs */ "../../node_modules/rxjs/index.js")
3. __webpack_require__( "../../node_modules/rxjs/operators/index.js")
4. __webpack_require__( "../../node_modules/@angular/fire/bundles/core.umd.js")
5. __webpack_require__( "../../node_modules/@angular/core/bundles/core.umd.js")
6. __webpack_require__("../../node_modules/@angular/common/bundles/common.umd.js")
7. __webpack_require__("../../node_modules/firebase/app/dist/index.cjs.js")
8. __webpack_require__("../../node_modules/firebase/firestore/dist/index.cjs.js")
9. __webpack_require__(/*! @angular/core */ "../../node_modules/@angular/core/bundles/core.umd.js")
When you look at the original UMD for Firestore, this starts to make sense because you can see there is an extra param there as well:
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('rxjs'), require('rxjs/operators'), require('@angular/fire'), require('@angular/core'), require('@angular/common'), require('firebase/app'), require('firebase/firestore')) :
typeof define === 'function' && define.amd ? define(['exports', 'rxjs', 'rxjs/operators', '@angular/fire', '@angular/core', '@angular/common', 'firebase/app', 'firebase/firestore'], factory) :
(factory((global.angularfire2 = global.angularfire2 || {}, global.angularfire2.firestore = {}),global.rxjs,global.rxjs.operators,global.angularfire2,global.ng.core,global.ng.common,global.firebase));
}(this, (function (exports,rxjs,operators,fire,core,common,firebase) { 'use strict';
You can see here that require('firebase/firestore') is at the end of the factory() call, but there is no param for that. So, in the original UMD there is no harm because that extra param isn't used. But, ngcc must be adding an extra param without checking for this.
So, I believe at least part of the fix is figuring out why the normal Firestore UMD has that references to /firebase/firestore even though it is not being used.
Steps to set up and reproduce
package.json scripts section make sure you have "postinstall": "ngcc"angular.json server options section make sure you have "bundleDependencies": true and add externalDependencies there for any native dependenciesSample data and security rules
N/A
* Errors in the JavaScript console *
N/A
* Output from firebase.database().enableLogging(true); *
N/A
* Screenshots *
N/A
To not error out
Get errors listed above.
As a secondary issue which is related, once I hack the Firestore UMD to temporarily fix the issue described above ^^^ (by removing the require('firebase/firestore') param in the UMD), I run into another issue depending on whether or not I add @angular/fire/firestore to my list of externalDependencies in angular.json.
If @angular/fire/firestore is in externalDependencies then I get this error when trying to go to a server route:
Error: Uncaught (in promise): Error: inject() must be called from an injection context
Error: inject() must be called from an injection context
at injectInjectorOnly (/Users/jeffwhelpley/repos/criticly/frontend/node_modules/@angular/core/bundles/core.umd.js:972:19)
at Object.ɵɵinject (/Users/jeffwhelpley/repos/criticly/frontend/node_modules/@angular/core/bundles/core.umd.js:983:61)
at Function.AngularFirestore_Factory [as ɵfac] (/Users/jeffwhelpley/repos/criticly/frontend/node_modules/@angular/fire/bundles/firestore.umd.js:307:106)
at Object.factory (/Users/jeffwhelpley/repos/criticly/frontend/node_modules/@angular/fire/bundles/firestore.umd.js:308:127)
at R3Injector.../../node_modules/@angular/core/bundles/core.umd.js.R3Injector.hydrate (/Users/jeffwhelpley/repos/criticly/frontend/dist/apps/criticly/server/main.js:72465:39)
Which I would imagine is because the main server package is using the @angular/core that is part of the main server package while Firestore in this case ^^^ is using @angular/core under node_modules. Thus the injection context is going to be different.
If @angular/fire/firestore is NOT in externalDependencies (i.e. it is packaged along with the main server build) then I get this error:
[2020-01-06T18:42:32.270Z] @firebase/firestore: Firestore (7.6.0): INTERNAL UNHANDLED ERROR: Error: ENOENT: no such file or directory, open '/Users/jeffwhelpley/repos/criticly/frontend/dist/apps/criticly/server/src/protos/google/firestore/v1/firestore.proto'
at Object.openSync (fs.js:431:3)
at Object.readFileSync (fs.js:333:35)
at fetch (/Users/jeffwhelpley/repos/criticly/frontend/node_modules/protobufjs/src/root.js:160:34)
at Root.load (/Users/jeffwhelpley/repos/criticly/frontend/node_modules/protobufjs/src/root.js:194:13)
at Root.loadSync (/Users/jeffwhelpley/repos/criticly/frontend/node_modules/protobufjs/src/root.js:235:17)
at Object.loadSync (/Users/jeffwhelpley/repos/criticly/frontend/node_modules/@grpc/proto-loader/build/src/index.js:221:27)
at loadProtos (/Users/jeffwhelpley/repos/criticly/frontend/dist/apps/criticly/server/main.js:135816:41)
The reason for this is because of this line of code where one of the downstream dependencies is referencing __dirname:
Since the code has been packaged up with the main server build, that path to firestore.proto is no longer valid.
So, I think one of two fixes clearly have to be made:
A) If firestore an external dependency, then have to figure out some way to maintain the same angular core context (not sure how to do that, though)
B) If firestore is packaged with the server build, need to update the firebase/firestore code so that it can still find that firestore.proto file.
OK, so after a lot of hacking compiled module code, I have Angular Universal + Firestore working for Angular v9 (Ivy). There definitely are some fixes needed here. The hacks I had to make are as follows:
Of the various options above, I did set it up to have the Angular server build include @angular/fire/firestore in the package (i.e. in other words, I did NOT add it to the externalDependencies in angular.json). I also had ngcc run as a postinstall step.
In my compiled server module code I manually changed the Firestore UMD bundle factory function so that it doesn't have that extra parameter anymore (but I did have to still require firebase/firestore so that it adds itself to the global firestore object):
(function (global, factory) {
// I added this so firestore adds itself to the global firebase object
__webpack_require__(/*! firebase/firestore */ "../../node_modules/firebase/firestore/dist/index.cjs.js");
// I removed the extra param to the factory here so that there are 8 inputs instead of 9
true ? factory(exports, __webpack_require__(/*! rxjs */ "../../node_modules/rxjs/index.js"), __webpack_require__(/*! rxjs/operators */ "../../node_modules/rxjs/operators/index.js"), __webpack_require__(/*! @angular/fire */ "../../node_modules/@angular/fire/bundles/core.umd.js"), __webpack_require__(/*! @angular/core */ "../../node_modules/@angular/core/bundles/core.umd.js"), __webpack_require__(/*! @angular/common */ "../../node_modules/@angular/common/bundles/common.umd.js"), __webpack_require__(/*! firebase/app */ "../../node_modules/firebase/app/dist/index.cjs.js"), __webpack_require__(/*! @angular/core */ "../../node_modules/@angular/core/bundles/core.umd.js")) :
undefined;
}(this, (function (exports,rxjs,operators,fire,core,common,firebase,ɵngcc0) { 'use strict';
I am not 100% but I believe ultimately this issue comes from this line in the source code:
https://github.com/angular/angularfire/blob/master/src/firestore/firestore.ts#L17
You can see the comment about it being there just for Angular 6 support. That firestore import reference isn't used anywhere. So I believe when the UMD module is built during the publishing process, it must result in that extra param in the UMD factory function. It is a hack, but I am pretty sure a super quick fix for this would be to use that firestore import value so that rollup or whatever is doing the compiling doesn't remove it.
__dirname:function loadProtos() {^M
//var root = path.resolve(__dirname, "src/protos" );^M
var root = "/Users/jeffwhelpley/repos/criticly/frontend/node_modules/@firebase/firestore/dist/src/protos";
var firestoreProtoFile = path.join(root, 'google/firestore/v1/firestore.proto');^M
var packageDefinition = protoLoader.loadSync(firestoreProtoFile, tslib.__assign(tslib.__assign({}, protoLoaderOptions), { includeDirs: [root] }));^M
return grpc.loadPackageDefinition(packageDefinition);^M
}
Now, interestingly, if you look at the source for this one:
You will see that there is a possibility to set FIRESTORE_PROTO_ROOT. However, that doesn't appear in the compiled code. So, the solution for this part of the issue should be to make it so the user can configure the FIRESTORE_PROTO_ROOT at run time. You cannot right now because it is not in the compiled code. Ideally this would be a configurable value in the AngularFire module (or AngularFire would just automatically set this correctly since it shouldn't change for Angular users).
@jeffwhelpley, FYI with regards to the FIRESTORE_PROTO_ROOT the environment variable itself is not available in the distributed version.
See: https://unpkg.com/browse/@firebase/firestore@1.9.1/dist/index.node.cjs.js - Line 23213
Regarding the UMD processing there is seems to be a bug as correctly mentioned above, however I didn't need to run NGCC as a postinstall hook as @angular/fire/store was processed even without it.
Maybe you can share a repo where your are encountering this issue?
PS: This issues is more of an Angular FW thing, rather than Angular Fire.
Here is a PR for the ngcc side of things: https://github.com/angular/angular/pull/34660
Here is a public repo with the issue: https://github.com/jeffwhelpley/ngufire. Follow the instructions in the README to recreate the issue.
Thanks for spelunking through this! Once we drop ng6 we'll be able to use Typescript versions that support dynamic types, typeof import('blah'). The lack of this feature is why I have "unused" imports.
I'm going to start developing v6 off of master today; expect me to drop those soon. Keep an eye out for @canary builds.
Should be addressed in 6.0.0-rc.0 reopen if you are continuing to have trouble.
Getting this error in version 10 of angular
This likely means that the library (@angular/fire/firestore) which declares AngularFirestore has not been processed correctly by ngcc, or is not compatible with Angular Ivy. Check if a newer version of the library is available, and update if so. Also consider checking with the library's authors to see if the library is expected to be compatible with Ivy.
any update on this issue ?
@OmarHegazi94 there's no issue here any longer. We're fully compatible with IVY and the latest versions of Angular.
Most helpful comment
Getting this error in version 10 of angular
This likely means that the library (@angular/fire/firestore) which declares AngularFirestore has not been processed correctly by ngcc, or is not compatible with Angular Ivy. Check if a newer version of the library is available, and update if so. Also consider checking with the library's authors to see if the library is expected to be compatible with Ivy.