Skip to content
当前有符合你浏览器所设置语言的版本,是否前往zh-CN版本的网站?
There is a version suitable for your browser's language settings. Would you like to go to the zh-CN language of the site?
HomeDocument

Command

H1

Yes, Milkio can be used not only to build servers behind the client side, but also to develop small tools that can be used in the terminal.

Writing

Any API located in the /apps/$/ directory is treated as a command. When using commands, it feels like using a regular API, with the difference being the format of the parameters. Create a /apps/$/say.ts file and try saying hello to the world…?

/* eslint-disable no-console */
import { defineApi, defineApiTest } from "milkio"
export const api = defineApi({
meta: {},
async action(
params: {
commands: Array<string>;
options: Record<string, string | true>;
},
context
) {
console.log(`hello world!`)
console.log(`Your Params:`, params)
},
})

You may notice that you now have two parameters: commands and options. These parameters are automatically parsed from argv by Milkio. Take a look at the following example, which shows the executed command and the obtained params.

Terminal window
./app say hello world --foo=bar --enable
params: {
commands: ["hello", "world"],
options: {
foo: "bar",
enable: true,
},
}

Usage

Before bundling, we can use our command with bun command.

Terminal window
bun command say hello world --foo=bar --enable

We can also bundle our application into a binary file. In the scripts section of our /package.json, modify the build script to bundle our command instead of the HTTP server.

"build:command": "bun build ./run-command.ts --splitting --sourcemap=inline --outdir=./dist --target=bun --minify",

Run the build command, and you will have a new file named app in your directory.

Terminal window
npm run build

Try running it!

Terminal window
./app say hello world --foo=bar --enable

Default Command

When executed directly, Milkio will try to find a command named default.

For example, when running ./app or bun command, it will actually execute your /src/apps/$/default.ts file.

Command Not Found

When a command is not found, Milkio will execute the notFoundHandler method defined in your /run-command.ts file. The event object contains the executed command name and any accompanying params.

/run-command.ts
async function command() {
const commandHandler = defineCommandHandler(await milkio, {
notFoundHandler(event) {
console.log("command not found", event)
}
})
await commandHandler(process.argv)
}

Interactive CLI

Bun provides built-in methods for creating an interactive CLI.

console.log(prompt("What's your sign?"))
console.log(alert("Get ready to move on!"))
console.log(confirm("Do you really want to leave?"))

$ Shell

Bun’s $ Shell feature is very powerful.

import { $ } from "bun";
await echo "Hello World!"`; // Hello World!

Get the output of a shell command as text:

import { $ } from "bun";
const welcome = await echo "Hello World!"`.text();
console.log(welcome); // Hello World!\n

Pass parameters:

import { $ } from "bun";
const name = "World";
await echo "Hello ${name}!"`; // Hello World!

To avoid potential security issues, Bun’s $ Shell parameterizes template string interpolation. This means that the following approach will not work as expected:

import { $ } from "bun";
const path = "-a /";
await ls ${path}`; // Will not work

You can use raw to disable this protection:

import { $ } from "bun";
const path = "-a /";
await ls ${{raw: path }}`; // Works as expected

For more usage, please refer to the $ Shell documentation.

Starting an HTTP Server with a Command

Sometimes, we may need to develop an application that includes both commands and an HTTP server, and start the HTTP server with a specific command.

Thanks to Milkio’s excellent modularity, it’s easy to combine the two. You just need to copy the code from /run-serve.ts into your command.

import { defineApi, defineHttpHandler, envToNumber } from "milkio"
import { env } from "node:process"
import { milkio } from "../../../milkio"
export const api = defineApi({
meta: {},
async action(params: { commands: Array<string>; options: Record<string, string | true>; }, context) {
const httpHandler = defineHttpHandler(await milkio)
// if you are using Bun
Bun.serve({
port: envToNumber(env.PORT, 9000),
fetch(request) {
return httpHandler({ request })
}
})
},
})