0

When i use storage emulator, I have been struggling to connect download URLs to URLs that can be accessed by 3rd parties - image and video optimisation tools. Firebase Storage production url is https://firebasestorage.googleapis.com/...(accessible over the web) whereas local environment url is http://localhost:9199/...(inaccessible).

I tried a bunch of things make the URL accessible. I've resorted to creating another bucket on my production environment and then the auth, function, firestore and hosting is on the local emulator.

This works but i wonder, what are the risks to this?

Is there a better way?

Edit: Adding my json file as per comment.

{
  "firestore": {
    "rules": "firestore.rules",
    "indexes": "firestore.indexes.json"
  },
  "functions": [
    {
      "source": "functions",
      "codebase": "default",
      "ignore": [
        "node_modules",
        ".git",
        "firebase-debug.log",
        "firebase-debug.*.log"
      ],
      "predeploy": [
        "npm --prefix \"$RESOURCE_DIR\" run lint"
      ]
    }
  ],
  "hosting": {
    "public": "build",
    "ignore": [
      "firebase.json",
      "**/.*",
      "**/node_modules/**"
    ],
    "rewrites": [
      {
        "source": "**",
        "destination": "/index.html"
      }
    ]
  },
  "storage": {
    "rules": "storage.rules"
  },
  "emulators": {
    "auth": {
      "port": 9099
    },
    "firestore": {
      "port": 8080
    },
    "hosting": {
      "port": 5000
    },
    "storage": {
      "port": 9199
    },
    "ui": {
      "enabled": true,
      "port": 4000
    },
    "singleProjectMode": true,
    "functions": {
      "port": 5001
    }
  }
}
Coolkid
  • 407
  • 1
  • 4
  • 13
  • Can you also share your `firebase.json` file just to confirm that it is not the problem with configuration ? – Rohit Kharche Apr 14 '23 at 09:20
  • @RohitKharche, just added the json file. – Coolkid Apr 14 '23 at 09:31
  • It is possible that your port `9199` is occupied already if you are on linux then you can kill that port's process using `npx kill-port 9199` and it will also work on windows then you can try starting emulator again. – Rohit Kharche Apr 14 '23 at 09:47
  • After i stop local emulator servers and run the command, the process is killed the port and when i rerun the servers and visit ```localhost:9199```, i still get ```501 Not Implemented``` error. – Coolkid Apr 14 '23 at 10:11
  • The error you shared means that you haven't initialized the firebase storage emulator make sure you enable it from the client using [Instrument your app to talk to the emulators](https://firebase.google.com/docs/emulator-suite/connect_storage#instrument_your_app_to_talk_to_the_emulators) – Rohit Kharche Apr 14 '23 at 11:27
  • It has initialised. I can see images and download urls starting with ```localhost:9199``` in the storage emulator. There's a link in the question, to another question, where i've shown its initialised. – Coolkid Apr 14 '23 at 20:18
  • No I didn't mean that I mean you have ran `firebase emulators:start` command but are you accessing firebase storage emulators with client SDK with using `connectStorageEmulator` and making the request for it – Rohit Kharche Apr 15 '23 at 13:26
  • This is how it is now: ```if (hostname === "localhost") { connectAuthEmulator(auth, "http://localhost:9099"); connectFirestoreEmulator(db, "localhost", 8080); // connectStorageEmulator(storage, "localhost", 9199); connectFunctionsEmulator(functions, "localhost", 5001); }``` I have commented out ```localhost:9199``` now but when it was not commented out and emulator storage was connected, the error was still there. Just to be clear, when the emulator storage was connected, i was able to upload and download videos/images locally, external sites couldn't access it - that's the issue – Coolkid Apr 15 '23 at 17:30

1 Answers1

0

I think you are accessing firebase emulator from the node environment and not in the browser environment as hostname will only work if the environment is running in the browser and here location.hostname will also not work.

If you initialize without checking the condition for ''localhost'' you should get the results. Because if you have used typescript here you might have got error on hostname like

This comparison appears to be unintentional because the types '() => string' and 'string' have no overlap.
if(hostname === "localhost")
    

Instead of initializing the firebase emulators from the client like you did, I recommend you to use some env file and add one variable called NODE_ENV = ''development'' and initialize based on that condition as follows:

