I have 2 repos one for firebase functions and another for static firebase hosting react site. They both use same firebase project.
myfirebaseproject
--- firebase functions
--- firebase hosting
------index.html
Can I read my firebase-hosting files from firebase-function?
let indexHTML = fs.readFileSync('pathToFirebaseHosting/index.html').toString();
One important thing to realize is that Firebase Hosting and Cloud Functions are completely different products, and there is not a simple local path for Hosting files available in a very temporary and transient Cloud Functions instance. Everything is not bundled up together in one place (that wouldn't scale at all).
Since Hosting files are all public, what Frank says is right - just make an HTTP request for what you need. I suggest using the request-promise module instead, as it gives you a promise-based interface that's easier to work with in Cloud Functions.
Please note that if you want to make an outgoing HTTP request like this, you will have to enable billing on your project. Otherwise, Cloud Functions will not allow the request to happen. Also note that the egress and ingress from both Cloud Functions and Hosting will have additional billing. So if you make this request frequently, expect some costs associated with it.
If you just want some static files available in Cloud Function without having to make an external request, simply copy those files in to your functions folder and deploy them all along with your code. You will be able to read them locally, you won't need to enable billing to try it, and you won't incur egress and ingress charges. It'll also be faster.
While there is a REST API for Firebase Hosting API, it is focused on deploying updates, and does not have a call to access the deployed files.
But since all deployed files are publicly accessible, you can read them from the public internet with a regular HTTP request:
request('https://yourproject.firebaseapp.com/index.html', (err, res, body) => {
if (err) { return console.log(err); }
console.log(body);
});
Related
Background: Some days ago, Firebase Hosting added support for NextJS.
I have Firebase Functions and Firebase Hosting inside the same project.
I'm implementing an SSR with NextJS in Firebase Hosting, and now I need to run some fetch calls inside getServerSideProps. Those fetch calls will hit my own Firebase Functions, and I wonder if there is a better base-URL for making "local fetch" while getting that data. Some base-URL to tell Firebase Hosting: "Hey, this is a call to a resource that is inside Google".
My goal is to reduce the response time, while reducing the "tracert" stack.
In other words, I need a "local URL" to point locally in the Google-Firebase-Functions-Servers.
I am relying on the getBlob function to download files from Cloud Storage for Firebase directly from the browser. For this to work, I have allowlisted my app's origin in my Cloud Storage bucket. Everything works fine and is as expected.
However, I am also using Firebase Hosting's preview channels, each creating a new, unique origin. In consequence, for the getBlob function to work, I need to re-configure CORS for every new preview channel (and remove configurations for obsolete preview channels).
Is there a way to configure CORS of Cloud Storage buckets to automatically allow origins from all preview channels?
There is no way to automatically allowlist all preview channels (without allowlisting all origins. However, something you could do is use the CORS configuration API and the Firebase Hosting REST API to script automatically adding all channels after each deploy.
How this would work is essentially you would call ListChannels on your site, then use the resulting URLs from that list to populate the CORS configuration via the Cloud Storage API.
I'm building web app with flutter web and I'm using firebase hosting to serve the web app.
The web app makes an API post request to the static IP of my aws ec2 instance to get a response
const String api = 'http://7.91.300.2411:8080/predict';
Map<String, String> upload = {'data1': _data1, 'data2': _data2};
var _body = jsonEncode(upload);
final Uri uri = Uri.parse(api);
http.Response response =
await http.post(uri, headers: _headers, body: _body);
When I run the app on development, like on my local machine, it works, I see the logs on my ec2 server saying the endpoint was hit/called, and then it runs successfully.
But when I now deployed this web app to firebase hosting, the endpoint never gets hit/called, is as if the http post request was not made.
I've upgraded my firebase plan to blaze, yet it's still not working. I also enable cors on my ec2 instance.
Something I taught could solve the problem, was to edit the firebase.json file, and add some config to enable firebase hosting allow calls to external apis, but I don't know how to go about it
Actually, Firebase Hosting does not make calls to external APIs. Firebase Hosting "serves both static and dynamic content to a global CDN (content delivery network)". In the case of a Flutter web app, Firebase Hosting serves the files that were generated in the /build/web directory of your project when you built the app for deployment (aka the app release bundle).
The only scenario I can see that could be considered as Firebase Hosting making calls to external APIs is if you pair Firebase Hosting with Cloud Functions or Cloud Run, which, when they are executed, call the external API. Strictly speaking, in this scenario, Firebase Hosting does not call an API but serves dynamic content that was generated via a call to an API.
If I'm not mistaking, by looking at your code, we can conclude that this scenario does not apply to your case. In your case, Firebase Hosting just hosts your Flutter app release bundle.
In your case, you are using the Dart http package in order to call the API from your web page/app. I don't see any reason why Firebase Hosting would prevent that: Your browser has downloaded the web page from Firebase Hosting and then the web page initiates, from your browser, a direct call to an API (without calling Firebase Hosting). So most probably the problem comes from something else.
I am working on a project in which we have pre-existing cloud functions in use with Firebase. We are adding a small React SPA using firebase cloud hosting, and this SPA will interact with some of the existing public cloud functions.
The way we have been doing things so far, we have a dev project, and a production project in Firebase. For cloud functions, this works fine, we have environment specific config set up with firebase functions:config:set for differentiations between prod and dev servers.
The problem comes with the hosted SPA contacting the cloud functions. I've seen a lot of questions on how to access the environment config in the hosted code, eg this one: How to reference Firebase Functions config variables from a Firebase-hosted application? where the answer seems to be to have firebase functions that return the values of the environment variables, but for me this just moves the problem further back on step. I fully understand that having the environment variables accessible to this code would be a massive security problem as the SPA is run in the browser.
The only environment specific config I really need for the hosted SPA is the base address for the cloud functions.
eg if in my cloud functions I have
const functions = require('firebase-functions');
const express = require('express');
const test = express();
test.on('/hello/:target', (req, res) => {
res.send(`Hello ${req.params.target}`);
})
exports.test = functions.https.onRequest(test);
then having deployed, this cloud function is available both at https://us-central1-DEV-PROJECT-NAME.cloudfunctions.net/test/hello/world and https://us-central1-PROD-PROJECT-NAME.cloudfunctions.net/test/hello/world . How would I best get the appropriate root url (https://us-central1-DEV-PROJECT-NAME.cloudfunctions.net or https://us-central1-PROD-PROJECT-NAME.cloudfunctions.net) for the project that the SPA is deployed to?
eg. is there some global I can access in the frontend js code where I could do something like:
const url = `${__FIREBASE_GLOBALS__.cloudFunctions.baseUrl}/test/hello/${input}`;
And have the url be correctly defined based on which project the hosted app is deployed to?
I'm assuming here that you're not using Firebase in any other way in your SPA other than to call Cloud Functions (since you didn't say otherwise).
Read the Firebase web setup docs for Firebase Hosting, especially the section on SDK imports and implicit initialization. When you host a site with Firebase Hosting, there are some special URLs that give you the configurations for that project. There are some special script includes that give you access to Firebase products. In particular, note the relative path URI /__/firebase/init.js will yield JavaScript that initializes the Firebase JavaScript SDK with the default settings for your project. Go ahead and access that in a browser pointing to your web app. You're probably interested in the projectId property of the config.
If you want to get a hold of that value, you can use the Firebase SDK, which would be initialized by the script includes from the first link above. Minimally, you could add:
<script src="/__/firebase/5.8.2/firebase-app.js"></script>
<script src="/__/firebase/init.js"></script>
Then later on (see API docs):
firebase.app().options.projectId
to get the ID of the project where Firebase Hosting is serving the content. You can use that to build the URL to your functions.
It might also be convenient for you to port your HTTP functions to callable functions and invoke them from the web site with the Firebase SDK to invoke kthem. Or not.
I was able to get the region and appId from the environment variables.
eg:
console.log(process.env);
Check your firebase logs
{ ...
ENTRY_POINT: 'server',
X_GOOGLE_FUNCTION_TRIGGER_TYPE: 'HTTP_TRIGGER',
FIREBASE_CONFIG: '{"projectId":"pid","databaseURL":"https://pid.firebaseio.com","storageBucket":"pid.appspot.com","locationId":"europe-west"}',
X_GOOGLE_FUNCTION_NAME: 'server',
FUNCTION_TRIGGER_TYPE: 'HTTP_TRIGGER',
X_GOOGLE_GCLOUD_PROJECT: 'pid',
FUNCTION_NAME: 'server',
X_GOOGLE_GCP_PROJECT: 'pid',
X_GOOGLE_FUNCTION_REGION: 'us-central1',
FUNCTION_REGION: 'us-central1',
X_GOOGLE_ENTRY_POINT: 'server',
GCLOUD_PROJECT: 'pid',
GCP_PROJECT: 'pid',
... ommited
}
Out of these GCP_PROJECT, GCLOUD_PROJECT, FUNCTION_REGION, FUNCTION_NAME should work. So for eg. process.env.FUNCTION_REGION
Not sure how reliable this will be.
I have three Firebase projects representing Development, Staging and Production environments hosted on Firebase hosting. Each environment utilizes its own deployed Firebase functions like so:
Dev function endpoint: https://us-central1-my-app-dev.cloudfunctions.net/someFunction
Staging function endpoint: https://us-central1-my-app-staging.cloudfunctions.net/someFunction
Production function endpoint: https://us-central1-my-app.cloudfunctions.net/someFunction
I can't figure out how the static, Firebase-hosted client React application should invoke these functions because the URI endpoints of each changes depending on which environment the code is executing from.
Ideally I could set environment-specific configuration for each Firebase Hosting environment; unfortunately the only way to do this in Firebase Hosting is from within Firebase Functions themselves.
How can I retrieve the environment-specific endpoint for each Firebase Function?
You have a couple options here.
First, you could just configure your React app any way you like. It's necessarily not a bad thing for each system component (backend, frontend) to have its own configuration.
Second, since you're using Firebase Hosting to serve your static content, you can also use it to serve your functions API endpoints. This means that both your static content and API endpoints are all served through the same hostname, which means you no longer have to specify the host when making a request. All the requests can be relative to that host. You can achieve this via Hosting rewrite rules.