Nuxt 404 error page should redirect to homepage - vue.js

I am looking for a way to always redirect to homepage when a page doesn't exist using Nuxt.Js.
Our sitemap generation had some problems a few days back and we submitted wrong urls that do not exist. Google Search Console shows a big number of 404 and we want to fix them with 301 redirect to homepage.
I tried this
created() {
this.$router.push(
this.localePath({
name: 'index',
query: {
e: 'er'
}
})
)
}
and although the page redirects to homepage successfully I think Google will have problems with this since the pages initially renders with 404.
I also tried this
async asyncData({ redirect }) {
return redirect(301, '/el?e=rnf')
},
but didn't work (same with fetch)
Any ideas on a solution to this?

Never redirect to home if page is not found as you can see in this Google's article: Create custom 404 pages
instead, redirect to 404 error page
Just use error
async asyncData({ params, $content, error }) {
try {
const post = await $content('blog', params.slug).fetch()
return { post }
} catch (e) {
error({ statusCode: 404, message: 'Post not found' })
}
}
do not forget to creat an error page in layout folder error.vue

You are able to create a default 404-page in nuxt - just put a file with a name _.vue in your ~/pages/ dir. This is your 404-page :)
or you can use another method to create such page: https://github.com/nuxt/nuxt.js/issues/1614 but I have not tried it
Then add a simple 404-redirect-middleware to this page:
// !!! not tested this code !!!
middleware: [
function({ redirect }) {
return redirect(301, '/el?e=rnf')
},
],

Personally I would advise to create a 404 page which provides a better user experience in comparison to being redirected to a homepage and potentially being confused about what happened.
In order to create a custom error page, just create error.vue file in the layouts folder and treat it as a page. See the official documentation. We've implemented this plenty of times and Google has never complained about it.
Still, gleam's solution is clever and if it serves the purpose, very well. Just wanted to point out another solution.

If you need to provide custom routes to your users like domain.com/<userID>
then putting a file with a name _.vue in your ~/pages/ directory will not work, because you'll need it for your custom user routes.
For maximum flexibility use the layouts folder as mentioned by Dan

Create a file called _.vue at pages directory with content:
<script>
export default {
asyncData ({ redirect }) {
return redirect('/')
}
}
</script>

Related

How to redirect if subdirectory includes hash Nuxt?

At the request of the SEO specialist, I need to implement the following functionality.
I have to redirect if the link contains a capital letter.
For example https//domain.com/#Contacts ==> https//domain.com/#contacts.
In Nuxt I implemented with by creating function on server.js file which located on middleware folder.
But it doesn't work if path contains hash(#)
export default function (req, res, next) {
const url = req.url;
if (url !== url.toLowerCase()) {
res.writeHead(301, { Location: url.toLowerCase() });
res.end()
} else {
next();
}
}
I would be grateful if you answer or help
The part after the hash (fragment identifier) is never going to be sent to the server by your browser, so what you're trying to do is impossible using redirects.
You can access them on the client-side, but I don't think that it would do any good in terms of SEO.

How to manually generate pages in Nuxt router with a 404 page fallback for .htaccess

I'm trying to create an SSG site with Nuxt.js.
When I access a route that isn't set in the generate property of nuxt.config.js,
I want to display the contents of a 404 page without changing the URL.(using htaccess)
The following is the site under construction
http://we-are-sober.d3v-svr.com/xxxx
This is working as expected.
http://we-are-sober.d3v-svr.com/user/xxxx
This does not work as expected.
The contents of page 404 are displayed for a moment, but soon after that, the process based on the dynamic route of "user/_id.vue" is executed.
The point of the problem is that the non-existent route behaves as if it exists.
Does anyone know how to solve this problem?
Here is the source code.
https://github.com/yhirochick/rewrite_test
404.vue
https://github.com/yhirochick/rewrite_test/blob/master/pages/404.vue
user/_id.vue
https://github.com/yhirochick/rewrite_test/blob/master/pages/user/_id.vue
nuxt.config.js
https://github.com/yhirochick/rewrite_test/blob/master/nuxt.config.js#L43-L45
.htaccess
https://github.com/yhirochick/rewrite_test/blob/master/static/.htaccess
I am Japanese. The above text is based on Google Translate.
It may be difficult to understand, but thank you.
My way of handling this kind of issue while minimizing the API calls required are following those steps:
generate a brand new Nuxt project
install axios: yarn add -D axios
add this to the nuxt.config.js file
import axios from 'axios'
export default {
...
generate: {
routes: async () => {
const users = await axios.get('https://jsonplaceholder.typicode.com/users')
return users.data.map((user) => ({
route: `/users/${user.id}`,
payload: user,
}))
},
fallback: 'no-user.html', // this one is not needed anymore if you ditch the redirect!
},
}
This will generate all the needed routes, while keeping the calls to a minimum thanks to payload that will be passed later on to the pages. More info can be found in the docs.
then, creating the /pages/users/_id.vue page does the trick
<template>
<div>
<div v-if="user">User name: {{ user.name }}</div>
<div v-else-if="error">{{ error }}</div>
</div>
</template>
<script>
export default {
asyncData({ payload }) {
if (payload && Object.entries(payload).length) return { user: payload }
else return { error: 'This user does not exist' } // this will also catch users going to `/users/`
},
}
</script>
create some no-user.vue page, error.vue layout and you should be gucci
At the end, we have 10 users from the mocked API. So those are the following cases:
if we go to /users/5, the user is already static so we do have it's info without any extra API call
if we go to /users/11, the user was not present at the time of build, hence he is not here and we are displaying an error
if we go to /users, we will still be sent to the /pages/users/_id page, but since the :id will be optional there, it will error and still display the error, an index.vue can of course handle this case
My github repo for this one can be found here: https://github.com/kissu/so-nuxt-generate-placeholder-users
This approach is called full static in Nuxt, as explained here: https://nuxtjs.org/announcements/going-full-static/
It's a tricky way, but I've found the code that works as I want.
https://fes.d3v-svr.com/users/xxxxxx
It's works that I expect.
User xxxxxx doesn't exist
Display 404 page
The URL /users/xxxxxx as it is
First, simply set .htaccess to rewrite non-exist page to 404 page
ErrorDocument 404 /no-user/index.html
Only above, Nuxt execute base on URL /users/xxxxxx/ and re-render the page as "UserXXXXXX" even he is not exist.
To avoid this, users/_id.vue is like bellow.
template
<template>
<div v-if="ssr">User name: {{ user.name }}</div>
</template>
script
<script>
export default {
asyncData({ payload }) {
return { user: payload, ssr:true }
},
}
</script>
It seems to be if a template is empty, nuxt will not execute the script depends on the URL.
It's very tricky, so I'll continue to how it is works.

