Static files inside `public` folder not being served (NextJS custom server using ExpressJS) - express

I am working on NextJS app. And I have made a custom server using ExpressJS. The problem is when I run the app using the custom server the app cannot find the static files inside the public folder.
Note: I don't have any problem When I run the app using next dev
My server
const express = require('express');
const next = require('next');
const path = require('path');
const port = parseInt(process.env.PORT, 10) || 3000;
const dev = process.env.NODE_ENV !== 'production';
const app = next({ dev });
const handle = app.getRequestHandler();
const prefix = (path = '') => `/:lang(en|tr)?`.concat(path);
app.prepare().then(() => {
const server = express();
server.get(prefix('/'), (req, res) => app.render(req, res, '/', req.query));
server.get(prefix('/agency'), (req, res) => app.render(req, res, '/agency', req.query));
server.get(prefix('/cases'), (req, res) => app.render(req, res, '/cases', req.query));
server.get(prefix('/blog'), (req, res) => app.render(req, res, '/blog', req.query));
server.get(prefix('/contact'), (req, res) => app.render(req, res, '/contact', req.query));
server.get(prefix('/image.png'), (req, res) => app.render(req, res, '/public/images/avatar01.jpg', req.query));
server.listen(port, err => {
if (err) throw err;
console.log(`> Ready on http://localhost:${port}`);
});
});

