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

ES2017 - import fails: Cannot read property "config" of undefined #202

Closed
sokraflex opened this issue Mar 14, 2018 · 3 comments
Closed

ES2017 - import fails: Cannot read property "config" of undefined #202

sokraflex opened this issue Mar 14, 2018 · 3 comments

Comments

@sokraflex
Copy link

Version info

firebase-functions: 0.8.2

firebase-tools: 3.17.6

firebase-admin: 5.8.2

node -v: 6.9.5

npm -v: 5.0.3

Test case

I've tried to use simple import-statements, compile the file using babel-cli and deploy the compiled code to firebase.

For readability, I'll provide you with the uncompiled and compiled source code. I am very certain that this is not an issue with babel-cli, as e.g. the import statement from firebase-admin works and I also did not encounter any issues with other projects and a similar setup of babel.

Nevertheless, I am new to firebase and it could be an issue on my side. If there are any more information you need/would like to have, please let me know.

index.src.js

import admin from 'firebase-admin';
import functions from 'firebase-functions';
admin.initializeApp(functions.config().firebase);

.babelrc

{
	"presets": ["env"]
}

index.js

'use strict';

var _firebaseAdmin = require('firebase-admin');

var _firebaseAdmin2 = _interopRequireDefault(_firebaseAdmin);

var _firebaseFunctions = require('firebase-functions');

var _firebaseFunctions2 = _interopRequireDefault(_firebaseFunctions);

function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }

_firebaseAdmin2.default.initializeApp(_firebaseFunctions2.default.config().firebase);

Result:

"TypeError: Cannot read property 'config' of undefined"

Steps to reproduce

Either:

a) Use the above index.js for your functions and deploy it, or
b) Use the above .babelrc and the index.src.js to generate index.js and deploy it.

Were you able to successfully deploy your functions?

I received the error message:

TypeError: Cannot read property 'config' of undefined
    at Object.<anonymous> (index.js:13:66)

Expected behavior

I would expect that the deployment succeeds without any error message. The deployed service would have 0 functions, but the deploy itself should succeed.

Actual behavior

Instead of suceeding, the deployment fails because functions is undefined instead of
containing the exports from the firebase-functions module. On the other hand, the same import-statement works fine with the firebase-admin module - and i did not encounter similar issues so far with other modules.

The firebase-debug.log:

[debug] [2018-03-14T17:44:17.451Z] ----------------------------------------------------------------------
[debug] [2018-03-14T17:44:17.467Z] Command:       C:\Program Files\nodejs\node.exe C:\Users\Username\AppData\Roaming\npm\node_modules\firebase-tools\bin\firebase deploy --only functions
[debug] [2018-03-14T17:44:17.467Z] CLI Version:   3.17.6
[debug] [2018-03-14T17:44:17.467Z] Platform:      win32
[debug] [2018-03-14T17:44:17.467Z] Node Version:  v6.9.5
[debug] [2018-03-14T17:44:17.467Z] Time:          Wed Mar 14 2018
[debug] [2018-03-14T17:44:17.467Z] ----------------------------------------------------------------------
[debug] 
[debug] [2018-03-14T17:44:17.513Z] > command requires scopes: ["email","openid","https://www.googleapis.com/auth/cloudplatformprojects.readonly","https://www.googleapis.com/auth/firebase","https://www.googleapis.com/auth/cloud-platform"]
[debug] [2018-03-14T17:44:17.529Z] > authorizing via signed-in user
[debug] [2018-03-14T17:44:17.529Z] >>> HTTP REQUEST GET https://admin.firebase.com/v1/projects/my-project  
  
 Wed Mar 14 2018
[debug] [2018-03-14T17:44:18.092Z] <<< HTTP RESPONSE 200
[debug] [2018-03-14T17:44:18.092Z] >>> HTTP REQUEST GET https://admin.firebase.com/v1/database/my-project/tokens  
  
 Wed Mar 14 2018
