8

I have an working nextjs project.

I need to create a script that I can run from the CLI that uses some of the CRUD libraries I've written for the next project.

**/scripts/backup-assets.js **

import {getAllProjectsData} from '../lib/api/projects'

async function main() {
  const allProjectsData = await getAllProjectsData()
  console.info({allProjectsData})
}

main()

I'm getting this error:

$ node scripts/backup-assets.js 
(node:9736) Warning: To load an ES module, set "type": "module" in the package.json or use the .mjs extension.
(Use `node --trace-warnings ...` to show where the warning was created)
C:\Users\...\scripts\backup-assets.js:1
import {getAllProjectsData} from '../lib/api/projects'
^^^^^^

SyntaxError: Cannot use import statement outside a module
    at Object.compileFunction (node:vm:352:18)
    at wrapSafe (node:internal/modules/cjs/loader:1033:15)
    at Module._compile (node:internal/modules/cjs/loader:1069:27)
    at Object.Module._extensions..js (node:internal/modules/cjs/loader:1159:10)
    at Module.load (node:internal/modules/cjs/loader:981:32)
    at Function.Module._load (node:internal/modules/cjs/loader:822:12)
    at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:77:12)
    at node:internal/main/run_main_module:17:47
juliomalves
  • 42,130
  • 20
  • 150
  • 146
user2632759
  • 81
  • 1
  • 6
  • Have you tried what's suggested in the warning message? _"Warning: To load an ES module, set "type": "module" in the package.json or use the .mjs extension."_. See [SyntaxError: Cannot use import statement outside a module](https://stackoverflow.com/questions/58384179/syntaxerror-cannot-use-import-statement-outside-a-module). – juliomalves May 11 '22 at 22:20
  • I guess if you're using js, you could just execute the module directly as a module; but if you use TS or special nextjs imports, e.g. css, then it's going to need to be compiled. @user2632759 did you figure out a solution to this? – Richard Scarrott Aug 03 '22 at 14:35

3 Answers3

13

Use TSX. It runs out of the box with NextJS, with both JavaScript and TypeScript.

Install it:

npm install --save-dev tsx

Declare your script. In package.json:

...
"scripts": {
  ...
  "my-js-script": "tsx scripts/my-script.js",
  "my-ts-script": "tsx scripts/my-script.ts"
},

Run it:

npm run my-js-script
npm run my-ts-script
philippe_b
  • 38,730
  • 7
  • 57
  • 59
2

I haven't found a way to do this but here's a workaround:

  1. Create an API route called /api/scripts which takes a task param.

  2. Add a check to prevent it running in production (or authentication if you'd like to run your scripts in production context).

export default async function handler(req, res) {
  
  if (process.env.NODE_ENV === 'production') return res.status(404).end();

  switch (req.query.task) {
    case 'backup-assets':
      // code
    case 'migrate-database':
      // code

  1. Launch in dev or production mode as appropriate:
npm run dev
  1. Run the desired script from the command line with curl:
curl http://localhost:3000/api/scripts?task=backup-assets

or just visit that URL in the browser.

rnbrady
  • 204
  • 1
  • 6
1

Here's how I managed to set up standalone deployment/maintenance scripts in my NextJS project.

First, install ts-node (CLI runner) and tsconfig-paths as local DEV dependencies. The last one is a ts-node plugin that loads path aliases from tsconfig.json. If you're using plain JavaScript or don't use path aliases, you can skip it.

npm i -D ts-node tsconfig-paths

Then add a script entry to your package.json:

...
"scripts": {
  ...
  "recreate-image-info": "ts-node -O '{\"module\": \"commonjs\"}' -r tsconfig-paths/register deploy/recreate-image-info.ts"
},

The -r flag with its parameter enables the tsconfig-paths plugin. The -O flag specifies compiler options.

Then, to run the script via CLI:

npm run recreate-image-info