change code from template engine to next js - reactjs

How do I convert my app that is made with .pug to next app ? I have an app using .pug engine and I want to convert it into next.
This is the app.js but as I know next is different how do I do it? Because here my files are in views, and in views the files are in pages etc how do I do it? Is there any way or I have to code it all again?
const express = require('express');
const app = express();
const port = process.env.PORT || 3000;
const middleware = require('./middleware')
const path = require('path')
const bodyParser = require("body-parser")
const mongoose = require("./database");
const session = require("express-session");
const http = require('http');
const server = app.listen(port, () => console.log("Server listening on port " + port));
const io = require("socket.io")(server, { pingTimeout: 60000 });
app.set("view engine", "pug");
app.set("views", "views");
app.use(bodyParser.urlencoded({ extended: false }));
app.use(express.static(path.join(__dirname, "public")));
app.use(session({
secret: "#########",
resave: true,
saveUninitialized: false
}))
// Routes
const loginRoute = require('./routes/loginRoutes');
const registerRoute = require('./routes/registerRoutes');
const logoutRoute = require('./routes/logout');
const postRoute = require('./routes/postRoutes');
const profileRoute = require('./routes/profileRoutes');
const uploadRoute = require('./routes/uploadRoutes');
const searchRoute = require('./routes/searchRoutes');
const messagesRoute = require('./routes/messagesRoutes');
const notificationsRoute = require('./routes/notificationRoutes');
// Api routes
const postsApiRoute = require('./routes/api/posts');
const usersApiRoute = require('./routes/api/users');
const chatsApiRoute = require('./routes/api/chats');
const messagesApiRoute = require('./routes/api/messages');
const notificationsApiRoute = require('./routes/api/notifications');
app.use("/login", loginRoute);
app.use("/register", registerRoute);
app.use("/logout", logoutRoute);
app.use("/posts", middleware.requireLogin, postRoute);
app.use("/profile", middleware.requireLogin, profileRoute);
app.use("/uploads", uploadRoute);
app.use("/search", middleware.requireLogin, searchRoute);
app.use("/messages", middleware.requireLogin, messagesRoute);
app.use("/notifications", middleware.requireLogin, notificationsRoute);
app.use("/api/posts", postsApiRoute);
app.use("/api/users", usersApiRoute);
app.use("/api/chats", chatsApiRoute);
app.use("/api/messages", messagesApiRoute);
app.use("/api/notifications", notificationsApiRoute);
app.get("/", middleware.requireLogin, (req, res, next) => {
var payload = {
pageTitle: "Home",
userLoggedIn: req.session.user,
userLoggedInJs: JSON.stringify(req.session.user),
}
res.status(200).render("home", payload);
})
io.on("connection", socket => {
socket.on("setup", userData => {
socket.join(userData._id);
socket.emit("connected");
})
socket.on("join room", room => socket.join(room));
socket.on("typing", room => socket.in(room).emit("typing"));
socket.on("stop typing", room => socket.in(room).emit("stop typing"));
socket.on("notification received", room => socket.in(room).emit("notification received"));
socket.on("new message", newMessage => {
var chat = newMessage.chat;
if(!chat.users) return console.log("Chat.users not defined");
chat.users.forEach(user => {
if(user._id == newMessage.sender._id) return;
socket.in(user._id).emit("message received", newMessage);
})
});
})

If you don't want to refactor all your pug template engine pages to next.js pages, then you can make the pug pages coexist with the next.js. You can make the next.js the default route, and place next.js code after all pug page routes. And you also need to refactor app.get("/", middleware.requireLogin, (req, res, next) => {...} to make sure next.js is the default route.
To apply this rule, you need a custom next.js server.
sample code
const express = require('express');
const next = require('next');
const port = 3000;
const dev = process.env.NODE_ENV !== 'production'; // use default NodeJS environment variable to figure out dev mode
const app = next({dev, conf});
const handle = app.getRequestHandler();
const server = express();
// all your pug page routes should be declared before `server.get('*'`.
server.get('*', authMiddleware(false), (req, res) => {
// pass through everything to NextJS
return handle(req, res);
});
app.prepare().then(() => {
server.listen(port, (err) => {
if (err) throw err;
console.log('NextJS is ready on http://localhost:' + port);
});
}).catch(e => {
console.error(e.stack);
process.exit(1);
});

