- Published on
Introducing the new `exec` and `exec-cache` commands
- Authors
- Name
- Isaac Schlueter
- X (Formerly Twitter)@izs
vlt exec
and vlt exec-cache
Commands
The New 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 likenpx
orpnpx
, downloading it if it's not already innode_modules
.vlxl <something...>
will run a command from a dependency, but only if it's found innode_modules
. (Ie, it won't download anything ever.)- The
vlt exec-cache
command lets you easily work with the stuff thatvlt
downloaded for this purpose.
Keep reading if you want to know how it works!
vlx
Works
How 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.)
exec-cache
The 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!