Vue-Routes redirect doesn't work and beforeEnter render App component again

I'm getting some issues when trying to redirect to an external link.
for ex:
{ path: '*', redirect: 'https://google.com'}
when I use "redirect" it doesn't work completely, but when I use something like that
{ path: '/*',
beforeEnter(to, from, next) {
window.location = "https://google.com"
}
}
it works but there is a problem because first, it tries to render App component again but there is no component so be empty and a blank page is being rendered for nearly 1-1.5 second then it redirects to target URL and I don't want it to reload App component, just redirect it to other link. I googled but found nothing noteworthy.
Or maybe is there another way like deactive a component or use v-if or directly rendering a html file?
redirect is meant to redirect to another route defined by your application, not to go to another website directly.
window.location works, but I think the behavior is somewhat browser-dependent.

Nuxt - How can I run a code in client-side after server-side-rendering?

I created a plugin injecting a noty (https://ned.im/noty/#/) so I can use it globally, it looks like this:
export default ({ app }, inject) => {
const notify = function (options = {}) {
if (process.client) {
new Noty(options).show();
}
}
app.$notify = notify;
inject('notify', notify);
}
This plugin shows a noty only on the client-side. On the server-side a noty does not appear, cause it can be displayed only in browser.
I have a page with product details and I am receiving data in asyncData method. When the product was not found I would like to show a noty with proper message and redirect user to a product list page. When I change a route in client-side everything works awesome. However on the first page load (eg. I change an url manually in the browser) which happens on the server-side a noty does not appear, only a redirect works.
My question is: how to show a noty in this case? How to create a noty in the browser after SSR or what is the best other solution to my problem?
Is there any way to run some code after client-side is already rendered (after server-side-rendering)?
You could just disable ssr for that plugin.
plugins: [
...,
{ src: '~plugins/yourplugin.js', ssr: false }
]
Okay, I found a module for that: https://github.com/potato4d/nuxt-client-init-module
it's not possible right know (nuxt <= 2.14.0 when i answering)
but you can combine client plugin and client middleware to achieve that
please take a look at this link:
https://github.com/nuxt/nuxt.js/issues/2653#issuecomment-390588837

res.render for routes on page reload?

(Using MEAN with UI Router)
The following code sends a json response for the route defined. This works fine when the template is rendered with UI Router; however, if I reload the page, because the response only contains json, I am left with an empty page rendering no html, only the json response.
router.get('/posts/:post', function(req, res, next) {
req.post.populate('comments', function(err, post) {
if (err) { return next(err); }
res.json(post);
});
});
Assuming this is a standard issue, how can I best allow this page to res.render('index') when the page is reloaded and respond with the json response? Should I,
Create a separate route for the json response which is called as a post promise with UI Router
Have the /posts/:post route simply respond with res.render('index')?
Thank you for any responses, not sure what the usual practise is for such issues!
It took me a while to find a working solution to this due to many of the examples online having different directory structures. I placed a catch all at the end of my routes so that url requests to any UI Router states would not be met with a 404, but instead always return the index.html file.
app.all('/*', function(req, res, next) {
// Just send the index.html for other files to support HTML5Mode
res.sendFile('index.html', { root: __dirname });
});
Then I added prefixes to my express routes, e.g. /api/posts/:post etc. Apparently express routes should not clash with any of the angular defined routes. Thanks to NormySan on reddit for informing me about this.