Как хранить динамически сгенерированные маршруты nuxtjs в магазине vuex

Я пытаюсь использовать возможности Nuxtjs SSG, создавая статический веб-сайт, на котором содержимое страниц и навигация извлекаются из API.

Я уже нашел способ динамически генерировать маршруты, определив модуль, в котором я использую крючок для получения содержимого и маршрутов страниц. При создании маршрутов я сохраняю содержимое страницы как полезную нагрузку маршрута. Следующий код делает именно это и работает по назначению.

      modules/dynamicRoutesGenerator.js

const generator = function () {
  //Before hook to generate our custom routes
  this.nuxt.hook('generate:before', async (generator, generatorOptions) => {
    generator.generateRoutes(await generateDynamicRoutes())
  })
}

let generateDynamicRoutes = async function() {
  //...
  return routes
}

export default generator

Теперь проблема, с которой я столкнулся, заключается в том, что у меня есть некоторые компоненты навигации, которым нужны сгенерированные маршруты, и я думал сохранить их в хранилище vuex.

Я попробовал но я не знаю, как получить оттуда контекст хранилища vuex. В конечном итоге я использовал действие, потому что, как указано в документации:

      If nuxt generate is ran, nuxtServerInit will be executed for every dynamic route generated.

Это именно то, что мне нужно, поэтому я пытаюсь использовать его со следующим кодом:

      store/index.js

export const actions = {
  nuxtServerInit (context, nuxtContext) {
    context.commit("dynamicRoutes/addRoute", nuxtContext)
  }
}

store/dynamicRoutes.js

export const state = () => ({
  navMenuNivel0: {}
})

export const mutations = {
  addRoute (state, { ssrContext }) {
    //Ignore static generated routes
    if (!ssrContext.payload || !ssrContext.payload.entrada) return
    //If we match this condition then it's a nivel0 route
    if (!ssrContext.payload.navMenuNivel0) {
      console.log(JSON.stringify(state.navMenuNivel0, null, 2));
      //Store nivel0 route, we could use url only but only _id is guaranteed to be unique
      state.navMenuNivel0[ssrContext.payload._id] =  {
        url: ssrContext.url,
        entrada: ssrContext.payload.entrada,
        navMenuNivel1: []
      }
      console.log(JSON.stringify(state.navMenuNivel0, null, 2));
      //Nivel1 route
    } else { 
      //...
    }
  }
}

export const getters = {
  navMenuNivel0: state => state.navMenuNivel0
}

Действие действительно вызывается, и я получаю все ожидаемые значения, однако похоже, что при каждом вызове хранилища состояние сбрасывается. Я распечатал значения в консоли (потому что я не уверен, даже если это можно отладить), и вот как они выглядят:

      {}                                                                                                                                                                                                                     
{                                                                                                                                                                                                                      
  "5fc2f4f15a691a0fe8d6d7e5": {
    "url": "/A",
    "entrada": "A",
    "navMenuNivel1": []
  }
}
{}                                                                                                                                                                                                                     
{                                                                                                                                                                                                                     
  "5fc2f5115a691a0fe8d6d7e6": {
    "url": "/B",
    "entrada": "B",
    "navMenuNivel1": []
  }
}

Я искал все, что мог по этому поводу, и хотя я не нашел примера, похожего на мой, я собрал все части, которые мог, и это то, что я придумал.

Моя идея заключалась в том, чтобы сделать только один запрос к API (во время сборки), сохранить все в vuex, а затем использовать эти данные в компонентах и ​​страницах.

Либо есть способ сделать это лучше, либо я не совсем понимаю действие. Я застрял и не знаю, как решить эту проблему, и не вижу другого решения.

Если вы дошли до этого места, спасибо за уделенное время!

1 ответ

Решение

I came up a with solution but I don't find it very elegant.

The idea is to store the the API requests data in a static file. Then create a plugin to have a $staticAPI object that expose the API data and some functions.

I used the build:before hook because it runs before generate:before and builder:extendPlugins which means that by the time the route generation or plugin creation happen, we already have the API data stored.

dynamicRoutesGenerator.js

      const generator = function () {
  //Add hook before build to create our static API files
  this.nuxt.hook('build:before', async (plugins) => {
    //Fetch the routes and pages from API
    let navMenuRoutes = await APIService.fetchQuery(QueryService.navMenuRoutesQuery())
    let pages = await APIService.fetchQuery(QueryService.paginasQuery())
    //Cache the queries results into staticAPI file
    APIService.saveStaticAPIData("navMenuRoutes", navMenuRoutes)
    APIService.saveStaticAPIData("pages", pages)
  })
  
  //Before hook to generate our custom routes
  this.nuxt.hook('generate:before', async (generator, generatorOptions) => {
    console.log('generate:before')
    generator.generateRoutes(await generateDynamicRoutes())
  })
}

//Here I can't find a way to access via $staticAPI
let generateDynamicRoutes = async function() {
  let navMenuRoutes = APIService.getStaticAPIData("navMenuRoutes")
  //...
}

The plugin staticAPI.js:

      import APIService from '../services/APIService'

let fetchPage = function(fetchUrl) {  
  return this.pages.find(p => { return p.url === fetchUrl})
}

export default async (context, inject) => {
  //Get routes and files from the files
  let navMenuRoutes = APIService.getStaticAPIData("navMenuRoutes")
  let pages = APIService.getStaticAPIData("pages")
  //Put the objects and functions in the $staticAPI property
  inject ('staticAPI', { navMenuRoutes, pages, fetchPage })
}

The APIService helper to save/load data to the file:

      //...
let fs = require('fs');

let saveStaticAPIData = function (fileName = 'test', fileContent = '{}') {
  fs.writeFileSync("./static-api-data/" + fileName + ".json", JSON.stringify(fileContent, null, 2));
}

let getStaticAPIData = function (fileName = '{}') {
  let staticData = {};

  try {
      staticData = require("../static-api-data/" + fileName + ".json");
  } catch (ex) {}

  return staticData;
}

module.exports = { fetchQuery, apiUrl, saveStaticAPIData, getStaticAPIData }

nuxt.config.js

      build: {
  //Enable 'fs' module
  extend (config, { isDev, isClient }) {
     config.node = { fs: 'empty' }
  }
},
plugins: [
  { src: '~/plugins/staticAPI.js', mode: 'server' }
],
buildModules: [
  '@nuxtjs/style-resources',
  '@/modules/dynamicRoutesGenerator'
]
Другие вопросы по тегам