This week, I tackled an interesting challenge revealing knowledge gaps – executing an exported function in a TypeScript file without calling it within the file and working with the Node CLI.

For most of the application code, you may write, you may never have to learn such concepts because, in software, we have A LOT of abstractions – mainly in the form of npm packages for fellow JavaScript Developers.

But if you’re building systems for other systems to run on, you have to dive deeper and learn the abstractions are.

Context - how seeding in Prisma works

The task involved writing a script would end up being part of a mini-test-suite to ensure that the instructions a user followed wouldn’t lead to an error.

One of the steps was seeding a database in a Prisma project. The Prisma CLI exposes a seed command, but at the time of writing this, it’s a preview-feature and its implementation is being redesigned.

The default way of executing a function in a file is by calling it. It just works. The stable implementation of seeding currently works as follows:

function main(){
  /** your seeding logic */
}

main()
  .catch((e) => {
    console.error(e);
    process.exit(1);
  })
  .finally(async () => {
    await prisma.$disconnect();
  });

Running npx prisma db seed --preview-feature would successfully seed your database with the above code example

But… seeding was using a different implementation of the seed command that the Prisma CLI supports – executing seed function with a default exported seed() or exported seed() function in your ./prisma/seed.ts file:

export default function seed (){
    /** your logic */
}
// OR

export function seed(){
  /** your logic */
}

Running npx prisma db seed --preview-feature would work just okay but it isn’t always guaranteed to work perfectly. Occasionally, prisma db seed encounters an error but won’t throw an error – indicating a false positive.

The solution

ts-node πŸŽ‰

ts-node is a handy tool for transpiling/ transforming TypeScript into JavaScript.

Unlike the first main() seeding example, the seed() function isn’t called. Running npx ts-node ./prisma/seed would only transform the file checking for type errors.

ts-node exposes the --eval/ -e flag from the Node CLI. The --eval flag accepts a script argument which is valid TypeScript/ JavaScript code. For It has to be valid JavaScript in the case of Node.js.

You can execute the seed() function with the following command:

npx ts-node -e "import seed from './prisma/seed'; seed()"

OR:

npx ts-node -e "import {seed} from './prisma/seed'; seed()"

As the command is being executed, --eval creates a “sandbox” – the Node.js REPL (Read-Eval-Print-Loop) – where the code is executed.

Note: You can execute exported functions in your TypeScript project following the above command. E.g.

// path - ./src/starWars.ts
export function fetchStarWarsMovies(){
  try{
    /** logic here */
  } catch (error){
    /** error handling */
  }
}
yarn ts-node -e "import {fetchStarWarsMovies} from './src/starWars'; fetchStarWarsMovies()"

Besides --eval flag, you can also use the --print/-p. --print is similar to --eval but prints the output on the console.

Learning about --eval and --print flag in ts-node and Node.js showed me there’s a whole mountain of tools/ software to learn out there. Abstractions are grand, but every once in a while, it’s a good idea to understand how to use them instead of installing another npm package :troll_face:

I hope you enjoyed this article. If you have any comments or feedback, my Twitter DM is open.

Till next week. ✌🏽