Nextjs routing stop working after adding CDN - next.js

I'm using react with nextjs. I decided to use CDN and added assetPrefix to next.config file with cdn domain. It works, now I get files from cdn but the problem is: routing does not work. I use next-routes library and change url with Router.pushRoute method. I can open a page I need if change url manually. Also I have noticed that if to pass {shallow: true} option to this method, then url changes as expected. Server on nodejs with express. getInitialProps for data fetching
Maybe these code samples will be helpfull
routes
const nextRoutes = require('next-routes');
const routes = require('./config/routes');
/**
* #type {Registry}
*/
module.exports = nextRoutes()
// first add static routes
.add(routes.EXAMPLES)
.add(routes.LOGIN)
.add(routes.SIGNIN)
.add(routes.SIGNUP)
.add(routes.STATIC_PAGE)
.add(routes.SETTINGS)
.add(routes.APPLY)
.add(routes.PRIVACY_POLICY)
.add(routes.TERMS_AND_CONDITIONS)
// then add dynamic routes
.add(routes.DOCUMENT)
.add(routes.HOME);
server.js
const routes = require('./routes');
const { DEV, PORT, HOST, GRAPHQL_APP_URL } = require('./config/vars');
// Create body-parser json middleware
const bodyParserJSON = bodyParser.json();
// Create the Express-Next App
const app = next({ dev: DEV });
const handle = routes.getRequestHandler(app);
// Start the app
app
.prepare()
// Start Express server and serve the
.then(() => {
// eslint-disable-next-line no-console
console.log(`using ${GRAPHQL_APP_URL} as API URL`);
const server = express()
// use proxy middleware to send graphql requests to api server
.use(GRAPHQL_APP_URL, bodyParserJSON, graphqlProxyMiddleware)
.use(secure)
.use((_req, res, nextRedirect) => {
newrelic.setTransactionName(res.req.path);
nextRedirect();
})
.get('/apply-now', createRateLimiter())
.get('/apply-now/:refId', createRateLimiter())
.use(handle)
.listen(PORT, HOST, (err) => {
if (err) throw err;
// eslint-disable-next-line no-console
console.log(`> Ready on ${server.address().address}:${server.address().port}`);
});
})
thank you in advance

Related

Mixed up data on concurrent requests to vue3 SSR app with apollo client

I'm trying to convert a vue3 SPA that uses an apollo client to SSR with the help of vite-plugin-ssr.
I'm facing an issue of mixed-up data on concurrent requests to the express server. The apollo client instance used to be global in the SPA, so I'm trying to create and use a new instance on every request.
I had this file that included the creation of the client, and wrapper functions around the client functions :
// apollo.ts - SPA
const apolloClient = new ApolloClient({
...
})
export const apolloQuery = async (args) => {
// some logic
const response = await apolloClient.query({...})
// some logic
return response
}
...
Those functions are used in components and store.
The integration example of apollo in vite-plugin-ssr repo uses #vue/apollo-composable
So I tried :
// app.ts
import { DefaultApolloClient } from "#vue/apollo-composable";
import { createApolloClient } from "./path/to/apollo.ts";
const createApp = () => {
const apolloClient = createApolloClient({...})
const app = createSSRApp({
setup() {
provide(DefaultApolloClient, apolloClient)
},
render() {
return h(App, pageProps || {});
}
});
}
// apollo.ts - SSR
import { useApolloClient } from "#vue/apollo-composable"
export const createApolloClient = (args) => {
// some logic
return new ApolloClient({...})
}
export const apolloQuery = async (args) => {
// some logic
const { client } = useApolloClient()
const response = await client.query({...})
// some logic
return response
}
However, this does not work as intended because useApolloClient depends on providing the apollo instance to the app (1), or using the provideApolloClient function (2) :
(1) this means that calls can only be made during component setup or life cycle hooks, as it leverages the Vue core function getCurrentInstance to inject the client. So I can neither use them in the onBeforeRender that vite-plugin-ssr provides, nor in Vue onServerPrefetch hook, nor in the async call to store action.
(2) provideApolloClient sets the client to a global variable, and the same problem occurs on concurrent requests.
Am I at a dead end and a complete refactor of the apollo client use is needed, or am I missing something?

