How to deploy Nuxt SSR app to firebase through cloud functions? - firebase

I followed this medium post as a guide to host my nuxt app on firebase hosting.
The deploy goes through, however, when I then visit the url I get a Cannot GET / error message. If I check the function logs I see that the function completes with a 404 error.
This is my functions/index.js
const functions = require('firebase-functions')
const admin = require("firebase-admin")
const { Nuxt } = require('nuxt-start')
const nuxtConfig = require('./nuxt.config.js')
admin.initializeApp()
const config = {
...nuxtConfig,
dev: false,
debug: true,
buildDir: "nuxt",
publicPath: "public",
}
const nuxt = new Nuxt(config)
exports.ssrapp = functions.https.onRequest(async (req, res) => {
await nuxt.ready()
nuxt.render(req, res)
})
And this is the firebase configuration
{
"functions": {
"source": "functions",
"predeploy": [
"npm --prefix src run build && rm -rf functions/nuxt && cp -r src/nuxt/ functions/nuxt/ && cp src/nuxt.config.js functions/"
]
},
"hosting": {
"predeploy": [
"rm -rf public/* && mkdir -p public/_nuxt && cp -a src/nuxt/dist/client/. public/_nuxt && cp -a src/static/. public/ && cp -a public_base/. public/"
],
"public": "public",
"ignore": [
"firebase.json",
"**/.*",
"**/node_modules/**"
],
"rewrites": [
{
"source": "**",
"function": "ssrapp"
}
]
}
}
The project structure is this
/
/src
/functions
/public
/public_base
When I run firebase deploy I do see the content of /src being copied to /functions/nuxt. For the sake of testing I also have my /functions/package.json file include all the dependencies that I have in my /src/package.json file.
How can I get this app up and running? If you need any more details, let me know.
Update #1
I tried serving hosting and functions using the command firebase serve --only functions,hosting -p 5004.
Running the server like so gave me some more insights. Specifically I got this warning message at load time that then resulted in actual error message when loading the page.
WARN Module #firebase/app not found. Silently ignoring module as programatic usage detected
I didn't install this package in the functions directory as I did not have it in my src directory either. However, after installing it inside /functions and restarting the dev server, that warning message was gone and with it also the error I was getting on page load.
I also spotted a couple of warnings that had to do with vue, vue-server-renderer and vue-template-compiler not running the same version.
Now everything seems to be working fine!

Your config and structure look right.
I also did this about a year ago with my app and I ran into the same problem. It has to do with the function code itself. I also tried using nuxt.render(req, res) (Docs) but it never worked for me so I ended up using nuxt.renderRoute(route) (Docs) instead. This worked perfectly fine.
You could change your code to something like this:
const { Nuxt } = require('nuxt')
...
exports.ssrapp = functions.https.onRequest(async (req, res) => {
await nuxt.ready()
const result = await nuxt.renderRoute(req.path) // Returns { html, error, redirected }
res.send(result.html) // Sends html as response
})
This worked for me. You should consider catching any errors though. I hope this solves your problem.
This is only a work-around, if anyone knows why nuxt.render isn't working, I would be interested to know. I wasted many hours because of this with my app...

I tried serving hosting and functions locally using the command firebase serve --only functions,hosting -p 5004.
By doing this I was able to spot a bunch of warnings and errors such as
FATAL
Vue packages version mismatch:
- vue#2.5.21
- vue-server-renderer#2.6.11
This may cause things to work incorrectly. Make sure to use the same version for both.
WARN Module #firebase/app not found. Silently ignoring module as programatic usage detected
I then made sure that those vue packages were indeed running the same version. Then I also added the #firebase/app package in /functions/package.json (that however, is not present in /src/package.json.
I run the local server again and everything worked. I then deployed to firebase and everything was working as expected.

the following works for me (using nuxt-start instead):
const functions = require("firebase-functions");
const { Nuxt } = require("nuxt-start");
const config = {
dev: false
};
const nuxt = new Nuxt(config);
let isReady = false;
async function handleRequest(req, res) {
if (!isReady) {
try {
isReady = await nuxt.ready();
} catch (error) {
process.exit(1);
}
}
await nuxt.render(req, res);
}
exports.nuxtssr = functions.https.onRequest(handleRequest);

Related

Nuxt3 and Firebase Cloud Functions: Where to place Firebase cloud functions in the /server directory?

