admin管理员组

文章数量:1316219

While I wrote this answer for StackOverflow I came across the problem that I wanted to execute some code exactly once in Nuxt.js when the server is started (or while the server is starting).

I thought about writing a module or a plugin, but I did not succeed, since both were executed every time I contacted the server, i.e., every time I made a call to localhost:3000/myPage. Probably I am missing the right module hook or some plugin setting?

Since I could not find any information on this problem in the official documentation, I now came up with a quite ugly solution: I wrote a serverMiddleware that executes some code (the code that should be run only once) and then returns an empty handler - which now adds (little) unnecessary overhead to every request.

My question: What would have been the best way to execute some code exactly once on a Nuxt.js server during/after startup, but not during building?


Minimal ugly working example:

nuxt.config.js:

export default {
  ...
  serverMiddleware: [ "~/serverMiddleware/run-once.js" ]
  ...
}

~/serverMiddleware/run-once.js:

console.log("Yay, I only run once when the server is started!")
// Since we are a serverMiddleware, we have to return a handler, even if this it does nothing
// I think this is really ugly...
export default function (req, res, next) {
  next()
}

PS: I saw questions such as Is it possible for Nuxt JS plugins to only run once? but it seems to not answer my question since the vue-renderer:ssr:prepareContext nuxt hook also executes every time I send a request to the server.

Also, a module such as the following does not work since it is also executed during nuxt build and not only on nuxt dev or nuxt start:

export default function MyModuleThatShouldOnlyRunOnce (_moduleOptions) {
  console.log("I run on 'nuxt dev' and 'nuxt start', but sadly also on 'nuxt build' :(");
}

While I wrote this answer for StackOverflow I came across the problem that I wanted to execute some code exactly once in Nuxt.js when the server is started (or while the server is starting).

I thought about writing a module or a plugin, but I did not succeed, since both were executed every time I contacted the server, i.e., every time I made a call to localhost:3000/myPage. Probably I am missing the right module hook or some plugin setting?

Since I could not find any information on this problem in the official documentation, I now came up with a quite ugly solution: I wrote a serverMiddleware that executes some code (the code that should be run only once) and then returns an empty handler - which now adds (little) unnecessary overhead to every request.

My question: What would have been the best way to execute some code exactly once on a Nuxt.js server during/after startup, but not during building?


Minimal ugly working example:

nuxt.config.js:

export default {
  ...
  serverMiddleware: [ "~/serverMiddleware/run-once.js" ]
  ...
}

~/serverMiddleware/run-once.js:

console.log("Yay, I only run once when the server is started!")
// Since we are a serverMiddleware, we have to return a handler, even if this it does nothing
// I think this is really ugly...
export default function (req, res, next) {
  next()
}

PS: I saw questions such as Is it possible for Nuxt JS plugins to only run once? but it seems to not answer my question since the vue-renderer:ssr:prepareContext nuxt hook also executes every time I send a request to the server.

Also, a module such as the following does not work since it is also executed during nuxt build and not only on nuxt dev or nuxt start:

export default function MyModuleThatShouldOnlyRunOnce (_moduleOptions) {
  console.log("I run on 'nuxt dev' and 'nuxt start', but sadly also on 'nuxt build' :(");
}
Share Improve this question edited Apr 4, 2021 at 8:43 Markus Weninger asked Apr 3, 2021 at 13:56 Markus WeningerMarkus Weninger 12.7k9 gold badges75 silver badges141 bronze badges 8
  • tried hooks? nuxtjs/docs/2.x/internals-glossary/internals-builder – Ilijanovic Commented Apr 3, 2021 at 14:00
  • @Ifaruki Yes, but it seems that I have not found the right hook yet. I do not want to run code during building, but when the server is being started. – Markus Weninger Commented Apr 3, 2021 at 14:01
  • build:before ? this hook? – Ilijanovic Commented Apr 3, 2021 at 14:02
  • @Ifaruki No, since I do not want to execute code during nuxt build but only on nuxt start or nuxt dev. "build:before", as the name suggests, is executed before building. – Markus Weninger Commented Apr 3, 2021 at 14:06
  • 3 @tony19 I appreciate your help. Yet, I want to be able to run code exactly once on nuxt start, i.e., a single time when I start the server. The nuxtServerInit method is executed every time when a vuex-store is set up, i.e., every time a user requests the page. This is not my use case. – Markus Weninger Commented Apr 6, 2021 at 13:41
 |  Show 3 more ments

2 Answers 2

Reset to default 2

I don't know if this topic is still relevant, but you can solve this using a 'ready' hook:

First create a file like this (./hooks/hooks.js):

export default (nuxtConfig) => ({
    ready: () => {
        // Execute your code here
    }
});

Then add it to your nuxt.config.js:

import hooks from './hooks/hooks';

export default {

    // Other stuff

    hooks: hooks(this),

    // Other stuff

}

I created a Nuxt plugin and a posable. By default the path is used as the transaction name, but by adding the ElasticApm Agent to the NuxtApp, I can customize the transaction name using the posable. My app is translated, so using the path as the transaction name doesn't group transactions well since the same transaction will have 10 different paths for the 10 different site languages. I would have liked to use a middleware to customize the transaction names, if someone finds a way to do that, would love for them to add that here. I am configuring APM using environment variables as described here: https://www.elastic.co/guide/en/apm/agent/nodejs/master/configuration.html

pages/index.vue

...
<script setup>
useApm("/");
...

plugins/elasticApm.ts

import apm from "elastic-apm-node/start";

if (!apm.isStarted() && process.env.ELASTIC_APM_ACTIVE) {
    apm.start({
        ignoreUrls: [/^\/_nuxt/, /^\/__nuxt/],
        usePathAsTransactionName: true,
    });
}

export default defineNuxtPlugin(() => {
    return {
        provide: {
            apm: apm,
        },
    };
});

posables/elasticApm.ts

export function useApm(routeName: string, method: string = "GET") {
    if (import.meta.client) {
        return;
    }

    const nuxtApp = useNuxtApp();
    nuxtApp.$apm.setTransactionName(`${method} ${routeName}`);
}

本文标签: