Next JS Images after next build gives 404 images - node.js

Default URL structure is http://localhost:5000/_next/image?url="someURL".
I want the URL to be like http://localhost:5000/demo/_next/image?url="someURL".
which can be achieved by
// next.config.js
images: {
domains: ['example.domain.com'],
path: `/demo/_next/image`
},
In this, the _next/image where the directory is pointing cannot be found.
After this, all the images are giving 404. I need a solution to this problem in the next js.

Have you tried to create a middleware to rewrite those routes to the correct location?
Something like:
pages/_middleware.ts with content:
import { NextRequest, NextResponse } from 'next/server';
export function middleware(req: NextRequest): NextResponse {
if (req.nextUrl.href.includes('/demo/_next/image'))
return NextResponse.rewrite(
req.nextUrl.href.replace('/demo/_next/image', '/_next/image'),
);
return null;
}

Related

NextJS dynamic route not working with mongoose

I've build a NextJS blog and want to write backend with NodeJS/Express for that blog to run in my local and then my own server.
And I wanted to use MongoDB/Mongoose to fetch blog posts data in my local.
I've created [slug].js file to show single blog post in my /posts/ directory.
In my index.js pages, I could achieve fetching all the posts data from my local and show all the blog titles without an error. So getStaticProps function working correctly with my mongoose.
But the problem is when i click the single post link in index page, i can't go to single blog post.When i click the link, nothing happens.
Also if i make a get request to single post page from postman application. No response is coming.
Instead of using my own database, i put some data top of the [slug].js page and i could use that data as a db succesfully.
Also if i copy the getStaticProps or getStaticPaths function from [slug].js file to another file to test. I can still receive the data from db.
Only in [slug].js file and only when i use my local db; single post page does not working.
Here is my [slug].js file:
import PostModel from "../../backend/models/PostModel";
export async function getStaticPaths() {
// Return a list of possible value for slug
const allPostData2 = await PostModel.find();
const paths = allPostData2.map((post) => {
return { params: { slug: post.slug } };
});
return {
paths,
fallback: false,
};
}
export async function getStaticProps(context) {
// Fetch necessary data for the blog post using params.slug
const slug = context.params.slug;
const myPost2 = await PostModel.find({ slug: slug });
return {
props: {
post: myPost2,
},
};
}
export default function PostPage({ post }) {
return (
<div>
<div>{myPost.title}</div>
<div>This is a single post page</div>
</div>
);
}
Here is the github repo for the project,any help would be greatly appreciated:
https://github.com/hakanolgun/try-next-blog

How can I properly create redirects from an array in Gatsby

I am working with Gatsby and WordPress. I am trying to redirect some URLs using the Gatsby redirect API. I write the query to get an Object and then I use the Map method to create an array of the items we need from that object. I then run a for Each method to get the individual data from that array but it fails on running the development server.
What is the Right way to do this?
const { createRedirect } = actions;
const yoastRedirects = graphql(`
{
wp {
seo {
redirects {
format
origin
target
type
}
}
}
}
`)
const redirectOriginUrls = yoastRedirects.wp.seo.redirects.map(redirect=>(redirect.origin))
const redirectTargetUrls = yoastRedirects.wp.seo.redirects.map(redirect=>(
redirect.target
))
redirectOriginUrls.forEach(redirectOriginUrl=>(
redirectTargetUrls.forEach(redirectTargetUrl=>(
createRedirect({
fromPath: `/${redirectOriginUrl}`,
toPath: `/${redirectTargetUrl}`,
isPermanent: true
})
))
))
The createRedirect API needs to recieve a structure like:
exports.createPages = ({ graphql, actions }) => {
const { createRedirect } = actions
createRedirect({ fromPath: '/old-url', toPath: '/new-url', isPermanent: true })
createRedirect({ fromPath: '/url', toPath: '/zn-CH/url', Language: 'zn' })
createRedirect({ fromPath: '/not_so-pretty_url', toPath: '/pretty/url', statusCode: 200 })
// Create pages
}
In your case, you are not entering to the correct fetched data. Assuming that the loops are properly done, you must do:
let redirectOriginUrls=[];
let redirectTargetUrls=[];
yoastRedirects.data.wp.seo.redirects.map(redirect=>{
return redirectOriginUrls.push(redirect.origin)
});
yoastRedirects.data.wp.seo.redirects.map(redirect=>{
return redirectTargetUrls.push(redirect.target)
})
Instead of:
const redirectOriginUrls = yoastRedirects.wp.seo.redirects.map(redirect=>(redirect.origin))
const redirectTargetUrls = yoastRedirects.wp.seo.redirects.map(redirect=>(
redirect.target
))
Notice the .data addition in the nested object.
In addition, keep in mind that the createRedirect API will only work only when having a hosting infrastructure behind, like AWS or Netlify, both have plugins integration with Gatsby. This will generate meta redirect HTML files for redirecting on any static file host.

why am I getting favicon.ico when i am using findOne method for express params routes?

when i am using list.save() method a object other than customList name which is favicon.ico is also
saving as record in following cod, Why am i gatting favicon.ico as object.
app.get('/:listRoute',function (req,res) {
const customList=(req.params.listRoute);
List.findOne({name:customList }, function (err,result) {
if (!err) {
if (!result) {
const list=new List({
name: customList,
items: defaultItems
})
list.save();
} else {
console.log(result);
res.render('list', {
listTitle: result.name,
latestItems: result.items})
}
}
});
})
When you visit a website (any URL on that website), a browser will typically also send a request to that same domain for /favicon.ico so see if the web site offers an icon to be a visual representation of the site.
Since you are using a wildcarded top level route:
app.get('/:listRoute', ...)
That will get hit by the request for /favicon.ico. Some other urls you also may need to watch out for being requested are: /robots.txt, /humans.txt, /sitemap.xml, /ads.txt.
There are a number of ways to work around this:
Your wildcard route can first check req.url or req.params.listRoute to see if it's something it should ignore.
You can place other top level routes that you want to keep out of your wildcard route in a position before this route so they don't end up in this one.
Don't use a top level wildcard route. Instead, use something like /list/:listRoute so it won't automatically match any top level http request. Your use of a top level wildcarded route interferes with other future uses of your site and can create backwards compatibility going forward when you want to add other top level routes to your site. Imagine if sometime in the future, you want to add /contact or /login or /logout. Those all conflict with /:listRoute.
Try to add a callback function to the list.save();
Let me know if this works. The reason is maybe because of sync issues. eg: time taken by mongoDB to update the first document & save > the time taken by the 'Get' method to redirect to itself. Therefore by adding this callback it kinda make sure the code gets saved first and err checked before the redirect.
eg:
list.save(function(err){
if(!err) {
console.log("list is successfully saved"); //log is optional
res.redirect("/" + listRoute);
}
});
When fetching route data using params with express,the entered data easily we can log.But if not adding top-level route and just trying to get the required route eg:
app.get("/:requireddata",function(req,res){
const data = req.params.requireddata;
});
in this case, when loading main page the favicon.ico will generate as a result.
So for getting an exact result, that's when only loading requireddata route we can get the result by using higher level route.
In case there is no higher-level route add just an additional route before requireddata as shown below:
app.get("/add/:requireddata",function(){});
Here /add/ is an additional route for avoiding favicon.ico
For me this worked, so if this information is useful just go head.
Hey there I also came across this exact issue.
So here is my solution to that.
Just enclose everything in a if block and there you go. DONE !!!!
app.get("/:name", function (req, res) {
if (req.params.name != "favicon.ico") {
const name = _.capitalize(req.params.name);
List.findOne({ name: name }, (err, foundList) => {
if (!err) {
//new list with default items created
if (!foundList) {
const list = new List({
name: name,
items: defaultItems,
});
list.save();
res.redirect("/" + name);
} else {
res.render("list", {
listTitle: foundList.name,
newListItem: foundList.items,
});
}
}
});
}
});
P.s.:- It will throw some error from mongo but that'll not affect the overall working.
Hope this helps.

Nuxt: can't use beforeCreate or beforeMount to check data or redirect

I want to have the following in my nuxt page:
beforeCreate() {
if (!this.$store.getters['experiences/current']) {
this.$router.push('/experiences');
}
},
Not 100% sure if I should use beforeCreate or beforeMount but the idea is, if the experiences/current getter is empty, go to the index page.
If I console.log(this.$store.getters['experiences/current']) it is actually empty, but the redirect doesn't happen and a template rendering error rises because it relies on this.$store.getters['experiences/current'].
So how can I make data validation before first component render and redirect if data is not present?
You can use a js middleware instead ...
For ts implementation ...
import { Middleware } from '#nuxt/types'
const myMiddleware: Middleware = ({ store, redirect }) => {
if (!store.state.applicationState && !store.state.yourProperty) {
return redirect('/')
}
}
export default myMiddleware

Vue SSR serverPrefetch server redirect with this.$ssrContext.res.redirect

Is it possible to do a redirect from a component, in VUE SSR, without getting the error on the server console: [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client?
Code is as follows:
serverPrefetch() {
// need the data from this.fetchPage service to decide on the redirect
return this.fetchPage().then(function (response) {
// do some checks here
// THIS IS THE NODE EXPRESS REDIRECT
this.$ssrContext.res.redirect('/');
this.$ssrContext.res.end(); // with or without, same error
}.bind(this));
},
beforeMount() {
this.fetchPage();
}
NOTE: If I try to use this.$router.replace('/') (or any other methods), I get the error: [Vue warn]: Error in callback for watcher $route: ReferenceError: document is not defined.
In my project I did the redirect on the client side, but I was wondering if this can be done also from server.
TL;DR:
Reject the serverPrefetch with {url: '/redirect-route'}
Found the solution as follows: If you implement the vue-ssr project as the https://github.com/vuejs/vue-hackernews-2.0 repo, in server/index.js you have a handleError function that has a redirect in it:
if (err.url) {
res.redirect(err.url);
}
And all you need to do in your component is:
serverPrefetch() {
return this.fetchPage().then(res => {
if(res === 'MY_REDIRECT_CONDITION') {
// !!! THE ACTUAL REDIRECT TRIGGER !!!
return Promise.reject({url: '/'});
}
});
},

Resources