4
votes

I have continuously had this problem while trying to deploy. I was able to deploy once initially while there was only the starter 'hello, world' cloud function to firebase.

I have Node 8 installed, and I realized this may be my problem. I did a search about it and found that it is ok as long as you specify the engine eg:

package.json snippet

 "engines": {
    "node": "8"
  },

but after I adding this I have the same result.

Here is my full package.json

{
  "name": "functions",
  "description": "Cloud Functions for Firebase",
  "scripts": {
    "serve": "firebase serve --only functions",
    "shell": "firebase functions:shell",
    "start": "npm run shell",
    "deploy": "firebase deploy --only functions",
    "logs": "firebase functions:log"
  },
  "dependencies": {
    "@google-cloud/storage": "^2.0.3",
    "busboy": "^0.2.14",
    "cors": "^2.8.4",
    "firebase-admin": "^6.0.0",
    "firebase-functions": "^2.0.5",
    "request-promise": "^4.2.2",
    "uuid": "^3.3.2"
  },
  "engines": {
    "node": "8"
  },
  "private": true
}

and here is my index.js in my functions folder

'use strict';
// // Create and Deploy Your First Cloud Functions
// // https://firebase.google.com/docs/functions/write-firebase-functions
//

const functions = require('firebase-functions');
const cors = require('cors')({ origin: true });
const Busboy = require('busboy');
const os = require('os');
const path = require('path');
const fs = require('fs');
const fbAdmin = require('firebase-admin');
const uuid = require('uuid/v4');

// exports.helloWorld = functions.https.onRequest((request, response) => {
//  response.send("Hello from Firebase!");
// });
const gcconfig = {
  projectId: 'rs-0001',
  keyFilename: 'rs-0001.json'
};

const gcs = require('@google-cloud/storage')(gcconfig);

// exports.helloWorld = functions.https.onRequest((request, response) => {
//     response.send("Hello from Firebase!");
//    });

   
fbAdmin.initializeApp({
  credential: fbAdmin.credential.cert(require('./rs-0001.json'))
});

exports.storeImage = functions.https.onRequest((req, res) => {
  return cors(req, res, () => {
    if (req.method !== 'POST') {
      return res.status(500).json({ message: 'Not allowed.' });
    }

    if (
      !req.headers.authorization ||
      !req.headers.authorization.startsWith('Bearer ')
    ) {
      return res.status(401).json({ error: 'Unauthorized.' });
    }

    let idToken;
    idToken = req.headers.authorization.split('Bearer ')[1];

    const busboy = new Busboy({ headers: req.headers });
    let uploadData;
    let oldImagePath;

    busboy.on('file', (fieldname, file, filename, encoding, mimetype) => {
      const filePath = path.join(os.tmpdir(), filename);
      uploadData = { filePath: filePath, type: mimetype, name: filename };
      file.pipe(fs.createWriteStream(filePath));
    });

    busboy.on('field', (fieldname, value) => {
      oldImagePath = decodeURIComponent(value);
    });

    busboy.on('finish', () => {
      const bucket = gcs.bucket('rs-0001.appspot.com');
      const id = uuid();
      let imagePath = 'images/' + id + '-' + uploadData.name;
      if (oldImagePath) {
        imagePath = oldImagePath;
      }

      return fbAdmin
        .auth()
        .verifyIdToken(idToken)
        .then(decodedToken => {
          return bucket.upload(uploadData.filePath, {
            uploadType: 'media',
            destination: imagePath,
            metadata: {
              metadata: {
                contentType: uploadData.type,
                firebaseStorageDownloadTokens: id
              }
            }
          });
        })
        .then(() => {
          return res.status(201).json({
            imageUrl:
              'https://firebasestorage.googleapis.com/v0/b/' +
              bucket.name +
              '/o/' +
              encodeURIComponent(imagePath) +
              '?alt=media&token=' +
              id,
            imagePath: imagePath
          });

          return null
        })
        .catch(error => {
          return res.status(401).json({ error: 'Unauthorized!' });
        });
    });
    return busboy.end(req.rawBody);
  });
});

I have used prior suggestions to similar issues suggesting to go to the /functions/ directory and doing an npm install, then proceeding to go to the previous directory and run

firebase deploy --only functions

which takes me back to

i  functions: preparing functions directory for uploading...

Error: Error parsing triggers: Cannot find module 'firebase-functions'

Try running "npm install" in your functions directory before deploying.

I have ran it with the --debug on, to receive

i  functions: preparing functions directory for uploading...
[2018-10-04T15:34:29.744Z] >>> HTTP REQUEST GET https://runtimeconfig.googleapis.com/v1beta1/projects/rs-0001/configs

[2018-10-04T15:34:31.249Z] <<< HTTP RESPONSE 200 content-type=application/json; charset=UTF-8,vary=X-Origin, Referer, Origin,Accept-Encoding, date=Thu, 04 Oct 2018 15:34:31 GMT, server=ESF, cache-control=private, x-xss-protection=1; mode=block, x-frame-options=SAMEORIGIN, x-content-type-options=nosniff, alt-svc=quic=":443"; ma=2592000; v="44,43,39,35", accept-ranges=none, connection=close

