Node.js’s younger sibling, Deno, has been evolving. Since its official, buzzy release in May 2020, a lot has changed. The hype has toned down, the runtime has been improved, and the community, alongside the whole module ecosystem, has started to form.
However, even with these changes, Deno still isn’t the “Node.js killer” some might have seen it as. Sure, it comes with great features, like first-class TypeScript support, a secure permission-based system, and URL-based module loading, but it lags behind Node in mind-share and a few basic aspects.
One example of such a feature is a script runner. In Node, there’s package.json
, in which you can specify your scripts
.
"scripts": { "dev": "vite", "build": "vite build", "serve": "vite preview" } }
The problem is, there’s no inbuilt package.json
or any alternative in Deno. You have to type out the full command any time you want to use it. Tons of config flags don’t make this any better:
deno run --allow-read --allow-write --allow-net --reload example.ts
The way around that is to use a third-party script runner, like Velociraptor. Let’s see what features it has, how it works, and how it can make working with Deno that much better!
Velociraptor is arguably the most popular script runner for Deno, with about 500 GitHub stars at the time of this article’s publication. It is inspired by package.json
’s scripts
and offers a similar out-of-the-box experience to its Node counterpart, but also comes with additional, Deno-specific features.
You can install Velociraptor from deno.land/x, like any other module:
deno install -qAn vr https://deno.land/x/[email protected]/cli.ts
It’s recommended to use vr
while assigning a name to the executable. Using a different name may result in some known issues with Git hooks.
Next, create your configuration file — the package.json
replacement. It could be either a scripts
or a velociraptor
file with one of the following extensions:
yml
/ yaml
json
ts
Here are examples of different config files:
scripts.yaml
scripts: start: deno run --allow-net server.ts test: deno test --allow-net server_test.ts
scripts.json
{ "scripts": { "start": "deno run --allow-net server.ts", "test": "deno test --allow-net server_test.ts" } }
script.ts
export default { scripts: { start: "deno run --allow-net server.ts", test: "deno test --allow-net server_test.ts", }, };
We’ll stick with yaml
for the rest of this post.
Besides the basic, compact form, scripts can also be defined as objects that allow for passing additional options, like desc
for describing the script’s purpose or watch
for reloading the script on file change.
scripts: start: desc: Runs the server cmd: deno run --allow-net server.ts watch: true
In object format, you specify the actual command under the cmd
property.
Alongside the configuration file, Velociraptor’s CLI is its most important feature. It’s your yarn
or npm run
equivalent for the Deno world.
Running plain vr
in your terminal will output all defined scripts, while vr run <script>
or vr <script>
will run the selected script.
vr # list available scripts vr run start # run "start" script vr start # more concise way of running "start" script vr start --prod # run "start" script with "prod" argument
Besides running scripts, Velociraptor also provides an export
command for outputting one or more scripts as a standalone executable for use in environments where Velociraptor is not installed.
vr export start # export "start" script ./bin/start --prod # run exported script with "prod" argument vr export start -o output # change output directory from default "bin"
While defining scripts and running them from the CLI should be enough in most cases, Velociraptor goes far beyond that. With its additional features, using a script runner in Deno becomes a much better experience.
Velociraptor allows you to specify some of your Deno CLI options in a clean, structured way with dedicated config properties.
You can specify Deno permissions in an array or object for all scripts at the upper-most allow
field, or on a script-by-script basis.
allow: - read - write scripts: start: cmd: server.ts allow: net: 127.0.0.1
You can also provide paths to files like tsconfig.json
, importmap.json
, lock files, and PEM certificates for SSL under separate config entries.
scripts: start: cmd: server.ts cert: certificate.pem lock: lock.json imap: importmap.json tsconfig: tsconfig.json
Apart from the above, there are many more additional options you can specify. These include:
inspect
for attaching the debuggerreload
for recompiling TypeScript (either everything or only specified modules)log
for specifying the log levelv8Flags
for passing options to the V8 engineunstable
, cachedOnly
, and othersCheck out the official Velociraptor documentation for more details.
Apart from the Deno CLI options, there are also dedicated fields for environment variables. This includes:
env
for listing the variables in the config file directlyenvFile
for specifying a dotenv file (or list of files) to load the variables fromThe options can be specified at both the top and script levels and will be combined so that the script receives all needed variables.
# for all scripts envFile: - .env env: PORT: 8081 scripts: start: cmd: deno run --allow-net server.ts # script-specific envFile: .start_env env: PORT: 8082
One more great feature of Velociraptor allows you to run multiple scripts at once. With composite scripts, complex commands filled with &&
and other operators can be replaced with a clean list of scripts.
scripts: start: - deno run one.ts - deno run two.ts test: # With script objects - deno test test_one.ts - cmd: deno test test_two.ts tsconfig: tsconfig.json
The example above runs scripts serially, in order. To run them in parallel, use the pll
option.
scripts: start: pll: # In parallel - deno run one.ts - deno run two.ts
pll
can be combined with a serial script list to form even more complex execution flows.
scripts: start: - pll: - deno run one.ts - deno run two.ts - deno run three.ts
This enables a new set of possibilities, having complex script flows defined and executed clearly, right from the config file.
Velociraptor comes with inbuilt support for Git hooks. It allows you to effortlessly integrate your scripts with Git hooks and share them with others working on the same repo.
To link a single script to a Git hook, add the gitHook
property to it.
scripts: format: cmd: deno fmt gitHook: pre-commit
To attach more than one script to a Git hook, you can use gitHook
alongside composite scripts.
With hooks set up, you can install them by running the vr
command. If you’d like to prevent this behavior (e.g., for CI configuration), set the VR\_HOOKS
environment variable to false
.
For more advanced workflows, Velociraptor integrates with GitHub Actions, thanks to a setup-velociraptor
action. When combined with setup-deno
, you can use vr
commands right from your Actions.
steps: - uses: denoland/setup-deno@v1 - uses: jurassiscripts/setup-velociraptor@v1 - run: vr ...
You can install the dedicated extension for autocompletion and other code assistance features for Velociraptor in VS Code. This will autocomplete configuration options in both yaml
and json
files.
You can still get autocompletion in other editors and IDEs by using TypeScript for your configuration file, alongside proper type annotation.
import { ScriptsConfiguration } from "https://deno.land/x/[email protected]/mod.ts"; const config: ScriptsConfiguration = { scripts: { start: "deno run --allow-net server.ts", test: "deno test --allow-net server_test.ts", }, }; export default config;
With a great, feature-packed script runner like Velociraptor, Deno becomes much more enjoyable to use. All of your scripts are just vr <script>
away; Git hooks integration couldn’t be simpler; and building complex script flows is easy, thanks to composite scripts, structured options, and autocompletion.
If you haven’t already, check out Velociraptor over on GitHub and give it a try!
Install LogRocket via npm or script tag. LogRocket.init()
must be called client-side, not
server-side
$ npm i --save logrocket // Code: import LogRocket from 'logrocket'; LogRocket.init('app/id');
// Add to your HTML: <script src="https://cdn.lr-ingest.com/LogRocket.min.js"></script> <script>window.LogRocket && window.LogRocket.init('app/id');</script>
Would you be interested in joining LogRocket's developer community?
Join LogRocket’s Content Advisory Board. You’ll help inform the type of content we create and get access to exclusive meetups, social accreditation, and swag.
Sign up nowLearn how to manage memory leaks in Rust, avoid unsafe behavior, and use tools like weak references to ensure efficient programs.
Bypass anti-bot measures in Node.js with curl-impersonate. Learn how it mimics browsers to overcome bot detection for web scraping.
Handle frontend data discrepancies with eventual consistency using WebSockets, Docker Compose, and practical code examples.
Efficient initializing is crucial to smooth-running websites. One way to optimize that process is through lazy initialization in Rust 1.80.