@ryanatkn/gro 0.129.6 → 0.129.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +30 -30
- package/dist/config.d.ts +3 -3
- package/dist/gen.test.js +1 -1
- package/dist/invoke.js +1 -1
- package/dist/package.js +2 -2
- package/dist/src_json.d.ts +1 -1
- package/dist/src_json.js +1 -1
- package/package.json +1 -1
- package/src/lib/config.ts +3 -3
- package/src/lib/gen.test.ts +1 -1
- package/src/lib/invoke.ts +1 -1
- package/src/lib/package.ts +2 -2
- package/src/lib/src_json.ts +1 -1
- package/dist/docs/README.gen.md.d.ts +0 -6
- package/dist/docs/README.gen.md.d.ts.map +0 -1
- package/dist/docs/README.gen.md.js +0 -53
- package/dist/docs/README.md +0 -20
- package/dist/docs/build.md +0 -41
- package/dist/docs/config.md +0 -213
- package/dist/docs/deploy.md +0 -32
- package/dist/docs/dev.md +0 -40
- package/dist/docs/gen.md +0 -269
- package/dist/docs/gro_plugin_sveltekit_app.md +0 -113
- package/dist/docs/package_json.md +0 -33
- package/dist/docs/plugin.md +0 -50
- package/dist/docs/publish.md +0 -137
- package/dist/docs/task.md +0 -391
- package/dist/docs/tasks.gen.md.d.ts +0 -3
- package/dist/docs/tasks.gen.md.d.ts.map +0 -1
- package/dist/docs/tasks.gen.md.js +0 -66
- package/dist/docs/tasks.md +0 -37
- package/dist/docs/test.md +0 -52
- package/src/lib/docs/README.gen.md.ts +0 -63
- package/src/lib/docs/README.md +0 -20
- package/src/lib/docs/build.md +0 -41
- package/src/lib/docs/config.md +0 -213
- package/src/lib/docs/deploy.md +0 -32
- package/src/lib/docs/dev.md +0 -40
- package/src/lib/docs/gen.md +0 -269
- package/src/lib/docs/gro_plugin_sveltekit_app.md +0 -113
- package/src/lib/docs/package_json.md +0 -33
- package/src/lib/docs/plugin.md +0 -50
- package/src/lib/docs/publish.md +0 -137
- package/src/lib/docs/task.md +0 -391
- package/src/lib/docs/tasks.gen.md.ts +0 -90
- package/src/lib/docs/tasks.md +0 -37
- package/src/lib/docs/test.md +0 -52
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
# `package.json`
|
|
2
|
-
|
|
3
|
-
Gro extends [`package.json`](https://docs.npmjs.com/cli/v10/configuring-npm/package-json)
|
|
4
|
-
with additional functionality.
|
|
5
|
-
|
|
6
|
-
## `public` packages
|
|
7
|
-
|
|
8
|
-
Setting `"public": true` in `package.json` opts into
|
|
9
|
-
behavior designed for public open source projects:
|
|
10
|
-
|
|
11
|
-
- [`gro_plugin_sveltekit_app`](./gro_plugin_sveltekit_app.md)
|
|
12
|
-
copies `package.json` from your project root to your
|
|
13
|
-
SvelteKit static directory at `.well-known/package.json` during `vite build`,
|
|
14
|
-
mapping it with the optional
|
|
15
|
-
[`well_known_package_json` option](./gro_plugin_sveltekit_app.md#well_known_package_json).
|
|
16
|
-
- `gro_plugin_sveltekit_app` outputs `.well-known/src.json`
|
|
17
|
-
using the `exports` property of `package.json` during `vite build`,
|
|
18
|
-
containing additional information about the source modules,
|
|
19
|
-
mapping it with the optional
|
|
20
|
-
[`well_known_src_json` option](./gro_plugin_sveltekit_app.md#well_known_src_json).
|
|
21
|
-
- If you define a truthy value for the
|
|
22
|
-
[`well_known_src_files` option](./gro_plugin_sveltekit_app.md#well_known_src_files),
|
|
23
|
-
`gro_plugin_sveltekit_app` outputs `.well-known/src/` by
|
|
24
|
-
copying over `src/` during `vite build`, filtered by `well_known_src_files` if it's a function.
|
|
25
|
-
This is costly (usually more than doubling the final output size
|
|
26
|
-
of the code files in bytes, not counting images and such),
|
|
27
|
-
it slows the build because it copies your entire source tree (sorry to hard drives),
|
|
28
|
-
and it exposes your source code the same as the built files.
|
|
29
|
-
|
|
30
|
-
> ⚠️ Setting `"public": true` in `package.json` exposes your `package.json`
|
|
31
|
-
> and `src.json` metadata with your other built files by default!
|
|
32
|
-
> Further opting in with `well_known_src_files` exposes your actual source files.
|
|
33
|
-
> If your built files are public, that means these additional files are also public.
|
package/src/lib/docs/plugin.md
DELETED
|
@@ -1,50 +0,0 @@
|
|
|
1
|
-
# plugin
|
|
2
|
-
|
|
3
|
-
During the [`gro dev`](dev.md) and [`gro build`](build.md) tasks,
|
|
4
|
-
Gro uses `Plugin`s to support custom usecases outside of the normal build pipeline.
|
|
5
|
-
|
|
6
|
-
In this early implementation of plugins in Gro,
|
|
7
|
-
plugins run serially, in the order they are returned from `plugins` in the `gro.config.ts`.
|
|
8
|
-
Each step of Gro's build processes - `gro dev` for development and `gro build` for production -
|
|
9
|
-
runs a method of each plugin, batched together as `setup -> adapt -> teardown`,
|
|
10
|
-
with some behavioral inconsistencies:
|
|
11
|
-
|
|
12
|
-
- `adapt` only runs during production aka `gro build`
|
|
13
|
-
- `teardown` does not run for `gro dev` in the default `watch` mode,
|
|
14
|
-
but it does run with `gro dev --no-watch`
|
|
15
|
-
- there should probably be a finalization step that runs `teardown` on uncaught exceptions
|
|
16
|
-
|
|
17
|
-
The API needs to be improved for more advanced usecases,
|
|
18
|
-
currently it offers little flexibility -
|
|
19
|
-
we'll follow the Vite/SvelteKit APIs probably. (`pre` etc)
|
|
20
|
-
Maybe let you map the array of each method batch. (is that possible with those?)
|
|
21
|
-
|
|
22
|
-
Gro's builtin plugins:
|
|
23
|
-
|
|
24
|
-
- [`@ryanatkn/gro_plugin_server`](../gro_plugin_server.ts)
|
|
25
|
-
- [`@ryanatkn/gro_plugin_sveltekit_library`](../gro_plugin_sveltekit_library.ts)
|
|
26
|
-
- [`@ryanatkn/gro_plugin_sveltekit_app`](../gro_plugin_sveltekit_app.ts)
|
|
27
|
-
- [`@ryanatkn/gro_plugin_gen`](../gro_plugin_gen.ts)
|
|
28
|
-
(currently disabled, will be replaced with an esbuild plugin)
|
|
29
|
-
|
|
30
|
-
Also see [`config.plugin` in the config docs](config.md#plugin)
|
|
31
|
-
and usage in [the default config](../gro.config.default.ts).
|
|
32
|
-
The default config detects which plugins are included by inspecting the current project.
|
|
33
|
-
|
|
34
|
-
The implementation is at [`src/lib/plugin.ts`](../plugin.ts) with more details.
|
|
35
|
-
|
|
36
|
-
```ts
|
|
37
|
-
export interface Plugin<T_Plugin_Context extends Plugin_Context = Plugin_Context> {
|
|
38
|
-
name: string;
|
|
39
|
-
setup?: (ctx: T_Plugin_Context) => void | Promise<void>;
|
|
40
|
-
adapt?: (ctx: T_Plugin_Context) => void | Promise<void>;
|
|
41
|
-
teardown?: (ctx: T_Plugin_Context) => void | Promise<void>;
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
export interface Plugin_Context<T_Args = object> extends Task_Context<T_Args> {
|
|
45
|
-
dev: boolean;
|
|
46
|
-
watch: boolean;
|
|
47
|
-
}
|
|
48
|
-
```
|
|
49
|
-
|
|
50
|
-
The `adapt` step only runs for production during `gro build`, taking after SvelteKit adapters.
|
package/src/lib/docs/publish.md
DELETED
|
@@ -1,137 +0,0 @@
|
|
|
1
|
-
# publish
|
|
2
|
-
|
|
3
|
-
Here's how to publish a new version of a repo with Gro, including for Gro itself.
|
|
4
|
-
|
|
5
|
-
## svelte-package
|
|
6
|
-
|
|
7
|
-
Gro uses SvelteKit's [`@sveltejs/package`](https://kit.svelte.dev/docs/packaging)
|
|
8
|
-
with the task `gro publish` to publish packages to npm.
|
|
9
|
-
Gro's default config enables [`@ryanatkn/gro/gro_plugin_sveltekit_library.js`](../gro_plugin_sveltekit_library.ts)
|
|
10
|
-
if it detects `@sveltejs/package` installed as a dependency in the package.json.
|
|
11
|
-
|
|
12
|
-
```bash
|
|
13
|
-
# enable `gro publish` to publish to npm:
|
|
14
|
-
npm i -D @sveltejs/package # enables `@ryanatkn/gro/gro_plugin_sveltekit_library.js`
|
|
15
|
-
gro sync # updates package.json "exports"
|
|
16
|
-
git commit -am "..."
|
|
17
|
-
# `gro publish` calls `svelte-package`
|
|
18
|
-
```
|
|
19
|
-
|
|
20
|
-
## login to npm
|
|
21
|
-
|
|
22
|
-
```bash
|
|
23
|
-
npm whoami # check if you're logged in
|
|
24
|
-
|
|
25
|
-
# not logged in?
|
|
26
|
-
npm login # and follow the instructions
|
|
27
|
-
```
|
|
28
|
-
|
|
29
|
-
> more about [`npm login`](https://docs.npmjs.com/v6/commands/npm-adduser)
|
|
30
|
-
|
|
31
|
-
## using changesets
|
|
32
|
-
|
|
33
|
-
The [`gro publish` task](https://github.com/ryanatkn/gro/blob/main/src/lib/publish.task.ts)
|
|
34
|
-
integrates with [Changesets](https://github.com/changesets/changesets)
|
|
35
|
-
to publish packages to [npm](https://npmjs.com/). Internally the task calls both
|
|
36
|
-
[`changeset version`](https://github.com/changesets/changesets/blob/main/packages/README.md#version)
|
|
37
|
-
and
|
|
38
|
-
[`changeset publish`](https://github.com/changesets/changesets/blob/main/packages/README.md#publish).
|
|
39
|
-
|
|
40
|
-
Gro does not include Changesets as a dependency.
|
|
41
|
-
Install it globally or local to your repo
|
|
42
|
-
(I prefer global, it's not a light dependency):
|
|
43
|
-
|
|
44
|
-
```bash
|
|
45
|
-
npm i -g @changesets/cli # install globally
|
|
46
|
-
npm i -D @changesets/cli # or install local to your repo
|
|
47
|
-
```
|
|
48
|
-
|
|
49
|
-
To [init Changesets](https://github.com/changesets/changesets/blob/main/packages/README.md#init)
|
|
50
|
-
in a repo or [add](https://github.com/changesets/changesets/blob/main/packages/README.md#add)
|
|
51
|
-
a changeset to an already-inited repo, use `gro changeset`:
|
|
52
|
-
|
|
53
|
-
```bash
|
|
54
|
-
gro changeset # inits or adds a changeset
|
|
55
|
-
gro changeset --help # view the args docs
|
|
56
|
-
|
|
57
|
-
# `gro changeset` is equivalent to:
|
|
58
|
-
changeset init # if needed -- prefix with `npx ` if installed only locally
|
|
59
|
-
changeset
|
|
60
|
-
git add .changeset/$FILE
|
|
61
|
-
# TODO include a `git commit` flag or default behavior, maybe `gro changeset "message"`
|
|
62
|
-
```
|
|
63
|
-
|
|
64
|
-
After initing, optionally configure and install a custom changelog package
|
|
65
|
-
in the `"changelog"` property of the newly created `.changeset/config.json`:
|
|
66
|
-
|
|
67
|
-
```diff
|
|
68
|
-
# .changeset/config.json
|
|
69
|
-
- "changelog": "@changesets/changelog",
|
|
70
|
-
+ "changelog": "@changesets/changelog-git",
|
|
71
|
-
```
|
|
72
|
-
|
|
73
|
-
```bash
|
|
74
|
-
npm i -D @changesets/changelog-git # a minimal package that requires no GitHub auth
|
|
75
|
-
```
|
|
76
|
-
|
|
77
|
-
Gro inits `"access"` based on the package.json `"private": true` value.
|
|
78
|
-
To manually configure the `access` property:
|
|
79
|
-
|
|
80
|
-
```diff
|
|
81
|
-
# .changeset/config.json
|
|
82
|
-
- "access": "public",
|
|
83
|
-
+ "access": "restricted",
|
|
84
|
-
```
|
|
85
|
-
|
|
86
|
-
See [the Changesets docs](https://github.com/changesets/changesets) for more.
|
|
87
|
-
|
|
88
|
-
## GitHub API setup
|
|
89
|
-
|
|
90
|
-
Gro currently expects repos to be on GitHub to generate changelogs with Changesets.
|
|
91
|
-
(sorry, maybe in the future we'll support other forges)
|
|
92
|
-
|
|
93
|
-
Gro modifies the barebones changelog generated by `@changesets/changelog-git`,
|
|
94
|
-
doing things like linkifying commit hashes or linking to PRs if they exist.
|
|
95
|
-
The difference between Gro's version and `@changesets/changelog-github` is that Gro
|
|
96
|
-
doesn't require a token for authorization for public repos,
|
|
97
|
-
and Gro makes some different choices for usability.
|
|
98
|
-
|
|
99
|
-
Gro calls the GitHub API using the environment variable `GITHUB_TOKEN_SECRET` for authorization,
|
|
100
|
-
which is a [GitHub token](https://github.com/settings/tokens)
|
|
101
|
-
(with "public access" for public repos, no options selected)
|
|
102
|
-
in either `process.env`, a project-local `.env`, or the parent directory at `../.env`
|
|
103
|
-
(currently optional to read public repos, but it's recommended regardless,
|
|
104
|
-
and you'll need to select options to support private repos).
|
|
105
|
-
|
|
106
|
-
You'll get a warning if the token is unavailable, but for light usage you won't hit rate limts.
|
|
107
|
-
|
|
108
|
-
## `gro publish`
|
|
109
|
-
|
|
110
|
-
The publish task builds the project, bumps the version, publishes to npm,
|
|
111
|
-
commits the changes, and then pushes the commit and tag.
|
|
112
|
-
|
|
113
|
-
Ensure `"dist"` is in the `"files"` property of `package.json`:
|
|
114
|
-
|
|
115
|
-
```json
|
|
116
|
-
"files": [
|
|
117
|
-
"dist"
|
|
118
|
-
],
|
|
119
|
-
```
|
|
120
|
-
|
|
121
|
-
Then publish:
|
|
122
|
-
|
|
123
|
-
```bash
|
|
124
|
-
gro publish
|
|
125
|
-
gro publish --help # view the options
|
|
126
|
-
gro publish -- svelte-package -w # forward options
|
|
127
|
-
```
|
|
128
|
-
|
|
129
|
-
See [the SvelteKit packaging docs](https://kit.svelte.dev/docs/packaging) for more.
|
|
130
|
-
|
|
131
|
-
If `changeset publish` fails during `gro publish`,
|
|
132
|
-
the task exits without pushing anything to the remote origin.
|
|
133
|
-
It does however create the version commit and tag.
|
|
134
|
-
A common failure is not being logged into npm. (see the instructions above)
|
|
135
|
-
If the builds are correct but `changeset publish` failed,
|
|
136
|
-
and you don't want to undo the version commit and tag,
|
|
137
|
-
you can continue manually with `changeset publish` or `npm publish`.
|
package/src/lib/docs/task.md
DELETED
|
@@ -1,391 +0,0 @@
|
|
|
1
|
-
# task
|
|
2
|
-
|
|
3
|
-
> task runner for
|
|
4
|
-
> [Gro](https://github.com/ryanatkn/gro)
|
|
5
|
-
|
|
6
|
-
## contents
|
|
7
|
-
|
|
8
|
-
- [what](#what)
|
|
9
|
-
- [usage](#usage)
|
|
10
|
-
- [why?](#why)
|
|
11
|
-
|
|
12
|
-
## what
|
|
13
|
-
|
|
14
|
-
A Gro `Task` is just an object with a `run` function and some optional metadata.
|
|
15
|
-
Gro prefers conventions and code over configuration,
|
|
16
|
-
and its task runner leverages the filesystem as the API
|
|
17
|
-
and defers composition to the user in regular TypeScript modules.
|
|
18
|
-
|
|
19
|
-
> Tasks are a special Gro construct.
|
|
20
|
-
> If you want to simply execute regular TypeScript files,
|
|
21
|
-
> use the `gro run` task, which works like the normal `node` CLI
|
|
22
|
-
> but uses the Gro loader to support `.ts`.
|
|
23
|
-
|
|
24
|
-
- tasks are defined by naming files with the `.task.ts` and `.task.js` suffixes
|
|
25
|
-
- tasks can be run from the CLI via a name (`gro foo`),
|
|
26
|
-
which uses Gro's task resolution (see more below),
|
|
27
|
-
or via paths that are absolute (`gro /path/to/foo`) or explicitly relative (`gro ./foo`)
|
|
28
|
-
- Gro automatically discovers all `*.task.ts|js` files
|
|
29
|
-
in its configurable directory, so creating a new task
|
|
30
|
-
is as simple as [creating a new file](#define-a-task), no config needed
|
|
31
|
-
(defaults to `src/lib`, see the config option [`task_root_dirs`](./config.md#task_root_dirs))
|
|
32
|
-
- to view [the available tasks](https://github.com/ryanatkn/gro/blob/main/src/lib/docs/tasks.md)
|
|
33
|
-
run `gro` with no arguments
|
|
34
|
-
- task definitions are just objects with an async `run` function and some optional properties,
|
|
35
|
-
so composing tasks is explicit in your code, just like any other module
|
|
36
|
-
(but there's also the helper `invoke_task`, see more below)
|
|
37
|
-
- the task object's `run` function has access to CLI args
|
|
38
|
-
- tasks optionally use [zod](https://github.com/colinhacks/zod) schemas
|
|
39
|
-
for `args` types, runtime parsing with helpful validation errors,
|
|
40
|
-
and generated help docs (`gro foo --help`), with DRY co-located definitions
|
|
41
|
-
- it's easy to call into or override any of Gro's builtin tasks,
|
|
42
|
-
like [`gro test`](/src/lib/test.task.ts) and [`gro gen`](/src/lib/gen.task.ts) -
|
|
43
|
-
your own versions with the same name take precedence, and you can invoke the base
|
|
44
|
-
tasks using the `gro/` prefix, e.g. `gro gro/test`
|
|
45
|
-
(tasks are also copy-paste friendly! just update the imports)
|
|
46
|
-
- it's fast because it imports only the modules imported by your invoked tasks, not every task's
|
|
47
|
-
|
|
48
|
-
The task runner's purpose is to provide an ergonomic interface
|
|
49
|
-
between the CLI, build tools, and app code.
|
|
50
|
-
As a developer, it's nice to be able to reuse TypeScript modules in every context.
|
|
51
|
-
|
|
52
|
-
## usage
|
|
53
|
-
|
|
54
|
-
### show all available tasks
|
|
55
|
-
|
|
56
|
-
```bash
|
|
57
|
-
# This looks through `src/lib` in both the current working directory and Gro's source
|
|
58
|
-
# for all files matching `*.task.ts|js` and logs them out with their args docs.
|
|
59
|
-
$ gro
|
|
60
|
-
```
|
|
61
|
-
|
|
62
|
-
The [config](./config.md) option [task_root_dirs](./config.md#task_root_dirs)
|
|
63
|
-
tells Gro where to search for tasks.
|
|
64
|
-
|
|
65
|
-
> Currently, only the first directory specified in `task_root_dirs` that's found on the filesystem
|
|
66
|
-
> will be used to automatically discover tasks, like when running `gro` without args.
|
|
67
|
-
> Please open an issue if you would like to see Gro be able to discover
|
|
68
|
-
> tasks in more than one directory - it will take some reworking of internals
|
|
69
|
-
> but it seems like the right design.
|
|
70
|
-
|
|
71
|
-
### show tasks in a directory
|
|
72
|
-
|
|
73
|
-
```bash
|
|
74
|
-
# Logs all `*.task.ts|js` files in `src/lib/some/dir` and `gro/src/lib/some/dir`.
|
|
75
|
-
# If no tasks are found, it displays an error.
|
|
76
|
-
$ gro some/dir
|
|
77
|
-
```
|
|
78
|
-
|
|
79
|
-
> To learn more about the Gro CLI path conventions,
|
|
80
|
-
> see [the `input_paths` comments](../input_path.ts)
|
|
81
|
-
|
|
82
|
-
### run a task
|
|
83
|
-
|
|
84
|
-
```bash
|
|
85
|
-
# This runs `src/lib/some/file.task.ts`,
|
|
86
|
-
# or if it doesn't exist, `gro/src/lib/some/file.task.ts`.
|
|
87
|
-
# If neither exists, it displays an error.
|
|
88
|
-
$ gro some/file arg1 arg2 --arg3 example
|
|
89
|
-
|
|
90
|
-
# This runs `gro/src/lib/some/file.task.ts` directly
|
|
91
|
-
# without checking the current working directory,
|
|
92
|
-
# and displays an error if it doesn't exist.
|
|
93
|
-
$ gro gro/some/file
|
|
94
|
-
```
|
|
95
|
-
|
|
96
|
-
### define a task
|
|
97
|
-
|
|
98
|
-
```ts
|
|
99
|
-
// src/lib/some/file.task.ts
|
|
100
|
-
import type {Task} from '@ryanatkn/gro';
|
|
101
|
-
|
|
102
|
-
export const task: Task = {
|
|
103
|
-
run: async ({log, args}) => {
|
|
104
|
-
log.info('CLI args', args); // => {_: ['arg1', 'arg2'], arg3: 'example'}
|
|
105
|
-
await whatever();
|
|
106
|
-
},
|
|
107
|
-
};
|
|
108
|
-
```
|
|
109
|
-
|
|
110
|
-
The minimum:
|
|
111
|
-
|
|
112
|
-
```ts
|
|
113
|
-
// src/lib/some/minimal.task.ts
|
|
114
|
-
export const task = {
|
|
115
|
-
run: () => console.log('a minimal example'),
|
|
116
|
-
};
|
|
117
|
-
```
|
|
118
|
-
|
|
119
|
-
Minimum with [`Args`](#task-args):
|
|
120
|
-
|
|
121
|
-
```ts
|
|
122
|
-
// src/lib/some/withargs.task.ts
|
|
123
|
-
import type {Task} from '@ryanatkn/gro';
|
|
124
|
-
import {z} from 'zod';
|
|
125
|
-
|
|
126
|
-
export const Args = z
|
|
127
|
-
.object({
|
|
128
|
-
arg: z.number({description: 'example number arg'}).default(2),
|
|
129
|
-
})
|
|
130
|
-
.strict();
|
|
131
|
-
export type Args = z.infer<typeof Args>;
|
|
132
|
-
|
|
133
|
-
export const task: Task = {
|
|
134
|
-
Args,
|
|
135
|
-
run: async ({args}) => {
|
|
136
|
-
args.arg; // `number` that defaults to `2`
|
|
137
|
-
},
|
|
138
|
-
};
|
|
139
|
-
```
|
|
140
|
-
|
|
141
|
-
### type `Task`
|
|
142
|
-
|
|
143
|
-
```ts
|
|
144
|
-
import type {Task} from '@ryanatkn/gro';
|
|
145
|
-
|
|
146
|
-
export interface Task<
|
|
147
|
-
T_Args = Args, // same as `z.infer<typeof Args>`
|
|
148
|
-
T_Args_Schema extends z.ZodType = z.ZodType,
|
|
149
|
-
T_Return = unknown,
|
|
150
|
-
> {
|
|
151
|
-
run: (ctx: Task_Context<T_Args>) => Promise<T_Return>;
|
|
152
|
-
summary?: string;
|
|
153
|
-
Args?: T_Args_Schema;
|
|
154
|
-
}
|
|
155
|
-
```
|
|
156
|
-
|
|
157
|
-
### type `Task_Context`
|
|
158
|
-
|
|
159
|
-
```ts
|
|
160
|
-
import type {Task_Context} from '@ryanatkn/gro';
|
|
161
|
-
|
|
162
|
-
export interface Task_Context<T_Args = object> {
|
|
163
|
-
args: T_Args;
|
|
164
|
-
config: Gro_Config;
|
|
165
|
-
sveltekit_config: Parsed_Sveltekit_Config;
|
|
166
|
-
log: Logger;
|
|
167
|
-
timings: Timings;
|
|
168
|
-
invoke_task: (task_name: string, args?: Args, config?: Gro_Config) => Promise<void>;
|
|
169
|
-
}
|
|
170
|
-
```
|
|
171
|
-
|
|
172
|
-
### run a task inside another task with `invoke_task`
|
|
173
|
-
|
|
174
|
-
Because Gro tasks are just functions,
|
|
175
|
-
you can directly import them from within other tasks and run them.
|
|
176
|
-
However, we recommend using the `invoke_task` helper
|
|
177
|
-
for its ergonomics and automatic logging and diagnostics.
|
|
178
|
-
|
|
179
|
-
The `invoke_task` helper uses Gro's task resolution rules
|
|
180
|
-
to allow user code to override builtin tasks.
|
|
181
|
-
For example, Gro's `check.task.ts` calls `invoke_task('test')`
|
|
182
|
-
so that it calls your `src/lib/test.task.ts` if it exists
|
|
183
|
-
and falls back to `gro/src/lib/test.task.ts` if not.
|
|
184
|
-
|
|
185
|
-
It's less important to use `invoke_task` over explicit imports in user code
|
|
186
|
-
because you don't need to rely on the task override rules to get desired behavior,
|
|
187
|
-
but the logging and diagnostics it provides are nice to have.
|
|
188
|
-
|
|
189
|
-
```bash
|
|
190
|
-
gro some/file
|
|
191
|
-
```
|
|
192
|
-
|
|
193
|
-
```ts
|
|
194
|
-
// src/lib/some/file.task.ts
|
|
195
|
-
import type {Task} from '@ryanatkn/gro';
|
|
196
|
-
|
|
197
|
-
export const task: Task = {
|
|
198
|
-
run: async ({args, invoke_task}) => {
|
|
199
|
-
// runs `src/lib/some/file.task.ts`, automatically forwarding `args`
|
|
200
|
-
await invoke_task('some/file');
|
|
201
|
-
// as documented above, the following is similar but lacks nice features:
|
|
202
|
-
// await (await import('./some/file.task.js')).run(ctx);
|
|
203
|
-
|
|
204
|
-
// runs `src/lib/other/file.task.ts` and falls back to `gro/src/other/file.task.ts`,
|
|
205
|
-
// forwarding both custom args and a different event emitter (warning: spaghetti)
|
|
206
|
-
await invoke_task(
|
|
207
|
-
'other/file',
|
|
208
|
-
{...args, optionally: 'extended'},
|
|
209
|
-
optionalEventEmitterForSubtree,
|
|
210
|
-
optionalDevFlagForSubtree,
|
|
211
|
-
optionalFsForSubtree,
|
|
212
|
-
);
|
|
213
|
-
|
|
214
|
-
// runs `gro/src/lib/other/file.task.ts` directly, bypassing any local version
|
|
215
|
-
await invoke_task('gro/other/file');
|
|
216
|
-
},
|
|
217
|
-
};
|
|
218
|
-
```
|
|
219
|
-
|
|
220
|
-
### hook into one of [Gro's builtin tasks](../docs/tasks.md)
|
|
221
|
-
|
|
222
|
-
```bash
|
|
223
|
-
# This normally loads Gro's version of the test task at `gro/src/lib/test.task.ts`,
|
|
224
|
-
# but projects can define `src/lib/test.task.ts` to extend or replace it.
|
|
225
|
-
$ gro test
|
|
226
|
-
```
|
|
227
|
-
|
|
228
|
-
```ts
|
|
229
|
-
// src/lib/test.task.ts
|
|
230
|
-
import type {Task} from '@ryanatkn/gro';
|
|
231
|
-
|
|
232
|
-
export const task: Task = {
|
|
233
|
-
run: async ({args, invoke_task}) => {
|
|
234
|
-
await doSomethingFirst();
|
|
235
|
-
// As discussed in the `invoke_task` section above,
|
|
236
|
-
// it's possible to `import {task as groBuiltinTestTask} from '@ryanatkn/gro/test.task.js'`
|
|
237
|
-
// and then call `groBuiltinTestTask.run` directly,
|
|
238
|
-
// but that loses some important benefits.
|
|
239
|
-
// Still, the task is available to import if you want it for any reason!
|
|
240
|
-
await invoke_task('gro/test', {...args, optionally: 'extended'}, newEventEmitterForSubtree);
|
|
241
|
-
await emailEveryoneWithTestResults();
|
|
242
|
-
},
|
|
243
|
-
};
|
|
244
|
-
```
|
|
245
|
-
|
|
246
|
-
Note that when hooking into [Gro's builtin tasks](../docs/tasks.md),
|
|
247
|
-
like `test.task.ts` above, you don't have to call its version.
|
|
248
|
-
You can copy/paste an existing task and customize it,
|
|
249
|
-
rewrite a task from scratch, compose them together, or whatever is needed for each project.
|
|
250
|
-
|
|
251
|
-
### task `Args`
|
|
252
|
-
|
|
253
|
-
The **`Args` property** of each `Task` (not the task context **`args` param** described above!)
|
|
254
|
-
is an optional [zod](https://github.com/colinhacks/zod) schema.
|
|
255
|
-
Using zod has some benefits:
|
|
256
|
-
|
|
257
|
-
- automatically print helpful text on the CLI with `gro` and `gro taskname --help`
|
|
258
|
-
- automated args parsing/validation using the schema with initialized defaults
|
|
259
|
-
- type safety using args in tasks
|
|
260
|
-
- concise source of truth
|
|
261
|
-
|
|
262
|
-
```ts
|
|
263
|
-
// src/lib/dosomething.task.ts
|
|
264
|
-
import type {Task} from '@ryanatkn/gro';
|
|
265
|
-
import type {z} from 'zod';
|
|
266
|
-
|
|
267
|
-
export const Args = z
|
|
268
|
-
.object({
|
|
269
|
-
_: z.array(z.string(), {description: 'rest args'}).default([]),
|
|
270
|
-
yepyep: z.string({description: 'helpful info'}).default('ya'),
|
|
271
|
-
okcool: z.number({description: 'that prints to the CLI'}).default(1234),
|
|
272
|
-
maybee: z.boolean({description: 'and optional args work too'}),
|
|
273
|
-
})
|
|
274
|
-
.strict();
|
|
275
|
-
export type Args = z.infer<typeof Args>;
|
|
276
|
-
|
|
277
|
-
export const task: Task<Args> = {
|
|
278
|
-
Args,
|
|
279
|
-
run: async ({args}) => {
|
|
280
|
-
args._; // string[]
|
|
281
|
-
args.yepyep; // string
|
|
282
|
-
args.okcool; // number
|
|
283
|
-
args.maybee; // boolean | undefined
|
|
284
|
-
},
|
|
285
|
-
};
|
|
286
|
-
```
|
|
287
|
-
|
|
288
|
-
Running `gro dosomething --help` prints the schema information in a friendly format.
|
|
289
|
-
|
|
290
|
-
### task args forwarding
|
|
291
|
-
|
|
292
|
-
Some builtin Gro tasks call external commands like
|
|
293
|
-
[`svelte-kit`](https://github.com/sveltejs/kit),
|
|
294
|
-
[`vite`](https://github.com/vitejs/vite),
|
|
295
|
-
[`uvu`](https://github.com/lukeed/uvu),
|
|
296
|
-
[`tsc`](https://github.com/microsoft/typescript),
|
|
297
|
-
and [`prettier`](https://github.com/prettier/prettier).
|
|
298
|
-
Gro supports generic agnostic args forwarding to these tasks via the `--` pattern:
|
|
299
|
-
for example, to forward args to `svelte-kit` and `uvu`, no matter which task invokes them,
|
|
300
|
-
use `gro taskname --taskname-arg -- uvu --arg1 neat --arg2 22 -- svelte-kit --arg3`.
|
|
301
|
-
|
|
302
|
-
Any number of sections separated by `--` may be defined, and the first arg
|
|
303
|
-
that appears after each `--` is assumed to be the CLI command.
|
|
304
|
-
If `gro taskname` or its invoked tasks don't call `uvu` or `svelte-kit`,
|
|
305
|
-
the `--` args will be ignored.
|
|
306
|
-
|
|
307
|
-
There's one special case for task args forwarding: running Gro tasks.
|
|
308
|
-
If `gro` is the command following a `--`, e.g. the second `gro` of
|
|
309
|
-
`gro taskname -- gro taskname2 --a --b`,
|
|
310
|
-
then `--a` and `--b` will be forwarded to `taskname2`.
|
|
311
|
-
Forwarded args to Gro tasks override direct args, including args to `invoke_task`,
|
|
312
|
-
so `gro taskname --a 1 -- gro taskname --a 2` will invoke `taskname` with `{a: 2}`.
|
|
313
|
-
|
|
314
|
-
The `invoke_task` helper in the task context forwards the CLI args for the specified task.
|
|
315
|
-
CLI args take precedence over args passed directly to `invoke_task`.
|
|
316
|
-
This may not always be the desired behavior, but it gives the user more control,
|
|
317
|
-
because you can't change args in code you don't control.
|
|
318
|
-
|
|
319
|
-
### throwing errors
|
|
320
|
-
|
|
321
|
-
If a task encounters an error, normally it should throw rather than exiting the process.
|
|
322
|
-
This defers control to the caller, like your own parent tasks.
|
|
323
|
-
|
|
324
|
-
Often, errors that tasks encounter do not need a stack trace,
|
|
325
|
-
and we don't want the added noise to be logged.
|
|
326
|
-
To suppress logging the stack trace for an error,
|
|
327
|
-
throw a `Task_Error`.
|
|
328
|
-
|
|
329
|
-
```ts
|
|
330
|
-
import {Task, Task_Error} from '@ryanatkn/gro';
|
|
331
|
-
|
|
332
|
-
export const task: Task = {
|
|
333
|
-
run: async () => {
|
|
334
|
-
if (someErrorCondition) {
|
|
335
|
-
throw new Task_Error('We hit a known error - ignore the stack trace!');
|
|
336
|
-
}
|
|
337
|
-
},
|
|
338
|
-
};
|
|
339
|
-
```
|
|
340
|
-
|
|
341
|
-
## why?
|
|
342
|
-
|
|
343
|
-
Gro usage on the command line (`gro <task_name_or_directory> [...flags]`)
|
|
344
|
-
looks a lot like using `node`.
|
|
345
|
-
What makes Gro different?
|
|
346
|
-
|
|
347
|
-
- The `*.task.ts` file name convention signals to Gro that your application
|
|
348
|
-
contains task modules that conform to some interface.
|
|
349
|
-
This allows them to be discoverable by convention,
|
|
350
|
-
so running `gro` displays them all without any config, and it puts generic handles on them,
|
|
351
|
-
enabling various verbs (e.g. `run`) and
|
|
352
|
-
structured metadata (e.g. `summary` and args schemas for docs and validation).
|
|
353
|
-
- Tasks aren't just a script on the filesystem, they can be composed and inspected in code.
|
|
354
|
-
Task modules do not have any side effects when imported,
|
|
355
|
-
while Node scripts just execute when imported -
|
|
356
|
-
their primary purpose is to cause side effects, and they're limited to the filesystem API.
|
|
357
|
-
This is useful in many cases - for example `gro taskname --help`
|
|
358
|
-
inspects the args schema and other metadata to print help to the console,
|
|
359
|
-
and `gro` prints the `summary` property of each task it discovers.
|
|
360
|
-
There's lots more to explore here, like task composition
|
|
361
|
-
and improved DX with new capabilities.
|
|
362
|
-
- Tasks support CLI args that are validated and typesafe
|
|
363
|
-
via colocated Zod schemas with minimal boilerplate.
|
|
364
|
-
- Tasks are forwarded CLI args when called via `invoke_task` in other tasks,
|
|
365
|
-
so running `gro foo -- gro bar --a b` passes `{a: 'b'}` automatically to the `bar` task.
|
|
366
|
-
- Module resolution differs and leverages discoverability:
|
|
367
|
-
- When a task name is given to Gro,
|
|
368
|
-
it first searches `src/lib/` in the current working directory and
|
|
369
|
-
falls back to searching the Gro directory.
|
|
370
|
-
This allows your code and CLI commands to compose Gro's builtin tasks
|
|
371
|
-
or override them without changing how you invoke them.
|
|
372
|
-
Gro reserves no special behavior for its own commands -
|
|
373
|
-
`gro test`, `gro gen`, and all the rest are just tasks that all follow the same rules.
|
|
374
|
-
(see its task at [`src/lib/test.task.ts`](/src/lib/test.task.ts)).
|
|
375
|
-
- When a directory is given to Gro,
|
|
376
|
-
it prints all of the tasks found inside it,
|
|
377
|
-
both relative to the current working directory and Gro's directory.
|
|
378
|
-
So when you run `gro` by itself,
|
|
379
|
-
it prints all tasks available both in your project and Gro.
|
|
380
|
-
- The trailing `.task.ts` in the file path provided to `gro` is optional,
|
|
381
|
-
so for example, `gro foo/bar` is the same as `gro foo/bar.task.ts`, a nice convenience.
|
|
382
|
-
|
|
383
|
-
## :turtle:<sub>:turtle:</sub><sub><sub>:turtle:</sub></sub>
|
|
384
|
-
|
|
385
|
-
Gro's task runner has many inspirations:
|
|
386
|
-
|
|
387
|
-
- [mgutz/task](https://github.com/mgutz/task)
|
|
388
|
-
- [Gulp](https://github.com/gulpjs/gulp)
|
|
389
|
-
- [@mgutz](https://github.com/mgutz)' [Projmate](https://github.com/projmate/projmate-core)
|
|
390
|
-
- [Grunt](https://github.com/gruntjs/grunt)
|
|
391
|
-
- [npm scripts](https://docs.npmjs.com/v8/using-npm/scripts)
|