Related

create Websocket with custom NextJS server

I'm runnung NextJS application with a custom server to establish a websocket between the frontend and the custom backend.
Here is the custom server:
const express = require("express");
const next = require("next");
const emitter = require("./lib/eventEmitter");
const port = parseInt(process.env.PORT, 10) || 3000;
const dev = process.env.NODE_ENV !== "production";
const app = next({ dev });
const handle = app.getRequestHandler();
const server = express();
const http = require('http')
const socketIo = require("socket.io");
const wbServer = http.createServer(server)
const io = socketIo(wbServer);
io.on("connection", (socket) => {
console.log("client connected: ", socket.id);
});
app.prepare().then(() => {
server.all("*", (req, res) => {
return handle(req, res);
});
server.listen(port, () => {
console.log(`> Ready on http://localhost:${port}`);
});
});
Here is the frontend connection:
useEffect(() => {
(async () => {
let socket = io("http://localhost:3000");
socket.on("connected", () => {
console.log("Connected");
});
})();
});
but it's not connecting React is showing 404 error like this:
XHR GET http://localhost:3000/socket.io?EIO=4&transport=polling&t=ODFLYBM
[HTTP/1.1 404 Not Found 8ms]
The answer is listening to wbServer instead of server like this:
const server = require("http").Server(app);
server.listen(port, () => {
console.log(`> Ready on http://localhost:${port}`);
});

How to resolve the Socket.io error "ERR_NAME_NOT_RESOLVED

When I run my MERN Stack project on my localhost and get my app's render page, when I click on a button in my app, that button does and displays nothing. When I inspect my client-side render page, I see the following error:polling.js:311 GET http://%22http/socket.io/?EIO=4&transport=polling&t=O7Mtvxd net::ERR_NAME_NOT_RESOLVED. I don't know what it means, I searched the meaning on the internet but without success. Here is my backend index.js file:
const express = require('express')
const cors = require('cors')
const mongoose = require('mongoose')
require("dotenv").config()
const app = express()
const http = require('http')
const server = http.createServer(app)
const io = require('socket.io')(server)
const UserRoutes = require('./routes/User')
const AuthRoutes = require('./routes/Auth')
const PostRoutes = require('./routes/Post')
const PORT = process.env.PORT || 5000
const {MONGODB_URI} = require("./config")
app.use(cors())
app.use(express.json())
app.use((req, res, next) => {
io.req = req
req.io = io
next()
})
app.use('/api/auth', AuthRoutes)
app.use('/api/user', UserRoutes)
app.use('/api/post', PostRoutes)
require('./socket')(io)
mongoose
.connect(MONGODB_URI, {
useNewUrlParser: true,
useUnifiedTopology: true,
useCreateIndex: true,
})
.then(() => {
console.log('database connected')
server.listen(PORT, () => console.log(`server started on port ${PORT}`))
})
.catch((err) => console.log(err))
my backend socket.js file :
const User = require('./models/User')
const jwt = require('jsonwebtoken')
module.exports = (io) => {
io.on('connection', (socket) => {
if (io.req) {
socket.broadcast.emit('friend-login-status', { user_id: io.req.userId })
addSocketIdInDB(socket.id, io.req.userId)
socket.on('disconnect', () => {
socket.broadcast.emit('friend-logout-status', {
user_id: io.req.userId,
})
io.req.userId = null
})
}
})
}
async function addSocketIdInDB(socket_id, user_id) {
const user = await User.findById(user_id)
if (socket_id) {
user.socketId = socket_id
}
await user.save()
}
I looked on this question after this but without success. I work on Microsoft Edge .

unexpected token in json at position 0 reactjs mongodb

