Can't access dynamic routes and error page in next js - javascript

Whenever I set proxy to backend api in next.config.js, dynamic routes and error page can no longer be accessed
async rewrites() {
return [
{
source: '/:slug*',
destination: 'http://localhost:5000/:slug*', // backend url
},
]
},
With the above set up, dynamically routing to [id].js gives cannot get...
Routing to random routes (routes not in my page) give cannot get... Instead of my 404.js (error page)
When I have the rewrites commented, everything works fine.
Is there something I'm doing wrong

Related

Nextjs static build redirecting to home page on reload

I have created a static nextjs build using: npm run export.
It is exported successfully but when I'm deploying the build on S3 or any other webserver(apache with .htaccess, Nginx), and serving the index.html when the routes are copy pasted in the browser, they redirect to /, and when after reloading when on some route, also get redirected to /.
I have tried adding trailingSlash: true, still not working and I have also tried:
exportPathMap: async function (
defaultPathMap,
{ dev, dir, outDir, distDir, buildId }
) {
return {
'/': { page: '/' },
'/home': { page: '/home' },
'/register': { page: '/register' },
'/login': { page: '/login' },
'/forgot_password': { page: '/forgot_password' },
}
},
And still getting redirected to the root. And making the required changes on S3 static Webhosting like adding redirection rules and index.html in error is not working.
But all works fine when served on a port on any server but getting this issue only in static build.

how to redirect to error page if path has a .(dot) in Nuxt 2?

