So basically I'm setting up an app using nuxt, and within the configuration's generate property I need to run a recursive function to build the sites route tree dynamically. The function is rather large so I dont want it to be in the config file itself
Ive tried doing it this way, but think Im way off
import {buildChildRoutes} from 'routeGenerator'
export default {
generate: {
routes(){
var response = await this.$deliveryClient
.itemsFeedAll()
.toPromise();
return buildChildRoutes(response)
})
has anyone done something like this before? i would assume its common and im just missing something in the documentation
Here's the solution I used that works
This is my code in nuxt.config.js
import getRoutes from './utils/route-generator.js'
const dynamicRoutes = () => {
return new Promise((resolve) => {
resolve(getRoutes())
})
}
export default {
generate: {
routes: dynamicRoutes
}
}
Related
So I'm using vue-query to get data from my API. The current way I'm doing that looks a little like this. I have a folder in src called hooks, and it may contain a file such as usePosts.ts. That file contains code like this:
import { useQuery, useMutation, useQueryClient } from "vue-query"
import axios, { AxiosError } from "axios"
import {
performOptimisticAdd,
handleMutateSuccess,
handleMutateError,
} from "./handlers"
export interface Post {
id: number
title: string
body: string
user: number // user_id
}
export function usePostsListQuery() {
return useQuery<Post[], AxiosError>(
"posts",
() => axios.get("/v1/posts").then(resp => resp.data),
{ placeholderData: [] }
)
}
export function useAddPostMutation() {
const client = useQueryClient()
return useMutation<Post, AxiosError>(
post => axios.post("/v1/posts", post).then(resp => resp.data),
{
onMutate: performOptimisticAdd(client, "posts"),
onSuccess: handleMutateSuccess(),
onError: handleMutateError()
}
)
}
Of course I'm not showing all the code, for brevity.
Now in my Vue components, I'm often doing something like this:
<script setup>
import { usePostsListQuery, useAddPostMutation } from "#/hooks/usePosts";
import { useUsersListQuery } from "#/hooks/useUsers";
const { data: posts } = $(usePostsListQuery())
const { data: users } = $(useUsersListQuery())
const { mutate: addPost } = $(useAddPostMutation())
const postsWithUsers = $computed(() => posts.map(
post => ({ ...post, user: users.find(user => user.id === post.user) })
))
const addPostWithUserId = (newPost: Post) => addPost({ ...newPost, user: newPost.user.id })
</script>
Because I want to be able to directly access the user associated with a post. And of course, the way I'm doing it works. But it doesn't seem right to do that transformation inside a Vue-component. Because that means I need to repeat that same code inside every new Vue-component.
So I'm wondering what would be the best place to do this transformation. One obstacle is that useQuery() may only be called during / inside the setup() function. So I'm a bit limited in terms of where I'm allowed to call these queries.
Maybe I could just put it inside usePosts.ts? But is that really the best place? I can imagine that it might make all my hooks very messy, because then every hook suddenly has TWO responsibilities (talking to my API, and transforming the output and input). I feel like that breaks the single responsibility principle?
Anyhow, this is why I'd love to hear some of your opinions.
I want to create a plugin for Nuxtjs to log everything I want only in client mode, something like this :
// ~/plugins/client-log.js
export default ({ app }, inject) => {
app.clog = string => console.log(string)
}
This plugin is working in components where I have access to context for example:
export default {
fetch({app}){
app.clog("some string")
}
};
But I want to be able to use it inside vuex (actions, mutations...). How can I do that?
Thanks in advance.
You're so close, you just need to change one thing:
// ~/plugins/client-log.js
export default ({ app }, inject) => {
inject('clog', string => console.log(string))
}
Then you're able to call it like:
export default {
fetch({app}){
// Note: inject will automatically prefix with a "$"
app.$clog("some string")
},
mounted() {
// this.$clog can also be accessed within vuex
this.$clog("I'm in a component")
}
};
I am trying to implement CASL with vuex and Nuxt. I get an issue when trying to initialize ability's rules when my application starts and I am already logged in.
Basically, I would like to get the rules and updates the Ability instance when the app starts. However, when I try to get the rules from the store, it returns null. At the moment, I need to log out and log in to get the rules.
store/ability.js
import ability from '../config/ability'
export const updateAbilities = store => {
ability.update(store['users/getRules']) // this does not work and returns null
return store.subscribe(mutation => {
if (mutation.type === 'users/setRules') {
ability.update(mutation.payload)
}
})
}
config/ability.js
import { Ability } from '#casl/ability'
export default new Ability()
store/index.js
import { updateAbilities } from './ability'
export const plugins = [updateAbilities]
Thanks for your help.
I ended up by getting the rule from the Local Storage and it works.
import ability from '../config/ability'
export const updateAbilities = store => {
const vuexData = JSON.parse(localStorage.getItem('vuex'))
const rules = vuexData.users.rules
ability.update(rules)
return store.subscribe(mutation => {
if (mutation.type === 'users/setRules') {
ability.update(mutation.payload)
}
})
}
I'm building a project where all my data - including page routes - comes from a GraphQL endpoint but needs to be hosted via a static site (I know, I know. Don't get me started).
I've managed to generate routes statically from the data using the following code in nuxt.config.js:
generate: {
routes: () => {
const uri = 'http://localhost:4000/graphql'
const apolloFetch = createApolloFetch({ uri })
const query = `
query Pages {
pages {
slug
template
pageContent {
replaced
components {
componentName
classes
body
}
}
}
}
`
return apolloFetch({ query }) // all apolloFetch arguments are optional
.then(result => {
const { data } = result
return data.pages.map(page => page.slug)
})
.catch(error => {
console.log('got error')
console.log(error)
})
}
}
The problem I am trying to solve is that some pages need to use a different layout from the default, the correct layout to use is specified in the GraphQL data as page.template but I don't see any way to pass that information to the router.
I've tried changing return data.pages.map(page => page.slug) to:
return data.pages.map(page => {
route: page.slug,
layout: page.template
})
but that seems to be a non-starter. Does anyone know how to pass a layout preference to the vue router?
One way would be to inject the data into a payload
https://nuxtjs.org/api/configuration-generate#speeding-up-dynamic-route-generation-with-code-payload-code-
This will allow you to pass generate information into the route itself.
Do I need to use express with next.js?
Im trying to add this code into a next.js application. ( from npm module example code: pdf2json )
let fs = require('fs');
var PDFParser = require("pdf2json");
let pdfParser = new PDFParser(this,1);
pdfParser.on("pdfParser_dataError", errData =>
console.error(errData.parserError) );
pdfParser.on("pdfParser_dataReady", pdfData => {
fs.writeFile("./sometxt.txt", pdfParser.getRawTextContent());
pdfParser.loadPDF("./page1.pdf");
You can require it conditionally by testing if it is the server:
static async getInitialProps({isServer}){
var fs;
if(isServer){
fs=require('fs');
//and do what ever you want
}
}
and dot not forgot to tell webpack to do not send the module to the client side by changing package.json like so:
"browser": {
"fs": false
}
unless it can produce errors.
The thing that's probably biting you is that most of your code must work on both the client and the server. You can write server-only code by creating a getInitialProps() method and checking to see if it's passed in a opts.req - if so, you know the code is running server-side and you can hit the filesystem:
import React from 'react'
const doServerSideStuff = () => {
let fs = require('fs');
var PDFParser = require("pdf2json");
let pdfParser = new PDFParser(this,1);
pdfParser.on("pdfParser_dataError", errData =>
console.error(errData.parserError) );
pdfParser.on("pdfParser_dataReady", pdfData => {
fs.writeFile("./sometxt.txt", pdfParser.getRawTextContent());
pdfParser.loadPDF("./page1.pdf");
}
export default class extends React.Component {
static async getInitialProps ({ req }) {
if (req) {
doServerSideStuff();
}
return {};
}
render () {
return <div> Hello World </div>
}
}
This isn't really a complete example yet, you should really make doServerSideStuff() async (or return a promise) and then await it in getInitialProps, and eventually return props that represent the result of the parsing & saving. Also, handle fs.writeFile errors. But, hopefully it's enough to get you going in the right direction.
See the docs for some more info on this.
Or you could just use Express like you suggested. There is a good tutorial and example code that should help you get started if you decide to go that route.