[debug] [2018-03-14T17:44:18.467Z] <<< HTTP RESPONSE 200
[info] 
[info] === Deploying to 'my-project'...
[info] 
[info] i  deploying functions
[info] Running command: npm --prefix "$RESOURCE_DIR" run lint
[info] +  functions: Finished running predeploy script.
[debug] [2018-03-14T17:44:27.123Z] > [functions] package.json contents: {
  "name": "functions",
  "description": "Cloud Functions for my-project",
  "scripts": {
    "lint": "eslint .",
    "serve": "firebase serve --only functions",
    "shell": "firebase experimental:functions:shell",
    "start": "npm run shell",
    "deploy": "firebase deploy --only functions",
    "logs": "firebase functions:log",
    "build": "node node_modules/babel-cli/bin/babel.js src/ --out-dir ./"
  },
  "dependencies": {
    "firebase-admin": "^5.8.2",
    "firebase-functions": "^0.8.1"
  },
  "devDependencies": {
    "babel-cli": "^6.26.0",
    "babel-preset-env": "^1.6.1",
    "eslint": "^4.12.0",
    "eslint-plugin-promise": "^3.6.0"
  },
  "private": true
}
[info] i  functions: ensuring necessary APIs are enabled...
[debug] [2018-03-14T17:44:27.123Z] >>> HTTP REQUEST GET https://servicemanagement.googleapis.com/v1/services/cloudfunctions.googleapis.com/projectSettings/my-project?view=CONSUMER_VIEW  
  
 Wed Mar 14 2018
[debug] [2018-03-14T17:44:27.123Z] >>> HTTP REQUEST GET https://servicemanagement.googleapis.com/v1/services/runtimeconfig.googleapis.com/projectSettings/my-project?view=CONSUMER_VIEW  
  
 Wed Mar 14 2018
[debug] [2018-03-14T17:44:27.920Z] <<< HTTP RESPONSE 200
[debug] [2018-03-14T17:44:27.936Z] <<< HTTP RESPONSE 200
[info] +  functions: all necessary APIs are enabled
[debug] [2018-03-14T17:44:27.936Z] >>> HTTP REQUEST GET https://cloudresourcemanager.googleapis.com/v1/projects/my-project  
  
 Wed Mar 14 2018
[debug] [2018-03-14T17:44:28.422Z] <<< HTTP RESPONSE 200
[debug] [2018-03-14T17:44:28.422Z] >>> HTTP REQUEST GET https://mobilesdk-pa.googleapis.com/v1/projects/some-numeric-id:getServerAppConfig  
  
 Wed Mar 14 2018
[debug] [2018-03-14T17:44:28.912Z] <<< HTTP RESPONSE 200
[info] i  functions: preparing functions directory for uploading...
[debug] [2018-03-14T17:44:28.927Z] >>> HTTP REQUEST GET https://runtimeconfig.googleapis.com/v1beta1/projects/my-project/configs  
  
 Wed Mar 14 2018
[debug] [2018-03-14T17:44:29.406Z] <<< HTTP RESPONSE 200
@sokraflex
Copy link
Author

Okay, I've debugged a little bit further. The following source code also compiles and deploys successfully:

import admin from 'firebase-admin';
const functions = require('firebase-functions');
admin.initializeApp(functions.config().firebase);

I was capable to pinpoint the problem down to the ".default"-usage: If, in the compiled source code, the erroneous line (13) gets changed to the following:

_firebaseAdmin2.default.initializeApp(_firebaseFunctions2.config().firebase);

it seems to work. Therefore, the problem is that _firebaseFunctions2.default is undefined. Unfortunately, I have to stop at this point as I do not understand enough about how ES6-modules work internally, and what exactly the function _interopRequireDefault() is required for - and why it checks for obj.__esModule. Maybe someone with more knowledge to that could help me out?

At this point, I am unsure if this is a bug or a feature request - as most other modules seem to work with that kind of import structure, but firebase-functions doesnt. I never noticed that I had to do anything special on my own modules so that they work, so I am a little bit confused right now :D

@jhu7235
Copy link

jhu7235 commented Apr 13, 2018

@SargTeX
Hey, I ran into this problem while converting require to import/export.

In es6, there are different ways of importing. There are also different methods of exporting. When you export like this export { name1, name2, …, nameN };, it exports an object of key/value pairs. When you export like this export default expression;, I think it sets the key 'default' to the expression.

When you import like this import defaultExport from "module-name";, it reads the value at the default key. When you import like this import * as name from "module-name"; it'll read in all the key/value pairs.

config must not be the default export, that's why it didn't work. require must be catching both scenarios, that's why using require works.
My solution is:

import * as functions from 'firebase-functions'; // <-- solution

/* eslint-disable-next-line import/no-mutable-exports */
let config;
if (!functions || process.env.NODE_ENV === ('silent' || 'test')) {
  // handle local unit testing
  config = {};
} else {
  config = functions.config();
}

export default config;

update:
If you checkout the source code, you'll see that there is no default export.

@laurenzlong
Copy link
Contributor

laurenzlong commented Apr 21, 2018

Thanks for stepping in @jhu7235 !

You can also do import { config } from 'firebase-functions'
You can add other imports to that list, for example:
import {config, database, firestore} from 'firebase-functions'

MichaelJahns added a commit to MichaelJahns/namespace-backend that referenced this issue Jan 16, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants