Trex 🦕
Package management for deno (pronounced "tee rex")
About
Trex is a package management tool for deno similar to npm but keeping close to
the deno philosophy. Packages are cached and only one import_map.json
file is
generated.
// import_map.json
{
"imports": {
"http/": "https://deno.land/std/http/"
}
}
For more information about the import maps in deno see import maps.
Additional topics
Installation
deno install -A --unstable --import-map=https://deno.land/x/trex/import_map.json -n trex --no-check https://deno.land/x/trex/cli.ts
Note: Works with deno >= 1.10.2
We shorten the install command so it's not that long
The permissions that Trex uses are:
--allow-net
--allow-read
--allow-write
--allow-run
--allow-env
You can give those permissions explicitly.
Updating Trex
Install new version with the -f
flag:
deno install -f -A --unstable --import-map=https://deno.land/x/trex/import_map.json -n trex --no-check https://deno.land/x/trex/cli.ts
Or use the upgrade
command:
trex upgrade
Note: available for versions 0.2.0 or higher.
Note: to try the latest pre-release features, use the
--canary
flag.
Verify the installation of Trex:
trex --version
The console should print the Trex version.
For help on the commands that Trex provides, use:
trex --help
Usage
Installing from deno.land
Use the --map
flag to install packages from the Standard Library (std
) and those hosted at deno.land/x
.
Example
Install the fs
, http
and fmt
modules from std
:
trex install --map fs http fmt
Note: you can also use the shorthand
i
, as in:trex i --map fs http fmt
Installing from nest.land
Use the --nest
flag and specify an explicit version to install packages hosted on nest.land.
trex install --nest [pkg]@[version]
Examples
trex install --nest opine@0.13.0
trex i --nest etag@0.0.2
You can install std
packages from nest.land
by specifying the package and version:
trex install --nest fs@0.61.0
Installing from a repository
trex install --pkg [user]/[repo or repo@tag/branch]/[path/to/file] [packageName]
Example
trex install --pkg oakserver/oak@main/mod.ts oak
Warning: In the event that the repository uses a branch other than master as the main branch, this must be specified!
The above downloads oak directly from its repository.
Example import map
All installation methods produce an import_map.json
file:
{
"imports": {
"fs/": "https://deno.land/std/fs/",
"http/": "https://deno.land/std/http/",
"fmt/": "https://deno.land/std/fmt/"
}
}
Downloading packages
Download all the packages listed in the import_map.json
similar to
npm install
:
trex install
Adding custom packages
Install a package from a custom URL source:
trex --custom React=https://dev.jspm.io/react/index.js
// import_map.json
{
"imports": {
"http/": "https://deno.land/std/http/",
"fmt/": "https://deno.land/std/fmt/",
"oak": "https://deno.land/x/oak/mod.ts",
"React": "https://dev.jspm.io/react/index.js"
}
}
Deleting packages
trex delete React
Remove a specific version from the cache and the import_map.json
file:
trex delete fs@0.52.0
// import_map.json
{
"imports": {
"fs/": "https://deno.land/std/fs/",
"http/": "https://deno.land/std/http/",
"fmt/": "https://deno.land/std/fmt/",
"oak": "https://deno.land/x/oak/mod.ts"
}
}
Note: Removing from cache only works with packages from
std
anddeno.land/x
Installing an explicit version of a package
Specify a package's version:
trex install --map fs@0.54.0
// import_map.json
{
"imports": {
"fs/": "https://deno.land/std@0.54.0/fs/"
}
}
Note: can be used with third party packages.
Checking for outdated dependencies
trex check
Warning: Currently limited to packages from
deno.land/std
anddeno.land/x
, in future versions this will support third party registries and CDN sources as well.
run.json
Run Scripts with You can create command aliases, similar to deno task
or npm run
.
Simply create a run.json
file with the following structure:
{
"scripts": {
"welcome": "deno run https://deno.land/std@0.71.0/examples/welcome.ts"
}
}
Aliasing external commands
You can call a command from within another, or call a script like denopack
or eggs update
from within a command alias:
// run.json
{
"scripts": {
"start": "trex run welcome",
"welcome": "deno run https://deno.land/std@0.71.0/examples/welcome.ts",
"dev": "denon run ./app.ts",
"build": "aleph build",
"update": "eggs update"
}
}
Then, for example, to update your dependencies:
trex run update
This will execute
eggs update
Installation life cycle
When the command trex install
or trex i
executed, you can perform actions
before and after the execution of trex install
.
Execution order:
preinstall
install
postinstall
// run.json
{
"scripts": {
"start": "trex run welcome",
"welcome": "deno run https://deno.land/std@0.71.0/examples/welcome.ts",
"dev": "denon run ./app.ts",
"build": "aleph build",
"preinstall": "deno --version",
"postinstall": "deno test --unstable"
}
}
Note: you can use the --watch flag to monitor the changes and rerun the script, example:
deno run --watch --unstable https://deno.land/std@0.71.0/examples/welcome.ts
Passing arguments to aliases
You can provide arguments when calling the command alias. These will be passed to the file to execute:
trex run start --port=3000 --env
console.log(Deno.args); // ["--port=3000", "--env"]
Reboot Script Alias Protocol (or RSAP)
With trex you can create script aliases that reload every time a file is
changed, similar to running deno with the --watch
flag.
The Reboot Script Alias Protocol (RSAP) provides this same functionality.
Just add a files
property to your run.json
file, specifying an array
of files that will be watched. When changes are detected in those files,
your script aliases will be restarted immediately.
// run.json
{
"scripts": {
"start": "trex run welcome",
"dev": "denon run ./app.ts",
"build": "aleph build"
},
"files": ["./app.ts"]
}
You only have to add the files
option in the run.json
file and it will only
observe the files and folders that you specify, if you leave the array empty it
will observe all the files.
// run.json
{
"scripts": {
"dev": "go build"
},
"files": ["./main.go"]
}
For the script alias to use rsap
you just need to add the --watch
or -w
flag to the end of the command alias:
trex run dev --watch [...args]
It can be used with any CLI tool, compiler or interpreter.
run.yml
or run.yaml
)
YAML is also acceptable (- scripts:
dev: go build
- files:
- ./main.go
Limitations
A limitation of watch mode is that they do not restart the processes that never end (such as http servers). In those cases we recommend other alternatives, such as denon.
Virtual cli tool execution
Trex will auto detect cli file in the order of "cli.ts", "cli.js", "%pacakge-name%.ts", "%package-name%.js", "main.ts", "main.js", "mod.ts", "mod.js", "index.ts", "index.js". If you want to publish a cli package, name your cli file as either of above(e.g.
cli.ts
) in your root package.
trex exec
allows you to run many cli tools hosted at deno.land/x
trex exec aleph init hello_world
trex will fetch aleph's cli and run without installing it locally using
deno install
, you can also specify the version you want to use.
trex exec aleph@v0.2.28 init hello_world
Permissions (perms)
You can also specify the permissions that the cli will use.
Just pass the --perms
flag followed by comma-separated permissions:
trex exec --perms env,read,write,net denon run ./app.ts
env
: --allow-envwrite
: --allow-writeread
: --allow-readnet
: --allow-netrun
: --allow-runreload
: --reloadplugin
: --allow-pluginhrtime
: --allow-hrtimeA
: --allow-all
Warning: if you don't specify the permissions, they are all automatically granted to you
You can also combine this with the command alias:
// run.json
{
"scripts": {
"denon": "trex exec denon run"
},
"files": ["./app.ts"]
}
trex run denon ./app.ts
And yes, you can do this:
trex exec trex exec trex exec ....
Even this:
trex exec land trex exec land trex exec ....
This functionality is heavily inspired by
npx and
land. If you need another alternative to trex exec
to use in deno
, land this is a great option.
Local configuration and global configuration (experimental)
When you work with import maps trex by default will handle everything using an import_map.json file, but what if I want to use an import-map.json or an importMap.json instead?
That's what the global settings are for! Basically it allows you to change the behavior of trex, with respect to the file where the dependencies will be handled.
Example
trex global-config --importMap=import-map.json
This will change the default name from import_map.json to import-map.json. to obtain the name or format used you must execute the following command.
trex global-config --getImportMap
But what happens if I am working with several people on the same project and we
have different configurations? For these cases there is the local configuration
or local configuration file - trex.config.json
:
// trex.config.json
{
"importMap": "importMap.json"
}
This will tell trex that the format for the import map will be the one dictated by the config file. This allows that there are no problems with the different local configurations of each developer since the configuration file only affects the scope of the project.
Note: the file
trex.config.json
must be at the same level(scope) as the import map for trex to detect it.
Thee hierarchy that trex respects with the configurations is the following:
graph TD
trex.config.json --> LocalGlobalConfig
LocalGlobalConfig --> defaultTrexConfig
Purge a package or URL
If you want delete a package or url package from cache memory in deno, you can
use the purge
command to remove from cache memory.
trex purge oak
This finds the oak
package in the import_map.json
, and removes it from the
cache.
Purging with full URL specifiers
trex purge https://deno.land/x/oak@v6.3.1/mod.ts
Checking a package's dependency tree
trex tree fs
This prints out something like:
local: C:\Users\trex\AppData\Local\deno\deps\https\deno.land\434fe4a7be02d1875....
type: TypeScript
compiled: C:\Users\trex\AppData\Local\deno\gen\https\deno.land\std\fs\mod.ts.js
map: C:\Users\trex\AppData\Local\deno\gen\https\deno.land\std\fs\mod.ts.js.map
deps:
https://deno.land/std/fs/mod.ts
├─┬ https://deno.land/std/fs/empty_dir.ts
│ └─┬ https://deno.land/std/path/mod.ts
│ ├── https://deno.land/std/path/_constants.ts
│ ├─┬ https://deno.land/std/path/win32.ts
│ │ ├── https://deno.land/std/path/_constants.ts
│ │ ├─┬ https://deno.land/std/path/_util.ts
│ │ │ └── https://deno.land/std/path/_constants.ts
│ │ └── https://deno.land/std/_util/assert.ts
│ ├─┬ https://deno.land/std/path/posix.ts
│ │ ├── https://deno.land/std/path/_constants.ts
│ │ └── https://deno.land/std/path/_util.ts
│ ├─┬ https://deno.land/std/path/common.ts
│ │ └─┬ https://deno.land/std/path/separator.ts
│ │ └── https://deno.land/std/path/_constants.ts
│ ├── https://deno.land/std/path/separator.ts
│ ├── https://deno.land/std/path/_interface.ts
│ └─┬ https://deno.land/std/path/glob.ts
│ ├── https://deno.land/std/path/separator.ts
│ ├─┬ https://deno.land/std/path/_globrex.ts
│ │ └── https://deno.land/std/path/_constants.ts
│ ├── https://deno.land/std/path/mod.ts
│ └── https://deno.land/std/_util/assert.ts
├─┬ https://deno.land/std/fs/ensure_dir.ts
# ... full response was truncated for brevity
Integrity checking & lock files
Let's say your module depends on a remote module. When you compile your module for the first time, it is retrieved, compiled and cached. It will remain this way until you run your module on a new machine (e.g. in production) or reload the cache.
But what happens if the content in the remote url is changed? This could lead to your production module running with different dependency code than your local module. Deno's solution to avoid this is to use integrity checking and lock files.
Create a lockfile:
deno cache --lock=lock.json --lock-write file.ts
The above generates a lock.json
file.
If you use import_map.json
in input file, you can specify it:
deno cache --lock=lock.json --lock-write --import-map=import_map.json --unstable file.ts
See deno document for more info.
Complete example
Simple std server
http
and fmt
:
Install trex install --map http fmt
Create a simple server
// server.ts
import { serve } from "http/server.ts";
import { green } from "fmt/colors.ts";
const server = serve({ port: 8000 });
console.log(green("http://localhost:8000/"));
for await (const req of server) {
req.respond({ body: "Hello World\n" });
}
Start the server
deno run --allow-net --import-map=import_map.json --unstable server.ts
Warning: it is important to use --import-map=import_map.json --unstable
oak
Adding third-party packages: Example usingoak
Install the master version of trex i --map oak
This adds oak
to the import_map.json
file:
{
"imports": {
"http/": "https://deno.land/std/http/",
"fmt/": "https://deno.land/std/fmt/",
"oak": "https://deno.land/x/oak/mod.ts"
}
}
Then create an oak application.
Note the import
statement, thanks to the import_map.json
addition:
// app.ts
import { Application } from "oak";
const app = new Application();
app.use((ctx) => {
ctx.response.body = "Hello World!";
});
await app.listen({ port: 8000 });
Run the server
deno run --allow-net --import-map=import_map.json --unstable app.ts
Warning: it is important to use --import-map=import_map.json --unstable
Contributing
Contributions are welcome, see CONTRIBUTING GUIDELINES.
Licensing
Trex is licensed under the MIT license.