I'm migrating from #nuxtjs/composition-api package to Nuxt Bridge and I see that useFetch is available only with Nuxt 3.
Before, I was using the pattern below:
const { state: userState, getUserList } = useUserList()
const { state: groupState, getGroupList } = useGroupList()
// ...
const { fetchState } = useFetch(async () => {
await Promise.all([
getUserList(),
getGroupList(),
// ...
])
})
And I could use fetchState.pending to display a loader until everything was loaded.
How to have the behavior with Nuxt Bridge knowing that only useLazyAsyncData and useLazyFetch are compatible?
Related
Using Nuxt 3 and vue-gtag, what is the right way to access $gtag from components?
plugins/gtag.client.js:
import VueGtag from 'vue-gtag';
export default defineNuxtPlugin(nuxtApp => {
const router = useRouter();
nuxtApp.vueApp.use(
VueGtag,
{
config: {
id: '...'
}
},
router
);
});
In Nuxt 2, this.$gtag was accessible from component file.
In Nuxt 3, I can't seem to find it:
const nuxtApp = useNuxtApp();
nuxtApp.$gtag //undefined
Looking at the source code, it seems to be defined correctly, so I don't think it's a problem with the plugin itself.
app.config.globalProperties.$gtag = api;
I have same issue when define the domToImage plugin in nuxt 3. I found a solution as follow. Hope to help you.
Return provide in nuxt plugin:
import domtoimage from "dom-to-image-more";
export default defineNuxtPlugin((nuxtApp) => {
// nuxtApp.vueApp.use(domtoimage)
return {
provide: {
domtoimage
}
}
})
Use in component:
const print = () => {
console.log("Print ...")
const { $domtoimage } = useNuxtApp()
$domtoimage.toPng(printMeDiv)
.then((dataUrl) => {
console.log(dataUrl)
})
}
}
My Code:
export const useMenuStore = defineStore("menuStore", {
state: () => ({
menus: [],
}),
actions: {
async nuxtServerInit() {
const { body } = await fetch("https://jsonplaceholder.typicode.com/posts/1").then((response) => response.json());
console.log(body);
this.menus = body;
resolve();
},
},
});
NuxtServerInit is not working on initial page render on nuxt js vuex module mode.Anyone know this error please help me.
NuxtServerInit is not implemented in Pinia, but exists a workaround.
Using Pinia alongside Vuex
// nuxt.config.js
export default {
buildModules: [
'#nuxtjs/composition-api/module',
['#pinia/nuxt', { disableVuex: false }],
],
// ... other options
}
then Include an index.js file inside /stores with a nuxtServerInit action which will be called from the server-side on the initial load.
// store/index.js
import { useSessionStore } from '~/stores/session'
export const actions = {
async nuxtServerInit ({ dispatch }, { req, redirect, $pinia }) {
if (!req.url.includes('/auth/')) {
const store = useSessionStore($pinia)
try {
await store.me() // load user information from the server-side before rendering on client-side
} catch (e) {
redirect('/auth/login') // redirects to login if user is not logged in
}
}
}
}
In Nuxt2, the Nuxt will run the code in nuxtServerInit() of store/index.js on the server-side to boot the app.
However, in Nuxt3, there is no specific place to write the boot code, you can write the boot code anywhere instead of in nuxtServerInit() of store/index.js.
It might be helpful, especially when you need to send a request before boosting the app.
your pinia file may define like following:
store/menu.js
import { defineStore } from 'pinia';
export const useMenuStore = defineStore('menuStore', {
state: () => ({
_menus: [],
}),
getters: {
menus() {
return this._menus;
}
},
actions: {
async boot() {
const { data } = await useFetch('https://jsonplaceholder.typicode.com/posts/1');
this._menus = data;
}
}
});
Then, create a plugin which named as *.server.[ts|js], for example init.server.js
(.sever.js tail will let the file only run in server side)
plugins/init.server.js
import { defineNuxtPlugin } from '#app';
import { useMenuStore } from '~/store/menu.js';
export default defineNuxtPlugin(async (nuxtApp) => {
const menu = useMenuStore(nuxtApp.$pinia);
await menu.boot();
});
nuxt.config.js
modules: [
'#pinia/nuxt',
],
There is an entire example of SSR Nuxt3 with authorization that may help
Currently we are able to build nuxt as following. But are unable to handle routes. We basically want to serve nuxt app from Nestjs.
import { NestFactory } from '#nestjs/core';
import { AppModule } from './app.module.js';
import { loadNuxt } from 'nuxt3';
import { buildNuxt, Resolver } from '#nuxt/kit';
async function bootstrap() {
const app = await NestFactory.create(AppModule);
// Check if we need to run Nuxt in development mode
const isDev = process.env.NODE_ENV !== 'production'
// Get a ready to use Nuxt instance
const nuxt = await loadNuxt({ rootDir: 'src/client-app/' })
// Enable live build & reloading on dev
if (isDev) {
buildNuxt(nuxt)
}
await app.listen(3001);
}
bootstrap();
Following is next (react) equivalent code which is working and trying to achieve in Nuxt 3.
https://github.com/hnviradiya/contact-list/blob/e38a72167d5710fcc9f3ed9718fa9bfe8ebb7d00/src/server/client-app/client-app.service.ts#L25
import { Injectable } from '#nestjs/common';
import { ConfigService } from '#nestjs/config';
import { IncomingMessage, ServerResponse } from 'http';
import createServer, { NextServer } from 'next/dist/server/next';
#Injectable()
export class ClientAppService {
private nextServer: NextServer;
constructor(private configService: ConfigService) {}
async onModuleInit(): Promise<void> {
try {
this.nextServer = createServer({
dev: this.configService.get<string>('NODE_ENV') !== 'production',
dir: './src/client',
});
await this.nextServer.prepare();
} catch (error) {
console.error(error);
}
}
handler(req: IncomingMessage, res: ServerResponse) {
return this.nextServer.getRequestHandler()(req, res);
}
}
In nuxt 2 there were nuxt.render(req, res) or nuxt.renderRoute(route, context). But these methods are not available in nuxt3.
https://nuxtjs.org/docs/internals-glossary/nuxt/
So how to serve nuxt app through NestJs.
Following is the repo where nuxt 3 code is there but it is not serving nuxt app.
https://github.com/hnviradiya/nest-nuxt
while Nestjs is a great server, it's angular style #decorators and modular setup is too unlike Nuxt3's scaffold simplicity.
This conception feels like a bad idea.
Nuxt 2 was having builder which we used to build nuxt app.
But nuxt 3 is not having builder. Is that not part of nuxt 3? Following is what we were using in nuxt 2.
import { Builder } from '#nuxt/builder';
I am serving nuxt app from nestjs like following example of next.js.
https://github.com/hnviradiya/contact-list/blob/main/src/server/client-app/client-app.service.ts
Following is equivalent to Nuxt 2 code.
import { NestFactory } from '#nestjs/core';
import { AppModule } from './app.module.js';
import { loadNuxt } from 'nuxt3';
import { buildNuxt, Resolver } from '#nuxt/kit';
async function bootstrap() {
const app = await NestFactory.create(AppModule);
// Check if we need to run Nuxt in development mode
const isDev = process.env.NODE_ENV !== 'production'
// Get a ready to use Nuxt instance
const nuxt = await loadNuxt({ rootDir: 'src/client-app/' })
// Enable live build & reloading on dev
if (isDev) {
buildNuxt(nuxt)
}
await app.listen(3001);
}
bootstrap();
I try to test my web services, hosted in my Next.js app and I have an error with not found Next.js configuration.
My web service are regular one, stored in the pages/api directory.
My API test fetches a constant ATTACKS_ENDPOINT thanks to this file:
/pages/api/tests/api.spec.js
import { ATTACKS_ENDPOINT } from "../config"
...
describe("endpoints", () => {
beforeAll(buildOptionsFetch)
it("should return all attacks for attacks endpoint", async () => {
const response = await fetch(API_URL + ATTACKS_ENDPOINT, headers)
config.js
import getConfig from "next/config"
const { publicRuntimeConfig } = getConfig()
export const API_URL = publicRuntimeConfig.API_URL
My next.config.js is present and is used properly by the app when started.
When the test is run, this error is thrown
TypeError: Cannot destructure property `publicRuntimeConfig` of 'undefined' or 'null'.
1 | import getConfig from "next/config"
2 |
> 3 | const { publicRuntimeConfig } = getConfig()
I looked for solutions and I found this issue which talks about _manually initialise__ next app.
How to do that, given that I don't test React component but API web service ?
I solved this problem by creating a jest.setup.js file and adding this line of code
First add jest.setup.js to jest.config.js file
// jest.config.js
module.exports = {
// Your config
setupFilesAfterEnv: ['<rootDir>/jest.setup.js'],
};
AND then
// jest.setup.js
jest.mock('next/config', () => () => ({
publicRuntimeConfig: {
YOUR_PUBLIC_VARIABLE: 'value-of-env' // Change this line and copy your env
}
}))
OR
// jest.setup.js
import { setConfig } from 'next/config'
import config from './next.config'
// Make sure you can use "publicRuntimeConfig" within tests.
setConfig(config)
The problem I faced with testing with Jest was that next was not being initialized as expected. My solution was to mock the next module... You can try this:
/** #jest-environment node */
jest.mock('next');
import next from 'next';
next.mockReturnValue({
prepare: () => Promise.resolve(),
getRequestHandler: () => (req, res) => res.status(200),
getConfig: () => ({
publicRuntimeConfig: {} /* This is where you import the mock values */
})
});
Read about manual mocks here: https://jestjs.io/docs/en/manual-mocks
In my case, I had to:
Create a jest.setup.js file and
setConfig({
...config,
publicRuntimeConfig: {
BASE_PATH: '/',
SOME_KEY: 'your_value',
},
serverRuntimeConfig: {
YOUR_KEY: 'your_value',
},
});
Then add this in your jest.config.js file:
setupFilesAfterEnv: ['<rootDir>/jest.setup.js'],