Error: Error parsing triggers: Cannot find module 'firebase-functions'

Try running "npm install" in your functions directory before deploying.

I have even tried

 cd functions && sudo npm i && cd .. && firebase deploy --only functions --debug

to come with the same result. I have spent hours seemingly with the same problem, deleted node_modules, installed all packages individually, etc. Can someone help?

node -v

v8.12.0

npm -v

6.4.1

and I installed firebase-tools globally at the latest version, and have the .json for the project in the same directory...

2
FYI: you don't have to change out of the functions folder to run firebase CLI comments. The CLI will look up to parent folders to find the root of the project.Doug Stevenson
What happens if you create a new project from scratch and copy your code into it and work from there?Doug Stevenson
shre your package.jsonSushant Somani

2 Answers

1
votes

There was an incompatible package.

    "@google-cloud/storage": "^2.0.3",

needed to be

    "@google-cloud/storage": "^1.7.0",

for some reason, after this I was able to upload. Here is the working version of my functions/index.js

    'use strict';

const functions = require('firebase-functions');
const cors = require('cors')({origin: true});
const Busboy = require('busboy');
const os = require('os');
const path = require('path');
const fs = require('fs');
const fbAdmin = require('firebase-admin');
const uuid = require('uuid/v4');
// // Create and Deploy Your First Cloud Functions
// // https://firebase.google.com/docs/functions/write-firebase-functions
//
// exports.helloWorld = functions.https.onRequest((request, response) => {
//  response.send("Hello from Firebase!");
// });
const gcconfig = {
    projectId: 'rs-0001',
    keyFilename: 'rs-0001.json'
};

const gcs = require('@google-cloud/storage')(gcconfig);

fbAdmin.initializeApp({credential: fbAdmin.credential.cert(require('./rs-0001.json'))})

exports.storeImage = functions.https.onRequest((request, response) => {
    return cors(req, res, () => {
        if (req.method !== 'POST') {
            return res.status(500).json({message: 'Not allowed mofo.' });
        }
    if (!req.headers.authorization ||
        !req.headers.authorization.startsWith('Bearer ')
        ) { 
        return res.status(401).json({ error: 'Unauthorized '});
    }

    let idToken;
    idToken = req.headers.authorization.split('Bearer ')[1];

    const busboy = new Busboy({headers: req.headers});
    let uploadData;

    busboy.on('file', (fieldname, file, filename, encoding, mimetype) => {
        const filePath = path.join(os.tmpdir(), filename);
        uploadData = {filePath: filePath, type: mimetype, name: filename};
        file.pipe(fs.createWriteStream(filePath));
    });

    busboy.on('field', (fieldname, value) => {
        oldImagePath = decodeURIComponent(value);
    })

    busboy.on('finish', () => {
        const bucket = gcs.bucket('rs-0001.appspot.com');
        const id = uuid();
        let imagePath = 'images/' + id + '-' + uploadData.name
        if (oldImagePath) {
            imagePath = oldImagePath;

        }

        return fbAdmin
        .auth()
        .verufyIdToken(idToken)
        .then(decodedToken => {
            return bucket.upload(uploadData.filePath, {
                uploadType: 'media',
                destination: imagePath,
                metadata: {
                    metadata: {
                        contentType: uploadData.type,
                        firebaseStorageDownloadToken: id
                    }
                }
            });
        })
        .then(() => {
            return res.status(201).json({
                imageUrl: 
                    'https://firebasestorage.googleapis.com/v0/b/' + 
                    bucket.name + 
                    '/o/' + 
                    encodeURIComponent(imagePath) + 
                    '?alt=media&token' + 
                    id,
                imagePath: imagePath
            });
        })
        .catch(error => {
            return res.status(401).json({ error: 'Unauthorized!' });
        });
    });
    return busboy.end(req.rawBody);
    });
});

and here is my full package.json now,

{
  "name": "functions",
  "description": "Cloud Functions for Firebase",
  "scripts": {
    "serve": "firebase serve --only functions",
    "shell": "firebase functions:shell",
    "start": "npm run shell",
    "deploy": "firebase deploy --only functions",
    "logs": "firebase functions:log"
  },
  "dependencies": {
    "@google-cloud/common": "^0.25.3",
    "@google-cloud/paginator": "^0.1.1",
    "@google-cloud/storage": "^1.7.0",
    "busboy": "^0.2.14",
    "cors": "^2.8.4",
    "firebase": "^5.5.3",
    "firebase-admin": "^6.0.0",
    "firebase-functions": "^2.0.5",
    "gcs-resumable-upload": "^0.13.0",
    "split-array-stream": "^2.0.0",
    "uuid": "^3.3.2"
  },
  "private": true
}

thanks all for your answers. I hope my solution can help someone

0
votes

Try this.

  1. Run this code locally using either

    • firebase functions:shell or
    • firebase serve --only functions

    See this for more details.

  2. Look for detailed stack trace in firebase-debug.log file that will be generated in you directory.