I created error.vue in layout directory and it work almost corectly, but if path has a dot like(http://localhost:3000/for.m) i see "Cannot GET /PATH" instead my custom error page.
Cannot GET /PATH
If i change in nuxt.config.js file target to 'server' this problem disappear but adding new problems in path (http://localhost:3000/_nuxt/) i see default 404 message from browser instead my custom error page and actually i need target static.
I don`t now can i fix this with Nuxt settings or i should write custom error handler
can anyone help me with this problem. Thanks for your help!
I found in nuxt github similar request
https://github.com/nuxt/nuxt.js/issues/8715
where someone writes that it's not a bug, that is a features of static nuxt app. Either you resign this, either change 'static' to 'server'. I choose second way, with error where in _nuxt path browser return default 404 message, fixed it like this:
in nuxt.config added
build: {
publicPath: 'store', // changed '_nuxt' way to 'store'
}
serverMiddleware: ['~/server-middleware/errorhandler'], // added middleware for handling error before render page
in server-middleware/errorhandler.js
import { readFileSync } from 'node:fs';
export default function (req, res, next) {
// if it's a stuff path for take
if (decodeURI(req.url).match(/\/_ipx.*/) || decodeURI(req.url).match(/\/store.*/)) {
// try to find file
try { // if the file is found, show it
readFileSync('static/'+ req.url.match(/img.*/)[0])
next()
} catch (error) { // if the file hasn't been found, rederect to custom error page
res.writeHead(301, { Location: '/404' })
res.end()
}
} else {
next()
}
}

Static serving on express js not working when also using custom middleware

I am trying to write a middleware for my express js website so that I can use subdomains. I also want to use static image, css, and js serving. My HTML pages load just fine but whenever I try to call a .js file, I get a long page load time and the js doesn't load.
Any help is appreciated, thanks! :)
app.use("/assets", express.static(path.join(__dirname, "assets")));
app.get("*", (req, res, next) => {
let host = req.get("host").split(".");
console.log(req.originalUrl);
let url = req.originalUrl.split("/");
url.shift();
console.log(url);
if (host.length > 2) {
res.send("myWebsite.com");
} else {
const pages = Page.getPages();
pages.forEach(page => {
if ((url[0] == "" ? "home" : url[0] ?? "home").toLowerCase() == page.name) {
if (url.length == 1 || (url.length == 2 && url[1] == "")) {
page.publish(res);
}
}
});
}
});
So, in Pages.html, you have this:
<script type="text/javascript" src="/assets/js/Pages.js"></script>
That looks like it would generally be compatible with your express.static() statement (shown below) to load Pages.js from your assets/js folder:
app.use("/assets", express.static(path.join(__dirname, "assets")));
But, then that Pages.js script immediately starts out with this:
import Page from '../../Page.js';
That will not work when requested by the browser. Remember paths in import statements from Javascript running in the browser are relative to the current URL of the web page. The browser will attempt to combine that relative URL with the URL of the web page and then make a request to your server for that newly constructed URL.
In this case, you'll end up with something like a request for http://somehost/../../Page.js. But, you don't have any route in your server that will handle that. By default express.static() skips any routes that contain ../ because that can be a nasty security issues (allowing attackers to fetch things around your server file system). So, you'll probably end up with a 404 error when trying to fetch that file.
ALL files you want the browser to be able to load, including imports embedded within other JS files must be in your public assets folder (or some other folder you've explicitly enabled public access to with something like express.static()).
FYI, if you look in the browser console, you probably see error messages that would have indicated to you where to look for the error.
__dirname is an environment variable that tells you the absolute path of the directory containing the currently executing file. You have to make sure that the final bundle (your asset folder) is present in that directory. Try to hard code the assets absolute path, if it works then use the below snippet instead:-
app.use("/assets", "express.static(process.cwd() + '/assets'));

How to tackle redirect to an external url in NextJS?

I have in place my next.config.js file with regular redirect rules, all within the same domain and all works fine. But in a specific case, I need to redirect the request from a certain URL (mydomain.com/abc) to a different domain. i.e differentdomain.com
How do I go about creating this rule to redirect to an external link in NextJs?
I appreciate any insight.
The latest version of Next.js has this built in using the next.config.js script (see https://nextjs.org/docs/api-reference/next.config.js/redirects). No need for additional plugins.
To test, copy the NextJs sample app:
npx create-next-app nextjs-blog --use-npm --example "https://github.com/vercel/next-learn-starter/tree/master/learn-starter"
Add a next.config.js file to the root folder with the following code:
// this simply tests the redirecting of the root path (source)
module.exports = {
async redirects() {
return [
{
source: '/',
destination: 'https://stackoverflow.com/posts/66662033',
permanent: false,
basePath: false
},
]
},
};
When you start the app npm run dev and visit localhost:3000, it should redirect to the destination URL specified in the next.config.js script (https://stackoverflow.com/posts/66662033).
Nextjs-redirect library should do what you want
You can try using window.location
Here's an example in which upon visiting a page it redirects the user to external url
// pages/redirect
import {useEffect} from 'react'
export default function redirect() {
useEffect(() => {
window.location.assign('https://duckduckgo.com/')
})
return(
<>
</>
)
}

Handle missing dynamic chunks after new deployment with Webpack

I have an AngularJs (1.7) SPA with Webpack (4.x).
This is how we create chunknames:
config.output = {
path: PATHS.build,
publicPath: '/dist/',
filename: `[name]${isDev ? '' : '.[contenthash:8]'}.bundle.js`,
chunkFilename: `chunks/[name]${isDev ? '' : '.[contenthash:8]'}.chunk.js`
};
The lazyloading is done in the state definitions in ui-router basically like this:
$stateProvider
.state('reports', {
url: '/projects/:project_id/reports',
lazyLoad: function($transition$) {
const injector = $transition$.injector().get('$injector');
return import(/* webpackChunkName: "admin.reports.module" */ './reports')
.then(mod => {
injector.loadNewModules([mod.default]);
})
.catch(err => {
throw new Error('An error occured, ' + err);
});
}
})
After a deployment due changes to a module in a "dynamic" chunk - the filename will change of this chunk ([contenthash] has changed).
When a logged in user (where all bundled assets are loaded before the last deployment) now tries to open a route with the new chunk - the chunk is not there (404) and it will fail with:
Transition Rejection($id: 4 type: 6, message: The transition errored, detail: Error: An error occured, Error: Loading chunk 14 failed.
(error: admin.reports.module.8fc31757.chunk.js))
Is there a common way to circumvent/deal with this?
Maybe more in general: How can changes to a bundled web app be detected? Is there a common way to trigger a reload? Is a manual refresh always neccessary?
I think there are a few ways to circumvent this, since the javascript in the current context isn't aware of the new hash of the content generated by the latest build you could try:
1.) You could try setting up an http redirect on the hashed files: https://developer.mozilla.org/en-US/docs/Web/HTTP/Redirections
The browser will request the old file and the server can point to the new file instead of returning 404. If all of your files follow a convention and only store one of the file at a time ex: component.hash.js then this should be pretty easy.
2.) A hacky client approach would be handling the transition-rejection in a try catch and reload the page, without the cache to get the new assets. https://developer.mozilla.org/en-US/docs/Web/API/Location/reload
There's always more than one approach, but this is what I could think of to solve the issue.

Categories