I successfully was able to deploy my Nuxt 3 app to Firebase hosting using Firebase cloud functions. Now, I want to create another Firebase cloud function that automatically runs some backend code in response to events triggered by Firebase Firestore database.
As a test, I wanted to add the following simple "Hello World" Http function as a test:
server/api/functions/helloWorld.js:
import * as functions from 'firebase-functions'
export default defineEventHandler(() => {
return functions.https.onRequest((request, response) => {
console.log(request)
return response.send('Hello from Firebase!')
})
})
I ran npm run build and saw the file in .output/server/chunks . Then, I ran the firebase emulator to test : I typed in http://localhost:5001/<myprojectid>/us-central1/server/api/functions/helloWorld but get the following server error:
{"url":"/api/functions/helloWorld","statusCode":404,"statusMessage":"Not Found","message":"Not Found","description":""}
However, when I try to access my other functions, I have no problem (ie, /server/api/posts/all):
This is the makeup of a "working" function (not an Http Cloud Function, though):
/server/api/posts/all.ts:
import { firestore } from '#/server/utils/firebase'
export default defineEventHandler(async (event) => {
const colRef = firestore.collection('posts').orderBy('createdAt', 'desc')
const querySnapshot = await colRef.get()
const posts = []
querySnapshot.forEach((doc) => {
if (doc.data().public_id) // ensure we only show posts with images
posts.push(doc.data())
})
return {
posts
}
})
How can I access the Firebase Function (helloWorld)?
Here is my firebase.json file:
{
"functions": {
"source": ".output/server"
},
"hosting": [
{
"site": "<removed>",
"public": ".output/public",
"ignore": [
"firebase.json",
"**/.*",
"**/node_modules/**"
],
"cleanUrls": true,
"rewrites": [
{
"source": "**",
"function": "server"
}
]
}
]
}
When using firebase preset, nuxt3 only treats functions as renderer. Here is the recommend way How to add additional firebase functions when deploying nuxt to firebase
Or you can write scripts to copy files and combine index.js, and run it at predeploy

Identifier 'module' has already been declared - amplify and nuxt 3

I am getting an error in nuxt3 then setting up this amplify plugin. I am trying to add auth to nuxt3 via plugins
plugins/amplify.js
import Amplify, {withSSRContext} from 'aws-amplify';
export default defineNuxtPlugin((ctx) => {
const awsConfig = {
Auth: {
region: "ap-south-1",
userPoolId: "ap-south-1_#########",
userPoolWebClientId: "#####################",
authenticationFlowType: "USER_SRP_AUTH",
},
};
Amplify.configure({ ...awsConfig, ssr: true });
if (process.server) {
const { Auth } = withSSRContext(ctx.req);
return {
provide: {
auth: Auth,
},
};
}
return {
provide: {
auth: Auth,
},
};
}
[nuxt] [request error] Identifier 'module' has already been declared
at Loader.moduleStrategy (internal/modules/esm/translators.js:145:18)
at async link (internal/modules/esm/module_job.js:67:21)
Does anyone know what's going on?
Been facing this myself... I don't think its a nuxt problem but rather Vite.
I gave up on running the app on dev mode and just resorted to building the app and launching it. Also, in order to use aws-amplify with vite you need to apply some workarounds:
https://ui.docs.amplify.aws/vue/getting-started/troubleshooting
For the window statement (which only makes sense on the browser) you'll need to wrap that with an if statement. Added this to my plugin file
if (process.client) {
window.global = window;
var exports = {};
}
This will let you build the project and run it with npm run build . Far from ideal but unless someone knows how to fix that issue with dev in vite...
BTW, you can also just switch to webpack builder on nuxt settings and the issue goes away.
// https://v3.nuxtjs.org/api/configuration/nuxt.config
export default defineNuxtConfig({
builder: "webpack"
});
I think this might be a problem with auto imports of nuxt.
I added a ~/composables/useBucket.ts file which I used in ~/api. Same error started popping up the next day. After I moved ~/composables/useBucket.ts to ~/composablesServer/useBucket.ts issue disappeared.

Nuxt plugin not available in Vuex's 'this' in Firebase production (ERROR: this.$myPlugin is not a function)

I'm trying to upload my nuxt app to Firebase as cloud function. The problem is that in the nuxtServerInit action I'm trying to call a plugin function, which apparently is not yet defined at that moment, because an error is thrown: (ERROR: this.$myPlugin is not a function). The code works in dev mode, it's just after upload to Firebase it fails.
The setup is as follows:
myPlugin.js
let env, auth, app, $store;
export default (context, inject) => {
env = context.app.context.env;
auth = context.app.$fire.auth;
app = context.app;
$store = context.store;
inject('myPlugin', myPlugin);
};
async function myPlugin(...) {... }
nuxt.config.js
plugins: [
{ src: '~/plugins/myPlugin', mode: 'all' }, // with no mode specified it fails too
],
vuex index.js
export const actions = {
async nuxtServerInit({ dispatch, commit }, { req }) {
const tl = await dispatch("initAction");
return tl;
}
}
vuex someModule.js
const actions = {
initAction({ commit }) {
return this.$myPlugin(...).then(...) // this line throws '$myPlugin is not a function' error
}
}
What can be the reason for the different behaviour in dev and in prod modes and how could I fix the problem?
UPDATE:
After further testing I established that the problem is not caused by the nuxtServerInit timing. I moved the call of the initAction from nuxtServerInit to a page's created hook. However the same error appears: this.$query is not a function.
The problem occured, because js files were not getting fully loaded due to CORB errors caused by incorrect configuration. Details described in this question.

Deno run is not working properly also drun

After created an index.ts and wrote a simple code for listening to port 3000 and printing hello world on the body, I'm also not able to run or get the output from deno's drun module.
import { Application, Router } from "https://deno.land/x/denotrain#v0.5.0/mod.ts";
const app = new Application();
const router = new Router();
// Middleware
app.use((ctx) => {
ctx.cookies["user.session"] = "qwertz";
ctx.cookies["a"] = "123";
ctx.cookies["b"] = "456";
delete ctx.cookies["user.session"];
return;
});
router.get("/", (ctx) => {
return new Promise((resolve) => resolve("This is the admin interface!"));
});
router.get("/edit", async (ctx) => {
return "This is an edit mode!";
});
app.get("/", (ctx) => {
return {"hello": "world"};
});
app.use("/admin", router);
app.get("/:id", (ctx) => {
// Use url parameters
return "Hello World with ID: " + ctx.req.params.id
});
return ctx.req.body;
});
await app.run()
Development Environment:- Windows 10
The problem seems to be the address 0.0.0.0 is specific to mac only.Windows Doesn't use 0.0.0.0 address.
After going to localhost:3000 / 127.0.0.1:3000. I was able to get the output.I think maybe Windows redirects the 0.0.0.0 to localhost. Anyway it solved my problem!
I am on windows. I faced with the same problem. Then,
const app = new Application({hostname:"127.0.0.1"});
I created the app in typescript giving parameter hostname like above.
And run deno like this:
deno run --allow-net=127.0.0.1 index.ts
it worked.
Run your server with the following command:
drun watch --entryPoint=./server.ts --runtimeOptions=--allow-net
In any case most Deno tools for watching changes are still bugged, I recommend to use nodemon, with --exec flag
nodemon --exec deno run --allow-net server.ts
For convenience you can use nodemon.json with the following content:
{
"execMap": {
"js": "deno run --allow-net",
"ts": "deno run --allow-net"
},
"ext": "js,json,ts"
}
And now just use: nodemon server.ts
It seems that you have an error in your code snippet, with the last
return ctx.req.body;
});
If you fix that and use the last deno (v1.0.1) and drun(v1.1.0) versions it should works with the following command:
drun --entryPoint=index.ts --runtimeOptions=--allow-net

Cannot get req.path and req.query.abc with firebase functions

I'm trying to get the request query params and url in firebase functions.
Here is the code I'm using
firebase.json
{
"hosting": {
"public": "build",
"rewrites": [{
"source": "/getCoins",
"function": "getCoins"
}]
}
}
Using "firebase-functions": "^2.3.1" in package.json
functions/index.js
'use strict';
const functions = require('firebase-functions');
exports.getCoins = functions.https.onRequest((req, res) => {
console.log(req.query); // [object Object]
console.log(req.query.repeat); // empty
console.log(req.url); // '/'
console.log(req.originalUrl); // '/'
res.sendStatus(200);
});
Started the firebase functions in my windows command prompt using firebase serve --only functions. As it starts serving data from http://localhost:5000, I'm trying to request http://localhost:5000/coins-app/us-central1/getCoins?repeat=4
I'm not getting any error in the command prompt, but could only see the commented lines from the above functions/index.js code.
You should run firebase serve and request to http://localhost:5000/getCoins?repeat=4 .
functions.https.onRequest() can't accept query string parameter directly.

Resources