///component
function Home() {
const [show, setShow]= useState([{name:'', info:'', airingDate:'', poster:''}])
useEffect(()=>{
fetch("/home")
//.then(res=> res.json())
.then(res => res.text())
.then(text => console.log(text))
})
return (
<div>
{show.map(a=>
<div>
<h2>{a.title}</h2>
</div>
)}
</div>
)
/////index.js
const TvShows = require("./models/TvShows");
const express = require("express");
const app = express();
const mongoose= require("mongoose")
const dotenv= require("dotenv");
const authRoute = require("./routes/auth");
const { application } = require("express");
const userRoute = require("./routes/users");
const commentRoute = require("./routes/comments");
const tvshowsRoute = require("./routes/tvshows");
const cors = require("cors");
app.use(cors());
console.log(".");
dotenv.config();
app.use(express.json());
mongoose.connect(process.env.MONGO_URL,{
useCreateIndex: true,
useNewUrlParser: true,
useUnifiedTopology: true,
}).then(console.log("connected to mongoDB"));
app.use("/auth", authRoute);
app.use("/users", userRoute);
app.use("/comments", commentRoute);
app.post("/api/home", tvshowsRoute);
app.use("/api/home", tvshowsRoute);
/*
app.get('/api/home', (req,res)=>{
TvShows.find().then((result)=>{
res.send(result);
})
})
*/
/*
app.use("/",(req,res)=>{
console.log("main url")
})*/
app.listen("3001",()=>{
console.log("backend running");
})
//////route
const router = require("express").Router();
const TvShows = require("../models/TvShows");
router.post("/api/home", async (req, res) => {
console.log("here")
try{
const newTvShow = new TvShows({
title: req.body.title,
poster: req.body.poster,
info: req.body.info
});
const savedTvShows = await newTvShow.save();
res.status(200).json(savedTvShows);
}catch (err) {
res.status(500).json(err);
}
}
);
router.route("/api/home").get((req, res)=>{
TvShows.find()
.then(foundShows=> res.json(foundShows))
})
module.exports = router;
when I change res.json with res.text I see my index.html page on console not the data I want to fetch from mongodb. This error is probably because I didn't use /api/ on root url but I couldn't figure it out where I should write it. I tried but didn't work. It would be so good if someone could've helped. Thank you so much.
Indeed, you are fetching the /home page of your front-end app.
Assuming the api is on a different server, you would need to call the address of that server.
If you have a set up locally with a nodejs server and a react app running separately, you should have them run on two different ports.
If you have react app on http://localhost:3000 (default), then change your api to listen on 3001, then in your react code above, you can use the full uri
http://localhost:3001/api/home
in your fetch call.
I'm making a lot of assumptions about how you have this set up, based on my own experience of local development for similar problems.

Error wooCommerce REST API : woocommerce_rest_cannot_view

I have some difficulties accessing my wooCommerce API with react and nextjs.
I always have this message : woocommerce_rest_cannot_view
I tried the response I've seen on other thread on stackoverflow, but nothing worked for me.
Here my server.js
const next = require('next');
const express = require('express');
const wooConfig = require( './wooConfig' );
const WooCommerceAPI = require('woocommerce-api');
// import WooCommerceRestApi from "#woocommerce/woocommerce-rest-api"; // Supports ESM
const WooCommerce = new WooCommerceAPI({
url: wooConfig.siteUrl,
consumerKey: wooConfig.consumerKey,
consumerSecret: wooConfig.consumerSecret,
wpAPI: true,
version: 'wc/v1',
query_string_auth: true
});
const port = 3000;
const dev = process.env.NODE_ENV !== 'production';
const app = next({ dev });
const handle = app.getRequestHandler();
app.prepare()
.then(() => {
const server = express();
server.get('/getProducts', (req, response) => {
WooCommerce.get('products', function (err, data, res) {
response.json(JSON.parse(res));
});
})
server.get('*', (req, res) => {
return handle(req, res);
});
server.listen(port, err => {
if (err) {
throw err;
}
console.log(`Ready on port ${port}`)
})
})
.catch(ex => {
console.error(ex.stack);
process.exit(1);
});;
I found the solution :
This is
queryStringAuth: true
instead of
query_string_auth: true

HTTPS on localhost using NextJS + Express

System Information
Express: 4.16.4
NextJS: 8.0.3
React: 16.8.4
ReactDOM: 16.8.4
Goal
Serve the web application using SSL over HTTPS on localhost
What has been done
Created basic NextJS application using Create Next App
Generated a certificate and key using OpenSSL and moved it into the project directory
Added the Express dependency
Configured the app to use express inside server.js
Changed script to use the server.js inside package.json scripts.
server.js
const express = require('express');
const next = require('next');
const dev = process.env.NODE_ENV !== 'production';
const app = next({ dev });
const handle = app.getRequestHandler();
const port = 3000;
const https = require('https');
const fs = require('fs');
const httpsOptions = {
key: fs.readFileSync('./certificates/key.pem'),
cert: fs.readFileSync('./certificates/cert.pem')
};
app
.prepare()
.then(() => {
const server = express();
server.get('*', (req, res) => {
return handle(req, res);
});
server.listen(port, err => {
if (err) throw err;
console.log('> Ready on http://localhost: ' + port);
});
})
.catch(ex => {
console.error(ex.stack);
process.exit(1);
});
Extra Information
The app currently works when initialized using yarn dev. I have tried to serve the app over https using this answer but I was unable to figure out how to apply this to my current setup using NextJS.
I spent a lot of time researching the web how to apply this solution but have not yet found a way on how to make this work.
Any help is greatly appreciated.
You just need to use the createServer method of https module.
const { createServer } = require('https');
const { parse } = require('url');
const { readFileSync } = require('fs');
const next = require('next');
const port = 3000;
const dev = process.env.NODE_ENV !== 'production';
const app = next({ dev });
const handle = app.getRequestHandler();
const httpsOptions = {
key: readFileSync('./certificates/key.pem'),
cert: readFileSync('./certificates/cert.pem')
};
app.prepare()
.then(() => {
createServer(httpsOptions, (req, res) => {
const parsedUrl = parse(req.url, true);
handle(req, res, parsedUrl);
}).listen(port, err => {
if (err) throw err;
console.log(`> Ready on https://localhost:${port}`);
})
});
Other answer seemed to just drop express... Found a solution after some difficulty with both server code and certificate so hopefully can save someone else the trouble!
First of all, solid advice for creating localhost certificate here:
https://letsencrypt.org/docs/certificates-for-localhost/
Secondly, simple code that offers HTTP/HTTPS with next js and express:
const next = require('next');
const express = require('express');
const http = require('http');
const https = require('https');
const fs = require('fs');
const ports = {
http: 3080,
https: 3443
}
const dev = process.env.NODE_ENV !== 'production';
const app = next({ dev });
const handle = app.getRequestHandler();
const server = express();
const options = {
key: fs.readFileSync('localhost.key'),
cert: fs.readFileSync('localhost.crt'),
};
app.prepare().then(() => {
server.all('*', (req, res) => {
return handle(req, res)
});
http.createServer(server).listen(ports.http);
https.createServer(options, server).listen(ports.https);
});
It is worth noting that one could omit or redirect either port.
Below work for me very well for next server with https;
Using this official documentation of node js https module Creating HTTPS Server
const { createServer } = require('http')
const { parse } = require('url')
const next = require('next')
const { readFileSync } = require('fs');
const port = parseInt(process.env.PORT, 10) || 3000
const dev = process.env.NODE_ENV !== 'production'
const app = next({ dev })
const handle = app.getRequestHandler()
const httpsOptions = {
pfx: readFileSync('./certificates/AMB.pfx'),
passphrase: 'Testabc$'
};
app.prepare().then(() => {
createServer(httpsOptions, (req, res) => {
const parsedUrl = parse(req.url, true)
const { pathname, query } = parsedUrl
if (pathname === '/login') {
app.render(req, res, '/login', query)
} else {
handle(req, res, parsedUrl)
}
}).listen(port, err => {
if (err) throw err
console.log(`> Ready on https://localhost:${port}`)
})
})
Our straightforward, switchable implementation:
const app = require('express')();
const https = require('https');
const http = require('http');
const next = require('next');
const fs = require('fs');
const path = require('path');
const HTTPS = true;
const server = HTTPS
? https.createServer(
{
key: fs.readFileSync(path.resolve(__dirname, './server.key')),
cert: fs.readFileSync(path.resolve(__dirname, './server.cert')),
},
app
)
: http.createServer({}, app);
const port = parseInt(process.env.PORT, 10) || 3000;
const dev = process.env.NODE_ENV !== 'production';
const nextApp = next({ dev });
const nextHandler = nextApp.getRequestHandler();
nextApp.prepare().then(() => {
app.get('/api/something', (req, res) => {
res.json({});
});
// ...
app.get('*', (req, res) => {
return nextHandler(req, res);
});
server.listen(port, (err) => {
if (err) throw err;
console.log(`> Ready on http${HTTPS ? 's' : ''}://localhost:${port}`);
});
});

Resources