It is because you are not implementing a fallback for when there is no match:
server.all('*', async (req, res) => {
return handle(req, res);
}
will handle all the other routes for you (API routes, public/static folder, etc).

Related

cookie-session, socket.io fails to store socket.id in sessions

server.js
const express = require("express");
const cookieSession = require("cookie-session");
const socketIo = require("socket.io");
const app = express();
app.use(
cookieSession({
name: "session",
keys: ["key1", "key2"],
})
);
app.use((req, res, next) => {
console.log(req.session);
next();
});
app.get("/", (req, res) => {
res.sendFile("./index.html", { root: __dirname });
});
app.get("/about", (req, res) => {
const connectionId = req.session.connectionId;
res.send(`About. connectionId: ${connectionId}`);
});
const server = app.listen(1234);
const io = socketIo(server);
io.on("connection", (socket) => {
const connectionId = Math.random().toString(36).substring(2);
socket.request.session.connectionId = connectionId;
// socket.request.session.save();
});
My problem is that when I call the connect event on the client, but on the server socket.request.session returns undefined so I can't set a unique value in the cookie-session. What is it connected with?

node axios as middleware

I am trying to construct a middleware and then use it within the app.get route.
I know it's looks very "pioneer" but i am learning.... How can io get it to work?
const BooksMiddle = async (req, res, next) => {
axios
.get(`https://www.googleapis.com/books/v1/volumes/? q=${term}&keyes&key=${process.env.GBOOKSKEY}`)
.then((result) => {
const data = result.data;
const books = data.items;
return books;
});
next();
}
module.exports = textMiddle;
app.get("/", textMiddle, (req, res, next) => {
res.render('index');
});
If the point of this middleware is to get some book data and make that available for your template rendering, then you can put that data into res.locals where templates called from res.render() will automatically look for data:
const bookMiddle = async (req, res, next) => {
axios
.get(`https://www.googleapis.com/books/v1/volumes/?q=${term}&keyes&key=${process.env.GBOOKSKEY}`)
.then((result) => {
res.locals.books = result.data.items;
next();
}).catch(next);
}
module.exports = bookMiddle;
And, then after you import bookMiddle, you can use it like this:
app.get("/", bookMiddle, (req, res, next) => {
res.render('index');
});
If you refer to the books data structure in your template, the template engine will look in res.locals.books for that data (where the middleware puts the data).

how to insert a express middleware after app init?

app = express();
I established a socket connection after app.use(), and I want to insert another middleware after socket is connected:
const app = express();
app.use('/', () => {});
const wss = new ws.Server({ port: 8086 });
wss.on('connection', (ws) => {
app.use((req, res, next) => {
ws.send(JSON.stringify({ req, res }));
next();
});
});
app.listen(8080);
but it doesn't work,can Express insert a middleware after app init?
one solution is to make a middleware that checks if a new middleware is added. check the following example.
//this is an array of functions which will work as a middlware.
let listOfMiddlewareFunctions = [];
app.use((req, res, next) => {
//this middleware will loop through all elements in listofMiddlewareFunctions
//and pass the parameters req, res, next to each middlewares.
listOfMiddlewareFunction.foreach(middleware => middleware(req, res, next));
});
wss.on('connection', (ws) => {
//on socket connection, the following will add the middleware to the array made before.
const newMiddleware = (req, res, next) => {
ws.send(JSON.stringify({ req, res }));
next();
};
listOfMiddlewareFunction .add(newMiddleware);
});
finally, I fixed this problem:
wss.on('connection', function (ws) {
app._mockUsedWsSend = ws.send.bind(ws);
});
// in router
const wsSend = req.app._mockUsedWsSend;
if (wsSend) {
wsSend(JSON.stringify({
path: req.path
}));
}

How to disable CORS on localhost using expressjs

I want to disable CORS on localhost for a specific url, here is my code
const express = require('express')
const app = express()
const port = 3000
app.use(express.static('files'))
app.all('/no-cors/', function(req, res, next) {
res.header("Access-Control-Allow-Origin", "fake");
next();
});
app.get('/', (req, res) => res.send('Hello World!'));
app.get('/sample-json', (req, res) => res.json({"foo": "bar"}));
// it shld show error in console
app.get('/no-cors/sample-json', (req, res) => {
res.json({"cors": "off"});
});
app
.listen(port, () => console.log(Example app listening on port 3000'))
but I open http://localhost:3000/no-cors/sample-json it still show me the json.
Path argument in express().get(path,...) is evaluated as whole string. Path in Express (and URL generally, not only in Express) does not work as folder structure.
That’s why the address /no-cors/sample-json is not catched with your app.all().
If you want it to work, try the path as /no-cors/*

Using Express Router with Next.js

I'm trying to use the Express Router with Next.js using their custom-express-server example as my boilerplate. The only difference is that I'm trying to define the routes externally on routes/router.js as follows:
Code in server.js:
const express = require('express')
const next = require('next')
const port = parseInt(process.env.PORT, 10) || 3000
const dev = process.env.NODE_ENV !== 'production'
const app = next({ dev })
const handle = app.getRequestHandler()
const routes = require('./routes/router')
app.prepare()
.then(() => {
const server = express()
server.use('/', routes)
server.get('*', (req, res) => {
return handle(req, res)
})
server.listen(port, (err) => {
if (err) throw err
console.log(`> Ready on http://localhost:${port}`)
})
})
module.exports = app;
Code in routes/router.js:
const express = require('express'),
app = require('../server.js'),
router = express.Router();
router.get('/a', (req, res) => {
return app.render(req, res, '/b', req.query)
})
router.get('/b', (req, res) => {
return app.render(req, res, '/a', req.query)
})
router.get('/posts/:id', (req, res) => {
return app.render(req, res, '/posts', { id: req.params.id })
})
module.exports = router;
At this point, even when I'm importing "app" from server.js, app is not available within router.js.
Is my logic incorrect?
If it's not, then why is app not available within router.js?
Just solved it. This issue is known as a circular dependency, and it should be avoided at all costs... unless the pattern you're using (like the boilerplate I used, I guess...) requires it.
To solve it, just export from file "A" the dependency that file "B" uses before you require file "B" on file "A".
...And that's it pretty much.
You might also try using next-routes, which I use on all of my Next project:
// server.js
const { createServer } = require('http');
const next = require('next');
const routes = require('./routes');
const port = parseInt(process.env.PORT, 10) || 3000;
const dev = process.env.NODE_ENV !== 'production';
const app = next({ dev });
const handler = routes.getRequestHandler(app);
app.prepare().then(() => {
createServer(handler).listen(port, err => {
if (err) {
throw err;
}
console.log(`> Ready on http://localhost:${port}`);
});
});
Then you can configure your routes in the routes.js file without accessing the app:
// routes.js
const nextRoutes = require('next-routes');
const routes = (module.exports = nextRoutes());
routes
.add('landing', '/')
.add('blog', '/blog', 'blog')
.add('blog-post', '/blog/:postId', 'blog')