if(process.env.NODE_ENV === 'development') {
    connectAuthEmulator(auth, "http://localhost:9099");
    connectFirestoreEmulator(db, "localhost", 8080);
    connectDatabaseEmulator(database, "localhost", 9000);
    connectStorageEmulator(storage, "localhost", 9199);
    connectFunctionsEmulator(functions, "localhost", 5001);
}

OR just use a variable like const useEmulator: boolean = true; in your firebase initialization file and check against this value and when you want to connect to production firebase instance just make the value of useEmulator to false.

Update : Let's double check if you have followed these steps or not, if yes then try to give it a chance again.

  1. Create 1 node-project using npm init -y and configure typescript project as shown in here.
  2. Run firebase init and select existing project and provide project_id to the cli then select which features you want to use in this case select Storage: Configure a security rules file for Cloud Storage and Emulators: Set up local emulators for Firebase products then hit enter.
  3. Choose Storage emulator when firebase cli will ask for which emulators to choose. Hit Enter. You will get Would you like to download the emulators now?(Y/n) as a prompt, type Y then enter. Your emulators will get downloaded.
  4. Run npm install firebase to add firebase dependency to your project.
  5. Next create src folder and create firebase.ts file then add your firebase credentials as follows:
// Import the functions you need from the SDKs you need
import { initializeApp } from "firebase/app";
import { connectAuthEmulator, getAuth } from "firebase/auth";
import { connectDatabaseEmulator, getDatabase } from "firebase/database";
import { connectFirestoreEmulator, getFirestore } from "firebase/firestore";
import { connectFunctionsEmulator, getFunctions } from "firebase/functions";
import { connectStorageEmulator, getStorage } from "firebase/storage";

const firebaseConfig = { … };

const useEmulator: boolean = true;

// Initialize Firebase Services
const app = initializeApp(firebaseConfig);
const auth = getAuth(app);
const db = getFirestore(app);
const database = getDatabase(app);
const storage = getStorage(app);
const functions = getFunctions(app);

if(useEmulator) {
    connectAuthEmulator(auth, "http://localhost:9099");
    connectFirestoreEmulator(db, "localhost", 8080);
    connectDatabaseEmulator(database, "localhost", 9000);
    connectStorageEmulator(storage, "localhost", 9199);
    connectFunctionsEmulator(functions, "localhost", 5001);
} else console.log("If Block has been Skipped");
export { auth, db, database, storage, functions }
  1. Run firebase emulators:start to start the emulator it will spit out ui URL and configured emulator services urls. Go to the ui URL and upload an image to the storage emulator. You will get the url for that image like this : http://127.0.0.1:9199/v0/b/<project_id>.appspot.com/...
  2. This will ensure that your configuration is correct and there are no issues from the firebase side if any occurred then you can contact firebase support.

Reference : Instrument your app to talk to the emulators

Rohit Kharche
  • 2,541
  • 1
  • 2
  • 13
  • Sorry for the delay in response. How do i know if it actually works, should ```localhost:9199``` not give me the ```Not Implemented``` error? I have tried both options of setting ```useEmulator``` to ```true/false``` and the ```process.env.NODE_ENV="development"```, nothing has changed. – Coolkid Apr 17 '23 at 14:29
  • If you are using Firebase Emulator UI then you can see the Storage emulator running in the firebase emulator UI and on the terminal console where you have run `firebase emulators:start` will also spit out local URL to access the storage emulator. – Rohit Kharche Apr 18 '23 at 05:39
  • thanks for the clarity. The localhost has always been working. ```localhost:3000```, ```localhost:8080``` and ```localhost:9199```, they all work. When i upload an image to the emulator, i do get a ```localhost:9199``` url. The issue is external accessibility. An image address of ```http://localhost:9199/v0/b/default-bucket/...``` can't be accessed by outside websites. These websites help optimise and transform images, which i have to do locally before i do them in production. Please note, that while all this is happening, when i visit ```localhost:9199``` still ```Not Implemented``` – Coolkid Apr 18 '23 at 09:44
  • @Coolkid Have you tried with the `http://127.0.0.1:9199/v0/b/.appspot.com/...` assuming you have configured the project `.firebaserc` having structure as follows: ```{ "projects": { "default": "" } }``` – Rohit Kharche Apr 21 '23 at 05:55
  • Hi @Rohit, yes i have tried that. – Coolkid Apr 22 '23 at 07:11