21

I have a (server-side) function I'd like to run when first starting my next.js server. Ordinarily I'd do something like this in my package.json script definition: node ./path/to/script.js && next start. But the script in question imports several resources from "webpacked" code, so that's not so easy. (I know it's possible to turn on es6 support in node.js with --experimental-modules, but this brings its own problems and I'd rather not go down that rabbit hole)

The best solution I have so far is to create an api endpoint to run these scripts and then either manually hit that endpoint after starting. But it seems like such a hack to do this, and it's possible that this endpoint could be used in some sort of DoS attack if someone found it.

Is there a better solution, something that just allows one to register a function/callback to be run when the app is starting? I figured a likely place would be the next.config.js but I don't see anything likely in the list of possible settings.

David784
  • 7,031
  • 2
  • 22
  • 29
  • 3
    Have you try custom server.js file? https://nextjs.org/docs/advanced-features/custom-server – Aga Jan 28 '21 at 14:43
  • 2
    I considered it, but I was hoping there was a less drastic solution. They seem to recommend against it, since "...A custom server will remove important performance optimizations, like serverless functions and Automatic Static Optimization." – David784 Feb 01 '21 at 15:08
  • Well, from what I understand, if you're running the next.js API, you are running it like serverless functions, so you don't have exactly a server first starting, you don't have a server running like in a traditional express server. I don't know about your context, but you could have each route calling this script in kind of a singleton pattern, as in, have the page store a state saying wether it was already run or not, and if not, when called run again, or use custom-server – iagowp Apr 09 '21 at 04:30
  • 1
    I think I've found a simple and working solution. Test my answer. – Victor Gorban Dec 29 '22 at 12:15

4 Answers4

1

Could it be possible to run the api after entering the code?

_app.js

const MyApp({pageProps}) {
   useEffect(() => {
   /* call to run API on app mount */
      return ( /* Call to clean up after app unmounted*/);
   },[])

   return (
      <Component {...pageProps} />
   );
}
export default MyApp;

Another solution could be using a Next's getServerSideProps or getStaticProps on the index/entry point for the app

index.js

export default function foo({props}) {
   /* Do something */
   return( /* return something to renderer */);
}

export function getServerSideProps() {
   const caller = fetch(/* Return from running API endpoint*/)
   return (
      props: caller;
   )
}

both of the get* functions from Next.js will run before the component renders to ensure that the data has been fetched. They are used for data fetching, but I don't see why they couldn't be used as a hack to force the API to run near launch.

nswagg
  • 11
  • 3
0

I guess you could use the webpack configuration on the next.config file to register a new plugin and run it after the build is done.

module.exports = {
    webpack: (config, options) => {
        config.plugins.push(
            {
                apply: (compiler) => {
                    compiler.hooks.afterEmit.tap('AfterEmitPlugin', (compilation) => {
                        console.log(".. Run after build")
                    });
                }
            }    
        )
        return config
    },
}
Italo Ayres
  • 2,603
  • 2
  • 16
  • 20
  • sorry, click wrong button. My question was, this solution can not be implemented in typescript ? Need to compile first... – Jerome Nov 08 '21 at 17:35
0

The only solution I've found for the end of 2022, is using some bash scripts. It's actually simple. Original bash answer My dev script:

start_dev.sh

yarn run dev & curl -I http://localhost:3002 & wait

My production script:

start.sh

yarn run start & curl -I http://localhost:3000 & wait

Here, I use curl to peek my site. That causes the site to actually launch it's scripts that normally launch on first visit. For sure, you can place you startup scripts anywhere you want, using home page is not required.

In my case, I need some database preparing and page data caching. So I use NextConnect for that. Here I give one example (I have simular code for each page and api route):

export async function getServerSideProps({ req, res }) {
    const middlewares = NextConnect().use(waitDB).use(withUser).use(withPagesCache)
    await middlewares.run(req, res);
    ...
}

My withUser middleware:

export default async function (req, res, next) {
  let cookies = getCookies({ req, res });
  let { user_id, token } = cookies;
  // some logic. You are free to use your globals, your DB and so on.
  console.log("Test this middleware");

  next();
}
Victor Gorban
  • 1,159
  • 16
  • 30
0

What exactly are you planning to do?

I assume you've red the script loading strategies available here:

https://nextjs.org/docs/basic-features/script

In general, you could just setup your own webpack config (instead of waiting for Next.js to pack it (means Next.js is going to pack again the same you've already packed, but it's like 'once in a while' (deployment time), maybe acceptable if no loading strategy fits your needs.

Otherwise you can always add webpack config into next.config.js so you could tell Next.js to grab your already packed code to avoid doing things twice.

You can also next build and then run the script (pointing to packed files, probably somewhere in .next/ directory, and then start the app.

This also looks interesting:

https://nextjs.org/docs/advanced-features/output-file-tracing

faebster
  • 727
  • 7
  • 13