Why am I getting a CORS error in the browser but not in Postman?

I am using the Firebase emulators to serve Firebase functions on localhost. If I test my functions using Postman, this all works using the following request:
http://localhost:5001/project-XXXX/us-central1/api/users
Then, I fire up my Next.js application on port 3000 and try to use Axios to get the same data as follows:
useEffect(() => {
axios
.get(
"http://localhost:5001/project-XXXX/us-central1/api/users"
)
.then((res) => {
console.log(res);
})
.catch(function (error) {
console.log(error);
});
}, []);
However, now I'm getting a CORS error: "Access to XMLHttpRequest at 'http://localhost:5001/project-XXXX/us-central1/api/appointments/availability' from origin 'http://localhost:3000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource."
In response to similar questions I have tried changing region and starting chrome with web-security disabled, which was both unsuccesful in solving the matter.
Does anyone have an idea as to why I am getting this error when requesting from the browser (and not from Postman)?
For full information, my index.js file of the Firebase cloud functions using Express.js:
const functions = require("firebase-functions");
const admin = require("firebase-admin");
const express = require("express");
const cors = require("cors");
const authMiddleware = require("./authMiddleware");
const { user } = require("firebase-functions/v1/auth");
admin.initializeApp();
const app = express();
const { users, updateUser } = require("./routes/users");
// user-related routes
app.use("/users", users);
const api = functions.https.onRequest(app);
// export as Firebase functions
module.exports = { api: api, updateUser: updateUser };
Thanks jub0bs! My problem was solved by installing cors (npm install cors) and adding the following to my index.js:
const cors = require("cors");
app.use(cors());
This enables CORS for all origins, so only use for development and change before you go to production.

Next.js app deployment as ssr app with some hosting provider restrictions

I have a shared hosting provider that enables hosting node apps. It has a restriction that the app entry file must be called app.js and it must be in folder /usr/home/username/domains/domain/public_nodeapp. The app is started automatically (probably by something like node app.js) upon first access from the web to the domain.
Is it possible to host a next.js app on such a provider as a server-side rendered app (not as static HTML site produced by next export)?
After running next build which makes a production version of the app, the production version has no app.js file and should be started by next start. I am not sure whether and how it could be tweaked (perhaps some file moving or renaming) to match the restrictions mentioned above.
You can put a app.js file that is placed in the required place, and then call the function that will be called when you trigger next start from the cli.
That means that this file should require https://github.com/zeit/next.js/blob/canary/packages/next/cli/next-start.ts and invoke nextStart.
// app.js
const startServer = require('next/dist/cli/next-start');
startServer();
Yes you can do it using a custom server eg. express.js
I am doing the same thing for Azure, the only difference is that I need a file called server.js
Example:
// app.js
const express = require('express');
const next = require('next');
const port = process.env.PORT || 3000;
const dev = process.env.NODE_ENV !== 'production';
const app = next({ dev });
const handle = app.getRequestHandler();
app.prepare().then(() => {
const server = express();
server.all('*', (req, res) => handle(req, res));
server.listen(port, (err) => {
if (err) throw err;
/* eslint no-console: "off" */
console.log(`> Ready on http://localhost:${port}`);
});
});
I hope this helps.

Nuxt SSR firebase functions returns 504 timeout

