Skip to content

Commit

Permalink
add docs about creating a server plugin
Browse files Browse the repository at this point in the history
  • Loading branch information
joshmossas committed Aug 7, 2024
1 parent a3cee6c commit b798f47
Showing 1 changed file with 127 additions and 0 deletions.
127 changes: 127 additions & 0 deletions docs/implementing-an-arri-server.md
Original file line number Diff line number Diff line change
Expand Up @@ -193,3 +193,130 @@ arri codegen AppDefinition.json # json app def
arri codegen AppDefinition.ts # ts app def
arri codegen https://myapi.com/__definition # http endpoint
```

## Bonus: Create a plugin for the Arri CLI

Server plugins dictate what happens when you run `arri dev` and `arri build`.

In order to create a server plugin use the `defineServerConfig` helper from the `arri` package:

```ts
import { defineServerConfig } from "arri";

const myCustomConfig = defineServerConfig({
devArgs: {
// define what CLI args the "dev" command accepts
foo: {
type: "string",
required: false,
},
},
devFn(args, generators) {
console.log(args.foo); // foo is now available here
},
buildArgs: {
// define what CLI args the "build" command accepts
bar: {
type: "boolean",
},
},
buildFn(args, generators) {
console.log(args.bar); // bar is now available here
},
});
```

Then you simply register your plugin in the arri config file:

```ts
export default defineConfig({
server: myCustomPlugin,
generators: [...]
})
```

Now the Arri CLI will use the functions in `devFn` and `buildFn` for the `dev` and `build` commands respectively.

```bash
arri dev --foo "hello world" # outputs "hello world"
arri build --bar # outputs false
```

You can also wrap this helper in a function if you have some options that you want users to input without needing to be passed as CLI args.

```ts
function myCustomServer(options: { port: number }) {
return defineServerConfig({...});
}
```

```ts
export default defineConfig({
server: myCustomServer({
port: 3000,
}),
generators: [...],
});
```

### Example: A simple Go server plugin

Let's say we've configured a go generator that reads our go application and outputs an [App Definition](/specifications/arri_app_definition.md) at the following location `.arri/__definition.json`. We can set up a simple plugin that looks like this.

```ts
const goServer = defineServerConfig({
devArgs: {},
devFn(_, generators) {
// run go generate
execSync("go generate", {
stdio: "inherit",
});
// read the App Definition
const appDef = JSON.parse(
readFileSync(".arri/__definition.json", "utf8"),
) as AppDefinition;
// run all of the registered Arri generators
await Promise.all(generators.map((item) => item.generator(appDef)));
// start run application
execSync("go run main.go", {
stdio: 'inherit'
});
},
buildArgs: {},
buildFn(_, generators) {
// run "go generate"
execSync("go generate", {
stdio: "inherit",
});
// read the App Definition
const appDef = JSON.parse(
readFileSync(".arri/__definition.json", "utf8"),
) as AppDefinition;
// run all of the registered Arri generators
await Promise.all(generators.map((item) => item.generator(appDef)));
// run "go build"
execSync("go build", {
stdio: "inherit"
})
},
});

export default defineConfig({
server: goServer,
generators: [...]
})
```

That's it. Now whenever we call `arri dev` it will:

- output JSON app definition file
- run the arri code generators against that file
- start the go server

And when we call `arri build` it will:

- output JSON app definition file
- run the arri code generators against that file
- build the go application

Now there's a lot more we can add to this such as file watchers and whatnot. It's just typescript go so you can basically do whatever you want.

0 comments on commit b798f47

Please sign in to comment.