I have a file under the pages folder named about.tsx. So the path for the page is /about and I'm able to access the page by visiting example.com/about. However, if I visit example.com/About, it will redirect to a 404 page.
I've checked the Nextjs repo, seems like this is the expected behavior. Therefore, is there a workaround that can make the path case insensitive so that example.com/About will also work and direct users to the /about page?
With using next v12
There are a lot of similar questions here that has this answer already. I'd like to note that this answer is handling redirecting with the url parameters by adding this after the pathname:
${request.nextUrl.search}
Add a new file in /pages named _middleware.ts
import { NextRequest, NextResponse } from "next/server";
export function middleware(request: NextRequest) {
if (request.nextUrl.pathname === request.nextUrl.pathname.toLocaleLowerCase())
return NextResponse.next();
return NextResponse.redirect(`${request.nextUrl.origin}${request.nextUrl.pathname.toLocaleLowerCase()}${request.nextUrl.search}`);
}
I agree that's Next.js's behavior, they only handle exact page name about instead of both about & About using the same file page/about.tsx
But the solution is you keep implementing a main page (e.g: about.tsx) and setup other pages to redirect to that page (e.g: About -> about) following this guide https://nextjs.org/docs/api-reference/next.config.js/redirects
// next.config.js
module.exports = {
async redirects() {
return [
{
source: '/About',
destination: '/about',
permanent: true,
},
]
},
}
// Set permanent:true for 301 redirect & clean SEO!
Related
I am using Next.JS application routing system.
I have created a dynamic route with structure like pages/[country]/[language]/index.js.
Also there is a static route with structure pages/cz/cz/index.js.
Issue appears then i am on static page and trying to navigate throught Link component to access static route content in my case should go to home page & reload same page, instead of that dynamic route content is rendered.
In my case link is just simple navigation to home page <Link to="/"> for both routes.
But maybe issue lies on how index.js file is setup for predefined & dynamic routes.
cz/cz/index.js
export { default } from '../../../components/HomePage/';
const { getStaticProps } = createRoute({
path: '/',
locale: 'cs',
});
export { getStaticProps };
[country]/[language]/index.js
export { default } from '../../../components/HomePage/v2';
const { getStaticPaths, getStaticProps } = createRoute({
path: '/',
exclude: ['cs'],
otherLocales: ['cs'],
});
export { getStaticPaths, getStaticProps };
createRoute
export default function createRoute({
path,
otherLocales,
getPathParams,
locale,
} = {}) {
const locales = _.without(include, ...exclude);
return {
getStaticPaths: createGetStaticPaths({
locales,
getPathParams,
}),
getStaticProps: createGetStaticProps({
path,
locale,
locales,
otherLocales,
}),
};
}
Pages structure
So why [country]/[language]/index.js overrides cz/cz/index.js ?
So is there anything available in nextJS route to match a URL absolutely?
Or insure that going from static route should go to static route?
Following next.js documentation predefined routes take precedence over dynamic routes, and dynamic routes over catch all routes.
Take a look at the following examples:
pages/post/create.js - Will match /post/create
pages/post/[pid].js - Will match /post/1, /post/abc, etc. But not /post/create
pages/post/[...slug].js - Will match /post/1/2, /post/a/b/c, etc. But not /post/create, /post/abc
In your case you have defined predefined routes cz/cz/index.js and this route have priority
If you happen to be using redirects, note that they are processed before next ever goes to the pages.
Redirects are checked before the filesystem which includes pages and /public files.
https://nextjs.org/docs/api-reference/next.config.js/redirects
I'm trying to create all my pages using NextJs with the slugs/uri I get when fetching the data, however when trying to create the home page it says.
Error: The provided path `/` does not match the page: `/[slug]`.
[slug].tsx is located in the page folder. I removed the index.js since I would like to have the home page the same page layout as other pages.
Currently getting the static paths like this:
export async function getStaticPaths() {
const allPages = await getAllPostsWithSlug();
return {
paths: allPages.edges.map(({ node }) => `${node.uri}`) || [],
fallback: true,
};
}
The error I got makes sense, but I couldn't really find a solution to create my home page in the same page template.
As per the documentation, you can use an optional catch-all route.
Name your page file [[...slug]].js, and then use something like the this for the paths prop in getStaticPaths:
paths: [
{ params: { slug: [] } },
{ params: { slug: ['foo'] } },
{ params: { slug: ['bar'] } },
]
FWIW - if you want to share components from the main template (i.e. header, nav, footer etc), I recommend using a custom _app.js page. If your homepage really is identical to your other pages, it might be worth re-visiting the design!
Good luck!
Since [...slug] is not the same as [slug] as it grabs sub-paths as well, you can achieve a closer match using just [slug].js and adding a rewrite to your next.config.js like so:
async rewrites() {
return [
{
source: '/',
destination: '/homepage',
},
]
},
Then you handle the homepage slug as your homepage, just like any other CMS page or post.
(/homepage can be anything you want, e.g. /index)
We have a vanilla Vue/Vite setup and I'm receiving TypeError: Failed to fetch dynamically imported module on sentry logs.
It seems like the errors are correlated in time with new deployment to prod, although I don't have enough data to confirm. It doesn't happen on local and appears only on deployed code.
I've seen some similar questions for react's setups, but none with a satisfactory response.
I've also found a similar question regarding dynamically imported svgs, but our errors happen for full components.
The only place where we use dynamic imported components is on routing:
export const router = createRouter({
history: routerHistory,
strict: true,
routes: [
{
path: '/',
name: routes.homepage.name,
component: () => import('#/views/Home.vue'),
children: [
{
path: '/overview',
name: routes.overview.name,
component: () => import('#/views/Overview.vue'),
},
// other similar routes
],
},
],
});
Our deps versions:
"vue": "^3.0.9",
"vue-router": "^4.0.5",
"vite": "^2.0.5",
Any additional information on this issue and how to debug it would be much appreciated!
When you dynamically import a route/component, during build it creates a separate chunk. By default, chunk filenames are hashed according to their content – Overview.abc123.js. If you don't change the component code, the hash remains the same. If the component code changes, the hash changes too - Overview.32ab1c.js. This is great for caching.
Now this is what happens when you get this error:
You deploy the application
Your Home chunk has a link to /overview route, which would load Overview.abc123.js
Client visits your site
You make changes in your code, not necessarily to the Overview component itself, but maybe to some children components that Overview imports.
You deploy changes, and Overview is built with a different hash now - Overview.32ab1c.js
Client clicks on /overview link - gets the Failed to fetch dynamically imported module error, because Overview.abc123.js no longer exists
That is why the errors correlate with deployments. One way to fix it is to not use lazy loaded routes, but that's not a great solution when you have many heavy routes - it will make your main bundle large
In my case the error was caused by not adding .vue extension to module name.
import MyComponent from 'components/MyComponent'
It worked in webpack setup, but with Vite file extension is required:
import MyComponent from 'components/MyComponent.vue'
I had the exact same issue. In my case some routes worked and some didn't. The solution was relatively easy. I just restarted the dev server.
The accepted answer correctly explains when this error is triggered but does not really provide a good solution.
The way I fixed this is by using an error handler on the router. This error handler makes sure that when this error occurs (so thus when a new version of the app is deployed), the next route change triggers a hard reload of the page instead of dynamically loading the modules. The code looks like this:
router.onError((error, to) => {
if (error.message.includes('Failed to fetch dynamically imported module')) {
window.location = to.fullPath
}
})
Where router is your vue-router instance.
My situation was similar.
I found that my Quasar setup works fine on the initial page but not page that are loaded dynamically through an import('../pages/page.vue');.
Short response:
I replaced import('../pages/TestPage.vue') in the middle of the route file by import TestPage from '../pages/TestPage.vue' at the top.
More detailed response:
In my situation I don't expect to have much pages, a single bundle with no dynamic loading is fine with me.
The solution is to import statically every page I need.
In my routes.ts I import all the pages I need.
import IndexPage from '../pages/IndexPage.vue';
import TestPage from '../pages/TestPage.vue';
Then I serve them statically in my routes :
const routes: RouteRecordRaw[] = [
{
path: '/',
component: () => import('layouts/MainLayout.vue'),
children: [
{ path: 'test', component: () => TestPage },
{ path: '', component: () => IndexPage }
],
},
// Always leave this as last one,
// but you can also remove it
{
path: '/:catchAll(.*)*',
component: () => import('pages/ErrorNotFound.vue'),
},
];
I recently expriencied this. The error was caused by an empty href inside an a tag: <a href="" #click="goToRoute">. You can either remove the href or change the a tag to something else, ie. button. Let me know if this helps.
I had the same problem. I found that I had not started my project.
I'm trying to catch routing exceptions in my app. Basically there are 3 ways a user can navigate:
Typing the address - catching that is easy just { path: '**', redirectTo: 'errorPage'} in the route config.
The code called router.navigate(['pageName']) - catching that is easy too: .then(res => res, error => {
//service to log error to server
router.navigate(['errorPage']);
});
Clicking an HTML element that has [routerLink]="somePath" attribute.
It's the third one that I don't know how to catch.
Presumably such an error could occur if the module didn't load for some reason. I need to be able to handle that (and other unforeseen events) gracefully.
TO CLARIFY
The wildcard definition works for router problems, in most cases. But here's the thing, what if there is a route defined earlier in the configuration, but it leads to a module that can't be found! (I actually had this error in develop, which is why I am aware that it can happen, we're using lazy loading, and it happened that with some network problems a required module didn't load). The router finds a route, and tries to resolve it, but can't because the module, for whatever reason, did not load. The wildcard definition doesn't help here, because the router found a path but can't reach it. So it throws an error, which I'm trying to catch. Because for some reason router errors choke the whole app.
Why not create fallback path in routing module?
const routes: Routes = [
{ path: '', component: HomeComponent },
{ path: '**', component: NotFoundComponent },
];
When user enter not existing url will be redirected to NotFoundComponent.
This { path: '**', redirectTo: 'errorPage'} is what is called the wildcard route definition, which Angular official doc defines as:
The router will select this route if the requested URL doesn't match any paths for routes defined earlier in the configuration. This is useful for displaying a "404 - Not Found" page or redirecting to another route.
So this should work for any case when the requested route doesn't match any of the defined routes (doesn't matter if it was typed or set). Check if the routerLink definition is correct because the definition for it is without the brackets: <a routerLink="/crisis-center" routerLinkActive="active">Crisis Center</a>
I'm building a filesytem based emberjs-app. But unfortunately the security won't allow me to push stuff to the history (see e.g. this but i guess that applies to all browsers).
setting the locationtype to none is fine, but I would still like to utilize the back and forward buttons and urls of the browser.
Is there a way to configure this (maybe setting the base-url to index.html, without rewriting the build process)?
edit
I call the url from my browser like this: file:///path/index.html.
in my routes.js and fileroute.js I've got this workaround:
// routes.js
export default Router.map(function() {
// this route only redirects to main
this.route('fileroute', {path: 'index.html'});
});
// routes/fileroute.js
// only for running app on filesystem
export default Ember.Route.extend({
redirect: function() {
this.transitionTo('fileroute.projects');
}
});
So I guess each hash-change would already effect the files-url
file:///path/#differentroute
also for
file:///path/#index.html/childRoute