1

I'm trying Nuxt because I need an app that create routes with data from an API.

For my example I got a fake data by using "nuxt/content" and I got 2 companies inside:

[
  {
   "id": "1",
   "name": "company1"
  },
  {
   "id": "2",
   "name": "company2"
  }    
]

With that, I would like to generate 2 routes so (because I got 2 companies):

  • /company1
  • /company2

Everytime a new company will be added in the API, I want that Nuxt create a new route.

I tried with static mode and generate function in nuxt.config.js with success. But in static mode, I have a generate static files every time a new data is added in the API.

Here what I did for static mode:

nuxt.config.js file:

export default {
  target: 'static',
  generate: {
    async routes() {
    const { $content } = require('@nuxt/content')

     const files = await $content('companies').fetch()
     return files.map(company => {
       return {
         route: '/' + company.name,
         payload: company
       }
     })
   }
},

_slug.vue file (in pages folder):

<template>
  <div>
    <h1>test</h1>
    <p>Path: {{ $route.path }}</p>

    data : {{ company }}
  </div>
</template>

<script>
  export default {
    asyncData({ payload }) {
      if (payload) return { company: payload}
      else {
        return '-1'
      }
    },
    mounted() {
      console.log(this.$router)
    }
  }
</script>

This solution worked great in Static because I saw the generated routes in the console and in the dist folder.

But I think I need the SSR solution to not to have to re-generate the static files all the time and re-upload them.

I didn't find the way to do that, I tried to only remove the "target: 'static'" from the nuxt.config file but the routes aren't generated (or I don't event know where to look to check if it's working). I have see only "_slug" and "index" route if I check the console.log(this.$router). Same if I check the dist folder (and routes.json file).

How do I do that in SSR mode? And will I be a good solution for the SEO?

kissu
  • 40,416
  • 14
  • 65
  • 133
Jer
  • 183
  • 3
  • 13

1 Answers1

1

Final answer after some tries and debugging

This is how the page /pages/users/_id.vue should look like

<template>
  <div>
    <div v-if="user">User name: {{ user.name }}</div>
  </div>
</template>

<script>
export default {
  async asyncData({ $axios, params }) {
    console.log('user ID >>', params.id)
    const user = await $axios.$get(`https://jsonplaceholder.typicode.com/users/${params.id}`)
    return { user }
  },
}
</script>

This is as simple to have something working as that, when you're using target: server.
You'll notice that each time your enter a different url manually, you'll see a console.log on your server. This proves you that the code there is generated on runtime on your Node.js server.


You probably took inspiration from Nuxt's content Programmatic Usage and from Nuxt's generate ~ Speeding up dynamic route generation with payload documentations.

So, you're totally doing it well! You've experienced the target: static approach.
Just to be clear, the behavior is totally fine here and this is how this is supposed to work.

If you want to have it generated each time on the server, you will need to set target: server (default value) and build your app with yarn build (rather than yarn generate for the target: static counterpart).

One more thing to know, is that you will need to have a Node.js server running. Hence, host it on some VPS or Heroku. If you want to take this route, you can find a tutorial on how to host there just here.

For SEO, this one will pretty much be as good. The biggest downside is that you need to pay for a server.
I'm not sure if target: static cannot be a solution still because platform like Vercel and Netlify are offering it for free, but I guess that your use-case (build time?) is maybe not suited for this approach.


A serverless-generation on the fly solution is coming in the next few weeks/months, called Nitro (not available as of today tho).

kissu
  • 40,416
  • 14
  • 65
  • 133
  • Thanks for your answer. I tried to set target: 'server'. But I can't get the payload on my _slug file. So it says "Property or method "company" is not defined on the instance but referenced during render..." Plus, if I make a "npm run build", I don't find any route with "/company1" for example. (It worked with static mode). – Jer Jul 25 '21 at 16:56
  • One thing to note is that you don't have any nested routes so far, you're doing it on the root directory, no? You should probably have it as `/companies/1` or `/company/2`. You can maybe take inspiration from one of my previous answers: https://stackoverflow.com/a/68431975/8816585 Meanwhile, if it does work with `static`, it should work with `server` too. What does it say when you're building it locally? Any errors? – kissu Jul 25 '21 at 17:01
  • I don't have any nested route, no. I made a "fast" test by just creating a "_slug.vue" file in the "pages" folder. So I can access to localhost:3000/company1 or localhost:3000/company2. It worked on statics yes. And I don't have any error with the build command. – Jer Jul 25 '21 at 17:21
  • I tried with a /company/ route also, with slug.vue inside. And I edited the returned route in the nuxt-config file to : route: '/' + company.name. Still doesn't work. I also added a console.log just on the top in the "async routes()" function. The console.log doesn't event trigger. Is that normal? – Jer Jul 25 '21 at 17:28
  • You should have the `console.log` server side. Also, do you have a [repro]? Did my answer helped? Gave it a look? – kissu Jul 25 '21 at 17:42
  • Yes gave a look and i tried to use axios with an external API and nothing comes ... How can I created fastly a minimal reproducible example? (I have never did that). Can I just push on a github? It's a fresh project – Jer Jul 25 '21 at 17:53
  • @jer codesandbox is nice for this, but here a Github link will be enough IMO. – kissu Jul 25 '21 at 18:08
  • I'm sorry, i don't know yet how to use codesandbox, I will check it out in the future. You can check it here (thank you so much if you can take a look) : https://github.com/jervalles/nuxttest1 .You can just pull, npm i, and try to go on http://localhost:3000/company/Leihia (I have put the API url in the project). Edit, whoa! it's so easy to do: https://codesandbox.io/s/epic-https-kcycx?file=/pages/index.vue – Jer Jul 25 '21 at 18:20
  • I edited the sandbox, I changed route: `/company/${company.id}`, to route: `/company/${company.name}`, in nuxt-config.js (I forgot to remove id, becase it was a test) – Jer Jul 25 '21 at 18:35
  • 1
    @jer Alright, my bad. I've read it again and tested it out and it clearly says: `As of Nuxt v2.13 there is a crawler installed that will crawl your link tags and generate your routes when running nuxt generate`. So, the `generate.routes` is only taken into account when you do `yarn generate`. If we think about it, it's true that there is no point into generating this ahead of time because it will still be done on runtime when the user will reach the Node.js server anyway. If you want to have the company/API info, you can simply make it into the component directly. Submitted a PR on top of edit – kissu Jul 25 '21 at 20:48
  • 1
    alright I guess there is no way to do that with the approach initlialy made. Thanks! So, in case i would like to do like welcometothejungle.com, for example like this company url: (https://www.welcometothejungle.com/fr/companies/zapp), I have to create a "companies" folder with "_name.vue" inside that fetch company by name (from my API). Will be it ok with SEO? I mean how can google will now that there are companies named like "zapp", "ingie" etc ... because I use slugs, there is no way that the server will now the list of all companies. Am I right? Thanks again! – Jer Jul 25 '21 at 21:51
  • 1
    To go to a `/companies/zapp` path, you'll need a index listing all of them. You cannot go to a page if there is no index listing all of them. But you'll of course have the index. Google will be able to follow all of those dynamic `_name` paths thanks to the index (this is how Web in general works). Another thing, is that you can inspect the source code, if you see the name of your company there (either on details page or in the index of all of them), bingo! The only requirement is `ssr: true`, the `target` is not a big deal, it just dictates when the SSR'ed content will be generated. – kissu Jul 25 '21 at 22:01