Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Error while serving universal app #1797

Closed
kartikwatwani opened this issue May 18, 2019 · 26 comments
Closed

Error while serving universal app #1797

kartikwatwani opened this issue May 18, 2019 · 26 comments

Comments

@kartikwatwani
Copy link

kartikwatwani commented May 18, 2019

[REQUIRED] Describe your environment

  • Operating System version:Windows 10
  • Firebase SDK version: 6.0.2

[REQUIRED] Describe the problem

I followed this tutorial for creating server side rendered app. There were other errors as well before I stumbled upon this error but they already had solutions. This error occurs when I try to serve the app using npm run serve:ssr.

The error I get is:

proxyRequestMethods(Index, '_index', IDBIndex, [
                                     ^

ReferenceError: IDBIndex is not defined
    at Module.<anonymous> (C:\Users\eg\dist\server.js:343794:38)
    at __webpack_require__ (C:\Users\eg\dist\server.js:30:30)
    at Module.<anonymous> (C:\Users\eg\dist\server.js:342436:61)
    at __webpack_require__ (C:\Users\eg\dist\server.js:30:30)
    at Module.<anonymous> (C:\Users\eg\dist\server.js:341227:81)
    at __webpack_require__ (C:\Users\eg\dist\server.js:30:30)
    at Module.<anonymous> (C:\Users\eg\dist\server.js:332069:79)
    at __webpack_require__ (C:\Users\eg\dist\server.js:30:30)
    at Object.firebase (C:\Users\eg\dist\server.js:189647:18)
    at __webpack_require__ (C:\Users\eg\dist\server.js:137349:30)

Before this I was receiving an error window is not defined so I added the below code in server.ts as mentioned in one of other issues in @angular/universal package, this comment

const domino = require('domino');
const fs = require('fs');
const path = require('path');
const template = fs.readFileSync(path.join(__dirname, '.', 'dist', 'index.html')).toString();
const win = domino.createWindow(template);
global['window'] = win;
global['document'] = win.document;

When I build ssr app using npm run build:ssr, I receive warnings shown below

WARNING in ./node_modules/@angular/fire/firestore/firestore.js 23:21-32
"export 'SDK_VERSION' was not found in 'firebase/app'
 @ ./node_modules/@angular/fire/firestore/public_api.js
 @ ./node_modules/@angular/fire/firestore/index.js
 @ ./dist/server/main.js
 @ ./server.ts

WARNING in ./node_modules/@angular/fire/firestore/firestore.js 24:21-32
"export 'SDK_VERSION' was not found in 'firebase/app'
 @ ./node_modules/@angular/fire/firestore/public_api.js
 @ ./node_modules/@angular/fire/firestore/index.js
 @ ./dist/server/main.js
 @ ./server.ts

Also when I serve(d) app using npm run serve:ssr while I receive these warnings when I used firebase@5.x.x I received error reference: self is not defined after updating to firebase@6.0.2 I receive error

var major = parseInt(firebase_app__WEBPACK_IMPORTED_MODULE_6__["SDK_VERSION"].split('.')[0]);
TypeError: Cannot read property 'split' of undefined
    at Module.<anonymous> (C:\Users\eg\dist\server.js:279474:79)
    at __webpack_require__ (C:\Users\eg\dist\server.js:30:30)
    at Module.<anonymous> (C:\Users\eg\dist\server.js:279385:68)
    at __webpack_require__ (C:\Users\eg\dist\server.js:30:30)
    at Module.<anonymous> (C:\Users\eg\dist\server.js:279341:69)
    at __webpack_require__ (C:\Users\eg\dist\server.js:30:30)
    at Object.@angular/fire/firestore (C:\Users\eg\dist\server.js:189255:18)
    at __webpack_require__ (C:\Users\eg\dist\server.js:137353:30)
    at Object../src/app/services/global-manager.service.ts (C:\Users\eg\dist\server.js:186535:19)
    at __webpack_require__ (C:\Users\eg\dist\server.js:137353:30)

I remove these warnings and errors by updating webpack.server.config.js by adding lines below

  const regex = /firebase\/(app|firestore)/;
module.exports={
externals: [/node_modules/, function(context, request, callback) {

    // exclude firebase products from being bundled, so they will be loaded using require() at runtime.
    if(regex.test(request)) {
      return callback(null, 'commonjs ' + request);
    }
    callback();
  }],
...
}

I also found out this stackoverflow question related to this error but I don't use performance module so solution is not applicable to me.

Steps to reproduce:

  1. Follow the fireship tutorial to use server side rendering
  2. If errors occurs like shown above, use the respective solution until you stumble upon IDBIndex error

How can I solve this IDBIndex error ? Please help

@google-oss-bot
Copy link
Contributor

I couldn't figure out how to label this issue, so I've labeled it for a human to triage. Hang tight.

@hsubox76
Copy link
Contributor

Take a look at this reply here: #1754 (comment)

The problem seems to be that your bundler is pulling in an esm build which is meant for browser use and not Node, because of the issues outlined in that comment. That reply contains a workaround you can use while waiting for a potential future fix in @angular/fire.

@tarunm007
Copy link

hi @hsubox76 the referred comments has fixed warning only. But the error of IDBIndex ReferenceError: IDBIndex is not defined is still coming.

@hsubox76
Copy link
Contributor

@tarunm007: I reproduced the original bug using the tutorial @itsmeneartou linked, and changing the resolve.alias field in package.json solved all the problems for me. Do you have a different setup? Is it possible for you to push your setup to Github or a minimal reproduction of it that still causes the bug? It's hard to figure out exactly what combination of configs and packages results in the IDBIndex bug and none of the combinations I've tried have done it.

@tarunm007
Copy link

Hi @hsubox76 @Feiyang1
I have committed a test project in git. This is using latest firebase sdk 6.0.2.

  1. Install firebase before starting: npm install --save firebase
  2. Also add firebase config object in environment/environment.ts and environment/environment.prod.ts
    Like:
    var firebaseConfig = {
    apiKey: "api-key",
    authDomain: "project-id.firebaseapp.com",
    databaseURL: "https://project-id.firebaseio.com",
    projectId: "project-id",
    storageBucket: "project-id.appspot.com",
    messagingSenderId: "sender-id",
    appID: "app-id",
    };

While running npm run serve:ssr as mentioned in https://angular.io/guide/universal, it throws :

> ng-test-ssr@0.0.0 serve:ssr C:\Tarun\Project\ng-test-ssr
> node dist/server

C:\Tarun\Project\ng-test-ssr\dist\server.js:195343
proxyRequestMethods(Index, '_index', IDBIndex, [
                                     ^

ReferenceError: IDBIndex is not defined
    at Module.<anonymous> (C:\Tarun\Project\ng-test-ssr\dist\server.js:195343:38)
    at __webpack_require__ (C:\Tarun\Project\ng-test-ssr\dist\server.js:20:30)
    at Module.<anonymous> (C:\Tarun\Project\ng-test-ssr\dist\server.js:193985:61)
    at __webpack_require__ (C:\Tarun\Project\ng-test-ssr\dist\server.js:20:30)
    at Module.<anonymous> (C:\Tarun\Project\ng-test-ssr\dist\server.js:192777:81)
    at __webpack_require__ (C:\Tarun\Project\ng-test-ssr\dist\server.js:20:30)
    at Module.<anonymous> (C:\Tarun\Project\ng-test-ssr\dist\server.js:146203:79)
    at __webpack_require__ (C:\Tarun\Project\ng-test-ssr\dist\server.js:20:30)
    at Object.firebase (C:\Tarun\Project\ng-test-ssr\dist\server.js:133515:18)
    at __webpack_require__ (C:\Tarun\Project\ng-test-ssr\dist\server.js:132835:30)
npm ERR! code ELIFECYCLE
npm ERR! errno 1
npm ERR! ng-test-ssr@0.0.0 serve:ssr: `node dist/server`
npm ERR! Exit status 1
npm ERR!
npm ERR! Failed at the ng-test-ssr@0.0.0 serve:ssr script.
npm ERR! This is probably not a problem with npm. There is likely additional logging output above.

npm ERR! A complete log of this run can be found in:

Let me know if you need any more info

@raberana
Copy link

raberana commented May 27, 2019

Also experiencing this issue even after following @Feiyang1 suggested solution.
To clarify, I only face the IndexedDB issue

@apunjaval
Copy link

Code that is throwing the error in server.js is "module.exports = webpack_require(405);"

// "firebase":
/!!
! external "firebase" !
**/
/! no static exports found /
// (function(module, exports) {

module.exports = webpack_require(405);

/***/ }),

// "firebase/app":
/!!
! external "firebase/app" !
/
/! no static exports found /
/
/ (function(module, exports) {

module.exports = webpack_require(420);

/***/ }),

// "firebase/auth":
/!****************************!
! external "firebase/auth" !
**************************/
/! no static exports found /
// (function(module, exports) {

@hsubox76
Copy link
Contributor

hsubox76 commented Jun 4, 2019

@tarunm007 Thanks so much for the repro. It was really helpful.

So the basic problem for you and I think for everyone facing IDBIndex is not defined errors is still, as mentioned earlier, that webpack is grabbing Firebase's browser (esm) bundle and not the Node bundle.

In your repo, you import firebase differently in different files.

In src/app/app.components.ts it's import * as firebase from 'firebase'

In src/app/auth/auth.service.ts it's import * as firebase from 'firebase/app'

So when applying the fix @Feiyang1 suggested in webpack.server.config.js:

  resolve: {  
    alias: {
	    ['firebase/app']: path.resolve(__dirname, 'node_modules/firebase/app/dist/index.cjs.js')
  },extensions: ['.ts', '.js'] },

You'll notice the alias only applies to any time you try to import from firebase/app. That means it won't apply to import statements from firebase. That's probably why it fixed some errors but not others. It'll be fixed if you either change the import to be from firebase/app or you add an additional alias entry:

  resolve: {  
    alias: {
	    ['firebase/app']: path.resolve(__dirname, 'node_modules/firebase/app/dist/index.cjs.js'),
	    ['firebase']: path.resolve(__dirname, 'node_modules/firebase/dist/index.node.cjs.js')
  },extensions: ['.ts', '.js'] },

I would probably pick one or the other, but if going with firebase/app, you may also have to set up aliases for other imports, such as firebase/firestore etc.

Let's call that Option 1.

Option 2 would be to tell Webpack to always pick the bundle specified in the "main" field of a library's package.json, which in the Firebase library, will always point to a Node-compatible bundle. You would do this by:

  resolve: {  
    mainFields: ['main', 'module', 'browser']
  },

And there's no need to keep track of every file you plan to import and find its path in node_modules/.

The downside is that this will apply to all of your dependencies, and other libraries may not have the same convention. They might not specify a main bundle or it might not point to the one you want.

Option 3 would be to tell Webpack to not bundle Firebase modules at all, but to directly bring them in with a Node require. For more on this solution see this comment: #1455 (comment) . You can change the regex there to include anything that begins with firebase if you want to apply it to all firebase packages.

This should ensure all the Firebase packages come in as Node (CommonJS) without breaking your non-Firebase dependencies, as well as any packages the Firebase code itself imports. It can be a little hard to read though.

Hope one of those options works for you (and others in this thread)!

@tarunm007
Copy link

@hsubox76 Thanks a lot. I had understood the problem but didn't got the solution which @Feiyang1 provided. Now I understood the solution also.
Thanks for all the options.

For my test repo, option1 works very well.

However I had used option3 in my project with change in regex to accommodate all the cases:

const regex = /firebase(\/([\w\d]+))*/;

@Feiyang1 Feiyang1 closed this as completed Jun 4, 2019
@raberana
Copy link

raberana commented Jun 5, 2019

hi @hsubox76, thanks for the explanation. is this a workaround only or we should still expect a proper fix?
and is the fix mentioned here by @Feiyang1 should have fixed these issues as well?

@Feiyang1
Copy link
Member

Feiyang1 commented Jun 5, 2019

@raberana It's a workaround till we change firebase packaging to disambiguate between nodejs build and browser build for bundlers. We are still investigating what the best way is. And since it's probably going to be a breaking change, we will need to align it with a major release, so it could take some time.

No, the linked fix only fix the SSR issue if you only use firebase products that don't have a special nodejs build. If you use firestore which has a different build for Nodejs, you need the workaround mentioned in this thread.

@stot3
Copy link

stot3 commented Jul 18, 2019

Hey I'm still experiencing this issue, after trying method 1, 2, and three. After using option 1, packages within the AngularFire directories started to break, as it seemed as though the AngularFire libraries were trying to pull in the node versions of firebase. Then option 2, gave me a /package.json could not be found error, then option three, still does not solve the IDBindex error. I am not even entirely sure how this error still persists. Regular, ng serve, works well. It's only when I am ng serve:ssr, from the ssr build. I am not quite sure what to do, because the workarounds are not working, affecting all 6.x versions. I have also trashed the node_modules and package-lock.json

@hsubox76
Copy link
Contributor

For option 3, did you use the regex as is, or did you modify it to include all the Firebase components you are using? IndexedDB is used by more components than just firebase/app and firebase/firestore, including auth, performance, and messaging. If you are using one of those and did not include it in the regex, perhaps that might be causing the error?

@stot3
Copy link

stot3 commented Jul 18, 2019

I used this one:

const regex = /firebase(/([\w\d]+))*/;

@stot3
Copy link

stot3 commented Jul 18, 2019

When I use option three, I get this error message:

Error: Cannot find module './firebase.app.module'
at Function.Module._resolveFilename (internal/modules/cjs/loader.js:636:15)
at Function.Module._load (internal/modules/cjs/loader.js:562:25)
at Module.require (internal/modules/cjs/loader.js:690:17)
at require (internal/modules/cjs/helpers.js:25:18)
at Object. (/Users/jeremysistrunk/Documents/Houston2/dist/server.js:185906:18)
at webpack_require (/Users/jeremysistrunk/Documents/Houston2/dist/server.js:20:30)
at Module. (/Users/jeremysistrunk/Documents/Houston2/dist/server.js:185813:78)
at webpack_require (/Users/jeremysistrunk/Documents/Houston2/dist/server.js:20:30)
at Module. (/Users/jeremysistrunk/Documents/Houston2/dist/server.js:185793:69)
at webpack_require (/Users/jeremysistrunk/Documents/Houston2/dist/server.js:20:30)

@stot3
Copy link

stot3 commented Jul 18, 2019

`// Work around for angular/angular-cli#7200
const path = require('path');
const webpack = require('webpack');

const regex = /firebase(/([\w\d]+))*/;

module.exports = {
mode: 'none',
entry: {
// This is our Express server for Dynamic universal
server: './server.ts'
},
target: 'node',
resolve: {
extensions: ['.ts', '.js'],
alias: {
['firebase/app']: path.resolve(__dirname, 'node_modules/firebase/app/dist/index.cjs.js'),
['firebase/auth']: path.resolve(__dirname, 'node_modules/firebase/auth/dist/index.cjs.js'),
['firebase/storage']: path.resolve(__dirname, 'node_modules/firebase/storage/dist/index.cjs.js'),
['firebase/firestore']: path.resolve(__dirname, 'node_modules/firebase/firestore/dist/index.cjs.js')
}
},
externals: [/node_modules/, function(context, request, callback) {

// exclude firebase products from being bundled, so they will be loaded using require() at runtime.
if(regex.test(request)) {
  return callback(null, 'commonjs ' + request);
}
callback();

}],
optimization: {
minimize: false
},
output: {
// Puts the output at the root of the dist folder
path: path.join(__dirname, 'dist'),
filename: '[name].js'
},
module: {
rules: [
{ test: /.ts$/, loader: 'ts-loader' },
{
// Mark files inside @angular/core as using SystemJS style dynamic imports.
// Removing this will cause deprecation warnings to appear.
test: /(\|/)@angular(\|/)core(\|/).+.js$/,
parser: { system: true },
},
]
},
plugins: [
new webpack.ContextReplacementPlugin(
// fixes WARNING Critical dependency: the request of a dependency is an expression
/(.+)?angular(\|/)core(.+)?/,
path.join(__dirname, 'src'), // location of your src
{} // a map of your routes
),
new webpack.ContextReplacementPlugin(
// fixes WARNING Critical dependency: the request of a dependency is an expression
/(.+)?express(\|/)(.+)?/,
path.join(__dirname, 'src'),
{}
)
]
};
`

@hsubox76
Copy link
Contributor

I think it may be that your regular expression is too broad and you are excluding your own Angular module (which seems to be named firebase.app.module?) from being compiled. Perhaps you can add a ^ to the beginning of the regex to ensure it only applies if the absolute path begins with firebase, or something else to separate firebase imports from your own files?

@stot3
Copy link

stot3 commented Jul 19, 2019 via email

@hbk899
Copy link

hbk899 commented Jul 20, 2019

@tarunm007 Thanks so much for the repro. It was really helpful.

So the basic problem for you and I think for everyone facing IDBIndex is not defined errors is still, as mentioned earlier, that webpack is grabbing Firebase's browser (esm) bundle and not the Node bundle.

In your repo, you import firebase differently in different files.

In src/app/app.components.ts it's import * as firebase from 'firebase'

In src/app/auth/auth.service.ts it's import * as firebase from 'firebase/app'

So when applying the fix @Feiyang1 suggested in webpack.server.config.js:

  resolve: {  
    alias: {
	    ['firebase/app']: path.resolve(__dirname, 'node_modules/firebase/app/dist/index.cjs.js')
  },extensions: ['.ts', '.js'] },

You'll notice the alias only applies to any time you try to import from firebase/app. That means it won't apply to import statements from firebase. That's probably why it fixed some errors but not others. It'll be fixed if you either change the import to be from firebase/app or you add an additional alias entry:

  resolve: {  
    alias: {
	    ['firebase/app']: path.resolve(__dirname, 'node_modules/firebase/app/dist/index.cjs.js'),
	    ['firebase']: path.resolve(__dirname, 'node_modules/firebase/dist/index.node.cjs.js')
  },extensions: ['.ts', '.js'] },

I would probably pick one or the other, but if going with firebase/app, you may also have to set up aliases for other imports, such as firebase/firestore etc.

Let's call that Option 1.

Option 2 would be to tell Webpack to always pick the bundle specified in the "main" field of a library's package.json, which in the Firebase library, will always point to a Node-compatible bundle. You would do this by:

  resolve: {  
    mainFields: ['main', 'module', 'browser']
  },

And there's no need to keep track of every file you plan to import and find its path in node_modules/.

The downside is that this will apply to all of your dependencies, and other libraries may not have the same convention. They might not specify a main bundle or it might not point to the one you want.

Option 3 would be to tell Webpack to not bundle Firebase modules at all, but to directly bring them in with a Node require. For more on this solution see this comment: #1455 (comment) . You can change the regex there to include anything that begins with firebase if you want to apply it to all firebase packages.

This should ensure all the Firebase packages come in as Node (CommonJS) without breaking your non-Firebase dependencies, as well as any packages the Firebase code itself imports. It can be a little hard to read though.

Hope one of those options works for you (and others in this thread)!

Adding the caret, did the trick, I modified the regex to look like this. const regex = /^firebase(/([\w\d]+))/;

On Jul 18, 2019, at 4:34 PM, Christina Holland @.
**> wrote: I think it may be that your regular expression is too broad and you are excluding your own Angular module (which seems to be named firebase.app.module?) from being compiled. Perhaps you can add a ^ to the beginning of the regex to ensure it only applies if the absolute path begins with firebase, or something else to separate firebase imports from your own files? — You are receiving this because you commented. Reply to this email directly, view it on GitHub <#1797?email_source=notifications&email_token=ACBPZGLD5PULCUKGYZDPBC3QADHUPA5CNFSM4HNZQQM2YY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOD2JWNCQ#issuecomment-512976522>, or mute the thread https://github.com/notifications/unsubscribe-auth/ACBPZGLVLEJ3UIFKG7SNJ4TQADHUPANCNFSM4HNZQQMQ.

Didnt you got windows error after solving this regex problem

@stot3
Copy link

stot3 commented Aug 1, 2019

Although the workaround is working for the moment, because of the two different references, firebase performance does not launch on the @firebase package, this is the error message:

FirebaseError: Performance: Performance can only start when Firebase app instance is the default one. (performance/FB not default), what can we do about this? I'd like to use the firebase performance module as well.

@Feiyang1
Copy link
Member

Feiyang1 commented Aug 1, 2019

@stot3 Only one Performance instance is allowed in a web app, and we only allow creating one from the default FirebaseApp instance.

The default FirebaseApp instance is created when you can initializeApp() without a name. It appears the one you are using is named performance/FB, so it's not the default one.

So to summarize, You need to instantiate Performance from the default FirebaseApp.

@raythurnvoid
Copy link

I had a similar problem using firebase.auth.EmailAuthProvider.credential in React SSR.

If you are able to use es2017 dynamic import with webpack you can avoid this problem like this:

// on top of you application
import * as firebase from 'firebase/app'; // this will include firebase in the main bundle
import 'firebase/auth';

// in React component
const firebase = await import('firebase'); // this will avoid the problem and it won't download a separate file because it is already included in the main bundle
let credential = firebase.auth.EmailAuthProvider.credential('email', 'password');

The firebase library will be avaiable

@erikjalevik
Copy link

Following the excellent instructions by hsubox76 fixes the IDBIndex error in my Electron app, but as soon as I try to do a send to the firestore database, I run into the next error:

ReferenceError: XMLHttpRequest is not defined
  at .../node_modules/@firebase/webchannel-wrapper/dist/index.esm.js.g.ca

Which again looks like it's using a browser API that is not available.

@hsubox76
Copy link
Contributor

Which option did you choose? If 1 or 3, you have to expand the list of aliases or the regex, respectively, to include all Firebase components you are using (in this case the list or regex must include firebase/firestore).

@erikjalevik
Copy link

I used option 1. And I only added an alias for "firebase" since that's the only file I actually import in my code. However, it seemed as if any require from firebase's index.node.cjs.js file resolved back to an esm version.

In the end, I just switched to using firebase from the Electron renderer thread instead, where the esm version works without problems.

@AAverin
Copy link

AAverin commented Sep 16, 2019

For documentation purposes, here is a thread solving this problem in GatsbyJS:
gatsbyjs/gatsby#10457

@firebase firebase locked and limited conversation to collaborators Oct 11, 2019
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests