A simple way to replace npm scripts in Deno
Tags: javascript, deno, notnode
Published: 2020-05-14 16:35:28

---
title: A simple way to replace npm scripts in Deno
published: true
description: Sometimes simplicity can be an obstacle but lucky for us this is javascript
tags: #javascript #deno #notnode
---

> Update 2022-04-13:
>
> Since version 1.20 deno now includes a task runner. You can finde the details in the release note: [new subcommand deno task](https://deno.com/blog/v1.20#new-subcommand-deno-task).

> Feel free to ignore the rest of this article.

Sooo I tried [deno](https://deno.land/), did the traditional "hello world" and 5 seconds later I felt the pain of not having the npm cli and the package.json file. I can't `npm start` anymore and it bothers me more than it should. Say whatever you want about the `node_module` folder and `npm, Inc.` but npm scripts are the bee's knees.

Anyway, as I was saying, Deno's simplicity just punched me in the face. Now this is usually the part were I search for a third party library to fill the void, but not today. Today I just want to run a couple of commands in a sequence, that's not hard, I can do that with some functions. So I created this file in the root of the project.

```js
// Taskfile.js

function run([name, ...args], tasks) {
  name in tasks 
    ? tasks[name](...args) 
    : console.log(`Task "${name}" not found`);
}

async function exec(args) {
  const proc = await Deno.run({ cmd: args }).status();

  if(proc.success == false) {
    Deno.exit(proc.code);
  }

  return proc;
}
```

The function `run` is the one that decides which task is going to be executed, and it will be kind enough to tell you if the task you asked for can't be found. But the interesting part of this story is `exec`, that's the one that's going to execute the external commands I need using [Deno.run](https://deno.land/manual/examples/subprocess). Now we can define our tasks.

```js
run(Deno.args, {
  start() {
    exec(['deno', 'run', './src/mod.ts']);
  },
  async install() {
    await exec(['echo', 'Installing stuff....']);
    // do other things
  },
  echo(str) {
    return exec(['echo', str, "\nThis is javascript, y'all"]);
  },
  async test() {
    // need more power? You got it
    if(/* some condition */) {
       await this.echo('Awesome');
    }

    // do other things
  }
});
```

> You can make this even better if you use a dependency to parse the arguments. Deno has [one](https://deno.land/std/flags) on their standard library.

This is how you run it.

```sh
deno run --allow-run ./Taskfile.js start
```

Now simplicity strikes again. That is quite a command, no one wants to type that, lucky for us we have the shell on our side. To solve this we can make an alias.

```sh
alias deno-task='deno run --allow-run ./Taskfile.js'
```

On windows using powershell.

```powershell
Set-Alias -Name deno-task -Value deno run --allow-run ./Taskfile.js
```

You can even improve this with some shell kung-fu.

```sh
alias deno-root-task='deno run --allow-run $(git rev-parse --show-toplevel)/Taskfile.js'
```

If you are in a folder controlled by git, this command can be used to make sure you execute the `Taskfile` of the root of the project.

> If anyone knows how to make an alias in cmd.exe, please put it in the comments.

Now we are done, we can use `deno-task start` to start our application/script or use any other custom commands to automate what we need. There is a bunch of things that this script doesn't do but if `npm scripts` were enough for you so will this.

edit: I wrote another post about this exact same thing but using a "shell function": [Extending the deno cli using a shell function ](https://dev.to/vonheikemen/extending-the-deno-cli-using-a-shell-function-3ifh)

---

Thank you for reading. If you find this article useful and want to support my efforts, [buy me a coffee ☕](https://www.buymeacoffee.com/vonheikemen).

[![buy me a coffee](https://res.cloudinary.com/vonheikemen/image/upload/v1618466522/buy-me-coffee_ah0uzh.png)](https://www.buymeacoffee.com/vonheikemen)