I'm trying to implement Nuxt with SSR in Firebase hosting (using Firebase functions), but after my function is triggered I keep getting an '504 timed out waiting for function to respond'.
My Firebase function:
const functions = require("firebase-functions");
const { Nuxt } = require("nuxt");
const express = require("express");
const app = express();
const config = {
dev: false,
buidlDir: 'src',
build: {
publicPath: '/'
}
};
const nuxt = new Nuxt(config);
function handleRequest(req, res){
console.log('handling request');
//res.set('Cache-Control', 'public, max-age=600, s-maxage=1200')
nuxt.renderRoute('/')
.then(result => {
console.log('result: ' + result.html);
res.send(result.html);
})
.catch(e => {
res.send(e);
console.log(e);
})
}
app.get('*', handleRequest);
exports.ssrApp = functions.https.onRequest(app);
I also tried with:
function handleRequest(req, res) {
console.log("log3");
res.set("Cache-Control", "public, max-age=300, s-maxage=600");
return new Promise((resolve, reject) => {
nuxt.render(req, res, promise => {
promise.then(resolve).catch(reject);
});
});
}
I also have node vs8 as default for my functions because I read that that could give problems. :
"engines": {
"node": "8"
},
But with the same result. My function is being triggered but it always times out, btw: I have this problem serving locally and when trying to deploy to Firebase itself.
Let me know if you need more information/code to try to help and see what the problem could be.
First, if you want to find out what caused it, use debug option.
Second, if you face the timeout error, check the path is valid.
If you success build Nuxt and nuxt.render, the error is processed by Nuxt, and Nuxt show this error page.
In other words, if you don't see Nuxt error page, the cause may be not related with Nuxt.
I also stuck 4 hours due to timeout error, and I finally found out the cause was the contents of publicPath.
Please check these 2 things.
buidlDir is valid ?
The path of buildDir is valid ? You should check .nuxt folder is deployed to your cloud functions successfully.
publicPath contents is uploaded successfully?
The builded contents in .nuxt/dist must be uploaded to Firebase Hosting. You should check it manually.
Type URL to address bar ex) https://test.firebaseapp.com/path/to/file.js
Finally, I post a URL of
my sample project, using Nuxt and Firebase.
I also stucked like you and it made me rally tired. I'm really happy if this answer helps someone like me.
PS: When you build Nuxt in functions folder, nuxt start is failed. Be careful. In my project, I build it in root, and when deploy, I copied it.
Nuxt SSR with Firebase Integration
I got the same problem because Nuxt is not ready yet (promise is undefined)
So you can try to add nuxt.ready() after new Nuxt()
Example:
const functions = require('firebase-functions');
const express = require('express');
const { Nuxt } = require('nuxt');
const config = {
dev: false
// Your config
};
const nuxt = new Nuxt(config);
const app = express();
nuxt.ready(); // <---------- Add this!
async function handleRequest(req, res) {
res.set('Cache-Control', 'public, max-age=1, s-maxage=1');
await nuxt.render(req, res);
}
app.get('*', handleRequest);
app.use(handleRequest);
exports.ssrApp = functions.https.onRequest(app);
Ref: https://github.com/nuxt/nuxt.js#using-nuxtjs-programmatically

my http request won't work, angular 2

I am using a MEAN stack
I have successfully served a simple JSON object {"message":"hello"} sent with an express get and res.send function that appears in my web browser if I go to the route
also on my angular 2 front end I have an http.request() that works fine if I put a JSON test api url but if I put my route url to my simple JSON then I don't get a response. Any idea what the reason might be?
my angular 2 component.ts:
makeRequest(): void {
this.loading = true;
this.http.request('myurl/members')
.subscribe((res: Response) => {
this.data = res.json();
this.loading = false;
});
}
my server.js express:
// Get dependencies
const express = require('express');
const path = require('path');
const http = require('http');
const bodyParser = require('body-parser');
var mongojs = require('mongojs');
var db = mongojs('sangha',['members']);
const app = express();
// Parsers for POST data
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
// Point static path to dist
app.use(express.static(path.join(__dirname, 'dist')));
// Set port
const port ='80';
app.set('port', port);
/**
* Create HTTP server.
*/
const server = http.createServer(app);
/**
* Listen on provided port, on all network interfaces.
*/
server.listen(port, () => console.log(`running on port ${port}`));
/*db methods
db.members.insert({"firstname":"Josh"});
db.members.findAndModify({
query: {lastname: ''},
update: {$set: {firstname: ''}},
new: true
}, function (err, doc, lastErrorObject){
//?
});
db.members.find(function(err,docs){
console.log("members collection: "+docs;
});
*/
/*submit on login page, first check the username doesn't already exists, then
db.members.insert*/
//app.post('/members',function(req,res)
app.get('/members',function(req,res){
res.send({"message":"hello"});
});
//this catch all must come after all route definitions
app.get('*', (req, res) => {
res.sendFile(path.join(__dirname, 'dist/index.html'));
});

Resources