Introducing the new `vlt exec` and `vlt exec-cache` commands
Published on

Introducing the new `exec` and `exec-cache` commands

Authors

The New vlt exec and vlt exec-cache Commands

A new way to run arbitrary code from the internet just dropped! This describes how the vlt exec command works (which you can also run as vlt x or just vlx).

tl;dr

  • vlx <something...> will run a command from a dependency package, just like npx or pnpx, downloading it if it's not already in node_modules.
  • vlxl <something...> will run a command from a dependency, but only if it's found in node_modules. (Ie, it won't download anything ever.)
  • The vlt exec-cache command lets you easily work with the stuff that vlt downloaded for this purpose.

Keep reading if you want to know how it works!

How vlx Works

If you run vlx some-command ..., without any version specifier, vlt will first attempt to see if there's a some-command executable present in your node_modules/.bin folder. If so, it'll use that, execute the command, and we're done.

If not, or if the command has a version specifier like vlx name@version ..., then vlt will resolve the specifier, and add it to the "exec cache" at your XDG data directory under vlt/vlx/${identifier} (unless it's already there).

If the package doesn't have a "default executable" (that is, a bin with the same name as the package), then this will fail, because it won't know what has to be run. If this happens, though, for example with a package like typescript that has tsc and tsserver executables, you can specify which package to pull the executable by using the package option, just like with npx and pnpx. For example:

vlx --package=[email protected] tsc

Whenever you're using the vlx or vlt exec commands, any options or flags that come after the first positional argument will be passed to the child process, so there's no need to use -- like you would with npm exec.

For safety, if vlx has to fetch and install a new package, you'll get prompted to allow it. You can skip this prompt by setting the --yes option (or the -y alias), if you only live once and aren't bothered by typo-squats or malware:

vlx -y --package=[email protected] tsc

As a special bonus that npx and pnpx don't support, you can also just use the vlt exec --package=<specifier> command with no other arguments, to drop into a subshell with those executables in the path. This can be handy if you want to use a command repeatedly, without vlx-ing it each time. Here's an example using glob:

$ vlt exec --package=[email protected]
$ which glob
/Users/isaacs/Library/Application Support/vlt/vlx/glob-53055220/node_modules/.bin/glob

When you're done with that subshell, just ^D to exit back to your original environment.

If you run vlt exec with no arguments and no --package option, then it'll spawn a subshell where all your project's node_modules/.bin folders are in the $PATH, so you can use your project dependency executables as you like. (This is similar to npm exec with no arguments.)

The exec-cache

When npx was initially developed, it seemed reasonable to put the downloaded packages in the ~/.npm folder that was also used as its request cache.

However, the problem with this is that it's not really the same kind of "cache" as the content-addressable cache that npm used for registry requests. And because npm didn't have the same kind of stale-while-revalidate support that vlt does, doing a resolution on each npx execution would've been prohibitively expensive. That led to many situations where it'd never notice that a given specifier had changed, so for example npx eslint@latest would keep getting an old version forever.

With vlx, we can first do a resolution with a stale-while-revalidate-factor set to Infinity. This means that if we have ever seen a given request, we'll use the cached copy, but if that cached copy is stale, we'll revalidate it asynchronously, in a detached background process, so that it's up to date the next time, without you having to wait right now.

These packages are installed in the XDG "data" directory under vlt/vlx/${identifier}. The XDG data directory defaults to ~/Library/Application Support on macOS, ~/AppData/Roaming/xdg.data on Windows, and ~/.local/share on Linux.

To see what's in this cache, we can run:

$ vlt exec-cache ls
abbrev-c37c2618
glob-a76c146a
typescript-695bf962
typescript-9b23527d
glob-53055220
typescript-20179657
@isaacs§ttlcache-f0fd9177

To get info about one of those installations, we can use the vlt exec-cache info <key> command:

$ vlt exec-cache info glob-a76c146a
{
  path: '/Users/isaacs/Library/Application Support/vlt/vlx/glob-a76c146a',
  name: 'glob',
  version: '10.4.5',
  resolved: 'https://registry.npmjs.org/glob/-/glob-10.4.5.tgz',
  arg0: 'glob',
  integrity: 'sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==',
  signatures: [
    {
      sig: 'MEYCIQC8e5UGHGkyQAsQTODAzsj5/qX2Kq7Esa3fY6YbSWwQygIhAMKHzp7AD/3NOukC7JY3L+pGkD40FCF5NGkDTpEM+0Fy',
      keyid: 'SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA'
    }
  ]
}

And of course, if you want to explicitly add or delete anything, you can do that with vlt exec-cache install <specifier> and vlt exec-cache delete <key>, respectively.

Now go execute some commands!

Join the waitlist

Curious to learn more about vlt? Join our waitlist and get early access.

Sign up