I am using Next.js (with Redux, react-i18next, styled components and Express) and Next.js loads my pages without AJAX (with a hard load, no in-place content replacement). Unfortunately, I can't determine the issue of the problem. There's no error in the console (browser and server). Does anyone of you know how to debug this issue or has helpful tips about the problem?
Here's the code of my server:
const express = require('express');
const next = require('next');
const {parse} = require('url');
const i18nextMiddleware = require('i18next-express-middleware');
const Backend = require('i18next-node-fs-backend');
const i18n = require('../hoc/i18n');
const port = parseInt(process.env.APP_PORT, 10) || 3000;
const dev = process.env.NODE_ENV !== 'production';
const app = next({dev});
const handle = app.getRequestHandler();
// init i18next with server-side settings
// using i18next-express-middleware
i18n.use(Backend).use(i18nextMiddleware.LanguageDetector).init({
preload: ['en', 'de'],
ns: ['common', 'home', 'content'],
backend: {
loadPath: __dirname + '/../locales/{{lng}}/{{ns}}.json',
addPath: __dirname + '/../locales/{{lng}}/{{ns}}-missing.json',
jsonIndent: 2
}
}, () => {
app.prepare().then(() => {
const server = express();
// Translation routing
server.use(i18nextMiddleware.handle(i18n));
server.use('/locales', express.static(__dirname + '/../locales'));
server.post('/locales/add/:lng/:ns', i18nextMiddleware.missingKeyHandler(i18n));
// Application Routing
server.get('*', (req, res) => {
// Be sure to pass `true` as the second argument to `url.parse`.
// This tells it to parse the query portion of the URL.
const parsedUrl = parse(req.url, true);
const {pathname, query} = parsedUrl;
if (pathname.startsWith('/_next')) {
return handle(req, res, parsedUrl);
} else if (pathname === '/') {
return app.render(req, res, '/', query);
} else {
return app.render(req, res, '/content', query);
}
});
server.listen(port, err => {
if (err) {
throw err;
}
console.log(`> Application server ready on http://localhost:${port}`);
});
})
});
The link itself is created with
<Link href={item.link}>
<a>
{item.title}
</a>
</Link>
Even though the server maps the dynamic URL correctly, the client-side still has to use the following link syntax to make it work (especially important is the "as" attribute):
<Link href={'/content'} as={'/the-real-url'}>
<a>Test Link</a>
</Link>
Related
I setup sentry cloud in our React application but its blocked by AdBlockers (when turning Adblocker off, it works).
Is there someone who successfully setup a tunnel in a react application?
I played around with CORS but it didnĀ“t work
Playing around with the tunnel property in Sentry.init from the nextjs example in https://github.com/getsentry/examples/blob/master/tunneling/nextjs/pages/api/tunnel.js is throwing a /tunnel 404 (Not Found) console error in react app although I added a route to this path into my App which contains the handle function from nextjs example.
...
Sentry.init({
dsn: 'https://mine#mine.ingest.sentry.io/mine',
integrations: [new BrowserTracing()],
environment,
tunnel: '/tunnel',
tracesSampleRate,
});
...
where I tried it directly via <Route path='/tunnel' component={(req, res) => handle(req, res)} /> and also by using a component <Route path='/tunnel' component={Tunnel} /> with
function Tunnel(props) {
let location = useLocation();
useEffect(() => {
if(location.pathname === '/tunnel') {
handle(props.req, props.res);
}
}, [location.pathname]);
return null;
}
I even tried Webpack Plugin
plugins: [
new SentryWebpackPlugin({
include: '.',
ignore: ['node_modules'],
org: 'my_org',
project: 'app',
authToken:
'myToken',
}),
],
but it also is being getting blocked
--- Update ---
At least for local development and testing its possible to adjust the webpack config.
const bodyParser = require('body-parser')
const sentryHost = '#o<orgId>.ingest.sentry.io';
// Set knownProjectIds to an array with your Sentry project IDs which you
// want to accept through this proxy.
const knownProjectIds = ['12345'];
app.use(bodyParser.text());
app?.post('/tunnel', async (req, res) => {
try {
const envelope = req.body;
const pieces = envelope.split('\n');
const header = JSON.parse(pieces[0]);
// DSNs are of the form `https://<key>#o<orgId>.ingest.sentry.io/<projectId>`
const { host, pathname } = new URL(header.dsn);
// Remove leading slash
const projectId = pathname.substring(1);
if (host !== sentryHost) {
throw new Error(`invalid host: ${host}`);
}
if (!knownProjectIds.includes(projectId)) {
throw new Error(`invalid project id: $. {projectId}`);
}
const sentryIngestURL = `https://${sentryHost}/api/${projectId}/envelope/`;
const sentryResponse = await fetch(sentryIngestURL, {
method: 'POST',
body: envelope,
});
sentryResponse.headers.forEach(([key, value]) => res.setHeader(key, value));
res.status(sentryResponse.status).send(sentryResponse.body);
} catch (e) {
captureException(e);
return res.status(400).json({ status: 'invalid request' });
}
res.send("POST res sent from webpack dev server")
})
but only for local testing. In production I guess we would use a proxy.
///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.
In my root project I have a /public holder set up with a "home.jpg" and "home-placeholder.jpg" image files.
Inside my /pages/index.js file I have a component that takes in two images:
function Page() {
return (
<>
<Head title="Home" />
<Home>
<Right
alt="home-image"
image="./home.jpg"
placeholder="./home-placeholder.jpg"
/>
</Home>
</>
);
}
I cannot get those images to display in my dev server, I always get: Cannot GET /home.jpg.
I've tried:
using next-images and importing the images
building and deploying on my production server
changing name of public folder to /static/
The images are correctly loading inside the output path /.next/static/images/
You are using custom Express Server and you are missing Next app requestHandler:
import * as Routes from "~/src/routes";
import express from "express";
import next from "next";
const dev = process.env.NODE_ENV !== "production";
const port = process.env.PORT || 8000;
const app = next({ dev, quiet: false });
const handle = app.getRequestHandler(); // <----
app.prepare().then(() => {
const server = express();
server.get("/", async (req, res) => {
return await Routes.signIn(req, res, app);
});
server.all("*", (req, res) => { // <----
return handle(req, res);
});
server.listen(port, (err) => {
if (err) throw err;
console.log(`Server running on http://localhost:${port}`);
});
});
Check out this Custom Express Server example by Next.js.
Below is an example of a link structure that I am trying to work with:
www.baseurl.com/pathname/some-sub-information
I essentially want NextJS to render the file matching the /pathname/ - so pathname.js. No matter what /some-sub-information might be, NextJS should render the pathname.js file, using the /some-sub-information as parameters for an API call.
I know this could essentially be done by passing queries through the link, and have it hook the the pathname, although I have been instructed by marketing that this is how they want the links.
I am at a bit of a loss how to do this, as this is the first time I am working with Next and SSR in general. I am hoping that there is someway in Next to specify that it should render a certain file when it hits the /pathname part of the url, and then just ignore the rest of the url.
This might be too much to ask, bug if there is any other way that I could achieve this, guiding information would be highly appreciated.
The solution I can think of is to add a custom server where you parse path like /pathname/some-sub-information and converts it into page to render pathname and some additional param some-sub-information
server.js
const { createServer } = require('http');
const { parse } = require('url');
const next = require('next');
const dev = process.env.NODE_ENV !== 'production';
const app = next({ dev });
const handle = app.getRequestHandler();
app.prepare().then(() => {
createServer((req, res) => {
const parsedUrl = parse(req.url, true);
const { pathname, query } = parsedUrl; // pathname = '/pathname/some-sub-information'
const parts = pathname.split('/');
const page = parts[1]; // 'pathname'
const param = parts[2]; // 'some-sub-information'
if (page) {
const queryParams = { ...query, pageParam: param };
app.render(req, res, '/' + page, queryParams);
} else {
handle(req, res, parsedUrl);
}
}).listen(3000, err => {
if (err) throw err;
console.log('> Ready on http://localhost:3000');
});
});
Params that are passed from server to client app.render(req, res, '/' + page, { pageParam: 'test' }); can be accessed inside getInitialProps query param e.g. query.pageParam
So the page will look something like this
pages/index.js
function Index({ pageParam }) {
return (
<div>
INDEX component with {pageParam}
</div>
);
}
Index.getInitialProps = async ({ query }) => {
const { pageParam } = query;
return { pageParam };
};
export default Index;
Having this custom server and pages/index.js (node server.js), go to /index/some-data-here will result into the following page
Hope this helps you!
I'm doing development on Next.JS, and every time I hot reload after making a modification of the codes, there seems to be some kind of a cache that causes Client side codes and Server side codes to be different.
Currently, I need to open a new window every time I save my codes, in order to see the updates.
Is there anything I can do so it auto reload to the latest codes available all the time?
I tried using helmet/nocache with no results.
const express = require('express')
const next = require('next')
//const routes = require('./routes')
const dev = process.env.NODE_ENV !== 'production'
const app = next({ dev })
const handle = app.getRequestHandler()
const nocache = require('nocache') //added no cache
app.prepare()
.then(() => {
const server = express()
server.use(nocache()) //using no cache
server.get('/listing/:id', (req, res) => {
const actualPage = '/listing'
const queryParams = { id: req.params.id }
return app.render(req, res, actualPage, queryParams)
})
server.get('*', (req, res) => {
return handle(req, res)
})
server.listen(3000, '127.0.0.2', (err) => {
if (err) throw err
console.log('> Ready on http://localhost:3000')
})
})
.catch((ex) => {
console.error(ex.stack)
process.exit(1)
})