Skip to content

Commit 57446bf

Browse files
committed
Fix #17.
Also, switch to deno task dependencies.
1 parent 19ac0a7 commit 57446bf

File tree

4 files changed

+156
-48
lines changed

4 files changed

+156
-48
lines changed

.github/workflows/test.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,4 +14,4 @@ jobs:
1414
- uses: denoland/setup-deno@v2
1515
with:
1616
deno-version: v2.x
17-
- run: deno task test
17+
- run: DENO_JOBS=1 deno task test

deno.jsonc

Lines changed: 104 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -28,34 +28,120 @@
2828
"examples/hono/**/*.ts"
2929
]
3030
},
31+
32+
// WARNING!
33+
// AFAIK, these task dependencies are declared properly. (And in fact, a bit conservatively to keep things simple)
34+
// However, when run in parallel, I get errors that very much make it seem like dependency tasks haven't finished
35+
// before running the next task.
36+
// BUT, with the current state of the output of `deno task` when running parallel tasks, it's difficult to verify/debug this.
37+
// TODO: Once better logging is implemented, come back and try to debug this again:
38+
// See: https://github.com/denoland/deno/issues/27647
39+
//
40+
// Until then, run tasks with `DENO_JOBS=1 deno task ...`
3141
"tasks": {
32-
// Run the full test suite:
33-
"test": "deno task check && deno task examples:test && deno task test:jsx && deno task lints",
42+
"test": {
43+
"description": "Run the full test suite. Use DENO_JOBS=1",
44+
"command": "echo Task test 'done'",
45+
"dependencies": [
46+
"check",
47+
"examples:test",
48+
"test:jsx",
49+
"test:crashes"
50+
]
51+
},
3452

3553
// Since this directory has its own deno.jsonc, we need to test it explicitly:
36-
"test:jsx": "cd tests/jsx_config && deno test -A",
54+
"test:jsx": {
55+
"command": "cd tests/jsx_config && deno test -A",
56+
"dependencies": ["build"],
57+
},
58+
"test:crashes": {
59+
"command": "cd tests/crashes && deno test -A --quiet",
60+
"dependencies": ["build"]
61+
},
3762

38-
"check": "deno task check:main && deno task check:without-embedder && deno task examples:build && deno task examples:check && deno task check:publish",
39-
"check:main": "./tools/with-exports.ts deno check --doc",
40-
"check:publish": "deno publish --dry-run --allow-dirty",
41-
"check:without-embedder": "cd examples/without-embedder; deno task check",
63+
// Runs code generation tasks. Depend on this to make sure file modifications have settled.
64+
"build": {
65+
"command": "echo Task build 'done'",
66+
"dependencies": ["oak:build", "hono:build"]
67+
},
4268

43-
"examples:check": "deno task oak:check && deno task hono:check",
44-
"examples:build": "deno task oak:build && deno task hono:build",
45-
"examples:test": "deno task oak:test && deno task hono:test",
69+
"check": {
70+
"command": "echo Task check 'done'",
71+
"dependencies": [
72+
"check:main",
73+
"examples:check",
74+
"check:publish",
75+
"lints",
76+
],
77+
},
78+
"check:main": {
79+
"command": "./tools/with-exports.ts deno check --doc",
80+
"dependencies": ["build"],
81+
},
82+
"check:publish": {
83+
"command": "deno publish --dry-run --allow-dirty",
84+
"dependencies": [
85+
"build",
86+
],
87+
},
88+
"check:without-embedder": {
89+
"command": "cd examples/without-embedder; deno task check",
90+
"dependencies": ["build"],
91+
},
4692

47-
"oak:check": "cd examples/with-embedder; deno task check",
48-
"oak:test": "cd examples/with-embedder && deno test -A --trace-leaks",
93+
"examples:check": {
94+
"command": "echo Task examples:check 'done'",
95+
"dependencies": [
96+
"oak:check",
97+
"hono:check",
98+
"check:without-embedder"
99+
]
100+
},
101+
"examples:build": {
102+
"command": "echo Task examples:build 'done'",
103+
"dependencies": ["build"],
104+
},
105+
"examples:test": {
106+
"command": "echo Task examples:test 'done'",
107+
"dependencies": ["oak:test", "hono:test"],
108+
},
49109
"oak:build": "cd examples/with-embedder && deno task build-embeds",
50-
"oak:start": "cd examples/with-embedder && deno task start",
110+
"oak:check": {
111+
"command": "cd examples/with-embedder; deno task check",
112+
"dependencies": ["build"]
113+
},
114+
"oak:test": {
115+
"command": "cd examples/with-embedder && deno test -A --trace-leaks",
116+
"dependencies": ["build"]
117+
},
118+
"oak:start": {
119+
"command": "cd examples/with-embedder && deno task start",
120+
"dependencies": ["build"]
121+
},
51122

52-
"hono:check": "cd examples/hono; deno task check",
53-
"hono:test": "cd examples/hono && deno test -A",
54123
"hono:build": "cd examples/hono && deno task build-embeds",
55-
"hono:start": "cd examples/hono && deno task start",
124+
"hono:check": {
125+
"command": "cd examples/hono; deno task check",
126+
"dependencies": ["build"]
127+
},
128+
"hono:test": {
129+
"command": "cd examples/hono && deno test -A",
130+
"dependencies": ["build"]
131+
},
132+
"hono:start": {
133+
"command": "cd examples/hono && deno task start",
134+
"dependencies": ["build"]
135+
},
56136

57-
"lints": "deno lint && deno task lints:docs",
58-
"lints:docs": "./tools/with-exports.ts deno doc --lint"
137+
"lints": {
138+
"command": "deno lint",
139+
"dependencies": ["build", "lints:docs"],
140+
},
141+
"lints:docs": {
142+
"command": "./tools/with-exports.ts deno doc --lint",
143+
"dependencies": ["build"],
144+
}
59145
},
60146
"lint": {
61147
"rules": {

src/mod.ts

Lines changed: 33 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -407,7 +407,11 @@ class PluginConverter implements Converter {
407407
// updates in the future. For now, it's just re-do everything:
408408
if (event.kind == "quiet") {
409409
console.log("Changes detected, regenerating...")
410-
await this.convert()
410+
try {
411+
await this.convert()
412+
} catch (e) {
413+
throw new Error("Error running plugin conversion", {cause: e})
414+
}
411415
}
412416
}
413417
}
@@ -487,10 +491,11 @@ export async function main({options, args}: MainArgs) {
487491
default: options.mainTask ?? "start"
488492
})
489493
.action(async (cliOptions) => {
490-
await devMode({
494+
const code = await devMode({
491495
...options,
492496
...{mainTask: cliOptions.task}
493497
})
498+
Deno.exit(code)
494499
})
495500

496501
const buildCommand = new Command()
@@ -536,7 +541,7 @@ export interface MainArgs {
536541
*
537542
* This is expected to be the main way you generate embedded files.
538543
*/
539-
async function devMode(opts: Options) {
544+
async function devMode(opts: Options): Promise<number> {
540545
let baseDir = dirFrom(opts.importMeta)
541546
let taskName = opts.mainTask ?? "start"
542547

@@ -549,21 +554,33 @@ async function devMode(opts: Options) {
549554
}
550555

551556
console.log("Starting server:");
552-
(async () => {
553-
const cmd = new Deno.Command("deno", {
554-
args: ["task", taskName],
555-
stdout: "inherit",
556-
})
557-
const output = await cmd.output()
558-
const { code: statusCode} = output
559-
console.log(`task "${taskName}" exited with status: ${statusCode}`)
560-
// TODO: Clean way to shut down converters?
561-
Deno.exit(statusCode)
562-
})()
563557

564-
for (let c of converters) {
565-
c.watch()
558+
const cmd = new Deno.Command("deno", {
559+
args: ["task", taskName],
560+
})
561+
await using proc = cmd.spawn()
562+
const mainTaskFinished = async () => {
563+
const status = await proc.status
564+
const msg = `task "${taskName}" exited with status: ${status.code}`
565+
if (status.code == 0) {
566+
console.log(msg)
567+
return
568+
}
569+
throw new Error(msg)
570+
}
571+
572+
let promises = [mainTaskFinished(), ...converters.map(c => c.watch())]
573+
574+
// If this resolves, there was either an error in one of the converters, or the main server task finished.
575+
let code = 0
576+
try {
577+
await Promise.race(promises)
578+
} catch (e) {
579+
console.log(e)
580+
code = 1
566581
}
582+
console.log("Exiting dev mode.")
583+
return code
567584
}
568585

569586
/**

src/plugins/esbuild.ts

Lines changed: 18 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -74,20 +74,25 @@ export class ESBuild implements WholeDirPlugin {
7474
...(await detectDenoOptions(sourceDir))
7575
} as const
7676

77-
// TODO: This requires holding all build results in memory.
78-
// Maybe build to tempdir instead?
79-
let build = await esbuild.build(options)
80-
81-
for (let outFile of build.outputFiles) {
82-
await emit({
83-
file: outFile.path,
84-
contents: outFile.contents,
85-
})
86-
}
77+
try {
78+
79+
// TODO: This requires holding all build results in memory.
80+
// Maybe build to tempdir instead?
81+
let build = await esbuild.build(options)
82+
83+
for (let outFile of build.outputFiles) {
84+
await emit({
85+
file: outFile.path,
86+
contents: outFile.contents,
87+
})
88+
}
8789

88-
// esbuild seems to start a long-running process. If you don't stop
89-
// it, Deno waits around forever for it to finish, instead of exiting.
90-
await esbuild.stop()
90+
} finally {
91+
// esbuild seems to start a long-running process. If you don't stop
92+
// it, Deno waits around forever for it to finish, instead of exiting.
93+
await esbuild.stop()
94+
// TODO: This doesn't work well if we have multiple instances of the ESBuild plugin running! Gah!
95+
}
9196
}
9297

9398
}

0 commit comments

Comments
 (0)