using Nuxt 3 with Nest - vue.js

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.

Related

Nuxt 3 - how to access plugin injections from components?

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)
})
}
}

How to Implement nuxtServerInit Action to load data from server-side on the initial load in Pinia (Nuxt3)

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

nuxt builder in nuxt3

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();

Making global plugin that I can use anywhere in app

I have this class for sockets. Is there any way that I could make this globally accessible? I'd like to access the functions anywhere in my app for example like $socket.methodName()
What I've tried
class InitSocket {
constructor(options) {
this.options = options;
}
connect() {
console.log(this.options);
}
}
export default {
install: (Vue, options) => {
Vue.prototype.$socket = new InitSocket(options);
},
};
in main.js
const { createApp } = require('vue');
import App from "./App.vue";
import Sockets from './plugins/Socket'
const app = createApp(App);
app.use(Sockets , "test");
app.mount("#app");
But I am getting this message
Cannot set properties of undefined (setting '$socket') - What am I doing wrong?
In Vue 3 you can have multiple apps and you can no longer add to Vue prototype.
In order to write and use a plugin, follow the steps:
Step 1: Create the plugin
export default {
install: (app, options) => {
class InitSocket {
constructor(options) {
this.options = options;
}
connect() {
console.log(this.options);
}
}
// inject a globally available $socket() method
app.config.globalProperties.$socket = new InitSocket(options)
}
}
Step 2: Import and install it in main.js
import { createApp } from 'vue'
import App from "./App.vue";
import Sockets from './plugins/Socket'
const app = createApp(App);
app.use(Sockets , "test");
app.mount("#app");
Read more on the Vue docs: Plugins

After Nuxt build api returns 404

I'm having this weird issue and I seriously need your help. In development my code works perfectly fine but after doing nuxt build and all the apis are returning 404 error. Please help
When I'm building the api and running it, it works. In development api and nuxt both works but building nuxt and the api, doesn't work.
Following are my configuration
Server configuration
import convert from 'koa-convert';
import cors from 'kcors';
import bodyParser from 'koa-body';
import session from 'koa-session';
import helmet from 'koa-helmet';
import config from 'config';
import serve from 'koa-static';
import mount from 'koa-mount';
import { cModules, cMiddleware } from '../app';
import { catchErr, statusMessage } from './errorConfig';
import nuxtConfig from './nuxtConfig';
function baseConfig(app, io) {
app.keys = config.get('secret');
app.proxy = true;
app.use(mount('/static', serve(config.get('paths.static'))));
app.use(convert.compose(
catchErr,
cors({
credentials: true,
origin: true
}),
bodyParser({
multipart: true,
formLimit: '200mb'
}),
session({
maxAge: 21600000
}, app),
helmet(),
statusMessage
));
cModules(app, io);
app.use(cMiddleware());
if (config.get('nuxtBuild')) {
nuxtConfig(app);
}
}
export default baseConfig;
And my Nuxt
import { Nuxt, Builder } from 'nuxt';
import koaConnect from 'koa-connect';
import isDev from 'isdev';
import config from '../../../nuxt.config';
async function nuxtConfig(app) {
const nuxt = new Nuxt(config);
if (isDev) {
await new Builder(nuxt).build();
}
const nuxtRender = koaConnect(nuxt.render);
app.use(async (ctx, next) => {
await next();
ctx.status = 200;
ctx.req.session = ctx.session;
await nuxtRender(ctx);
});
}
export default nuxtConfig;