Skip to content

Commit bb68c2b

Browse files
committed
feat: run assets bundler when running dev server
1 parent 4c101f3 commit bb68c2b

File tree

4 files changed

+87
-16
lines changed

4 files changed

+87
-16
lines changed

src/dev_server.ts

Lines changed: 49 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,13 @@ import getPort from 'get-port'
1111
import picomatch from 'picomatch'
1212
import type tsStatic from 'typescript'
1313
import { type ExecaChildProcess } from 'execa'
14+
import type { Watcher } from '@poppinss/chokidar-ts'
1415
import { cliui, type Logger } from '@poppinss/cliui'
1516
import { EnvLoader, EnvParser } from '@adonisjs/env'
1617

17-
import { run } from './run.js'
1818
import { watch } from './watch.js'
19+
import { run, runNode } from './run.js'
1920
import type { DevServerOptions } from './types.js'
20-
import type { Watcher } from '@poppinss/chokidar-ts'
2121

2222
/**
2323
* Instance of CLIUI
@@ -45,6 +45,7 @@ export class DevServer {
4545
#isMetaFileWithReloadsEnabled: picomatch.Matcher
4646
#isMetaFileWithReloadsDisabled: picomatch.Matcher
4747
#watcher?: ReturnType<Watcher['watch']>
48+
#assetsServerProcess?: ExecaChildProcess<string>
4849
#onError?: (error: any) => any
4950
#onClose?: (exitCode: number) => any
5051

@@ -141,7 +142,7 @@ export class DevServer {
141142
* Starts the HTTP server
142143
*/
143144
#startHTTPServer(port: string, mode: 'blocking' | 'nonblocking') {
144-
this.#httpServerProcess = run(this.#cwd, {
145+
this.#httpServerProcess = runNode(this.#cwd, {
145146
script: this.#scriptFile,
146147
env: { PORT: port, ...this.#options.env },
147148
nodeArgs: this.#options.nodeArgs,
@@ -179,6 +180,35 @@ export class DevServer {
179180
})
180181
}
181182

183+
/**
184+
* Starts the assets bundler server. The assets bundler server process is
185+
* considered as the secondary process and therefore we do not perform
186+
* any cleanup if it dies.
187+
*/
188+
#startAssetsServer() {
189+
const assetsBundler = this.#options.assets
190+
if (!assetsBundler?.serve) {
191+
return
192+
}
193+
194+
this.#logger.info(`starting "${assetsBundler.driver}" dev server...`)
195+
this.#assetsServerProcess = run(assetsBundler.cmd, {
196+
script: this.#scriptFile,
197+
scriptArgs: this.#options.scriptArgs,
198+
})
199+
200+
this.#assetsServerProcess
201+
.then((result) => {
202+
this.#logger.warning(
203+
`"${assetsBundler.driver}" dev server closed with status code "${result.exitCode}"`
204+
)
205+
})
206+
.catch((error) => {
207+
this.#logger.warning(`unable to connect to "${assetsBundler.driver}" dev server`)
208+
this.#logger.fatal(error)
209+
})
210+
}
211+
182212
/**
183213
* Restart the development server
184214
*/
@@ -224,26 +254,36 @@ export class DevServer {
224254
this.#clearScreen()
225255
this.#logger.info('starting HTTP server...')
226256
this.#startHTTPServer(String(await this.#getPort()), 'nonblocking')
257+
258+
this.#startAssetsServer()
227259
}
228260

229261
/**
230262
* Start the development server in watch mode
231263
*/
232264
async startAndWatch(ts: typeof tsStatic, options?: { poll: boolean }) {
233-
this.#isWatching = true
234-
this.#clearScreen()
235-
236265
const port = String(await this.#getPort())
266+
this.#isWatching = true
237267

268+
this.#clearScreen()
238269
this.#logger.info('starting HTTP server...')
270+
239271
this.#startHTTPServer(port, 'blocking')
272+
this.#startAssetsServer()
240273

274+
/**
275+
* Create watcher using tsconfig.json file
276+
*/
241277
const output = watch(this.#cwd, ts, options || {})
242278
if (!output) {
243279
this.#onClose?.(1)
244280
return
245281
}
246282

283+
/**
284+
* Storing reference to watcher, so that we can close it
285+
* when HTTP server exists with error
286+
*/
247287
this.#watcher = output.chokidar
248288

249289
/**
@@ -253,6 +293,9 @@ export class DevServer {
253293
this.#logger.info('watching file system for changes...')
254294
})
255295

296+
/**
297+
* Cleanup when watcher dies
298+
*/
256299
output.chokidar.on('error', (error) => {
257300
this.#logger.warning('file system watcher failure')
258301
this.#logger.fatal(error)

src/run.ts

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
* file that was distributed with this source code.
88
*/
99

10-
import { execaNode } from 'execa'
10+
import { execaNode, execa } from 'execa'
1111
import type { RunOptions } from './types.js'
1212

1313
/**
@@ -24,9 +24,9 @@ const DEFAULT_NODE_ARGS = [
2424
]
2525

2626
/**
27-
* Runs a script as a child process and inherits the stdio streams
27+
* Runs a Node.js script as a child process and inherits the stdio streams
2828
*/
29-
export function run(cwd: string | URL, options: RunOptions) {
29+
export function runNode(cwd: string | URL, options: RunOptions) {
3030
const childProces = execaNode(options.script, options.scriptArgs, {
3131
nodeOptions: DEFAULT_NODE_ARGS.concat(options.nodeArgs),
3232
preferLocal: true,
@@ -40,3 +40,20 @@ export function run(cwd: string | URL, options: RunOptions) {
4040

4141
return childProces
4242
}
43+
44+
/**
45+
* Runs a script as a child process and inherits the stdio streams
46+
*/
47+
export function run(cwd: string | URL, options: Omit<RunOptions, 'nodeArgs'>) {
48+
const childProces = execa(options.script, options.scriptArgs, {
49+
preferLocal: true,
50+
windowsHide: false,
51+
localDir: cwd,
52+
cwd,
53+
buffer: false,
54+
stdio: 'inherit',
55+
env: options.env,
56+
})
57+
58+
return childProces
59+
}

src/types.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,17 @@ export type DevServerOptions = {
3636
pattern: string
3737
reloadServer: boolean
3838
}[]
39+
assets?:
40+
| {
41+
serve: false
42+
driver?: string
43+
cmd?: string
44+
}
45+
| {
46+
serve: true
47+
driver: string
48+
cmd: string
49+
}
3950
}
4051

4152
/**

tests/run.spec.ts

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99

1010
import { pEvent } from 'p-event'
1111
import { test } from '@japa/runner'
12-
import { run } from '../src/run.js'
12+
import { run, runNode } from '../src/run.js'
1313

1414
test.group('Child process', () => {
1515
test('run typescript file as a child process', async ({ fs, assert }) => {
@@ -20,7 +20,7 @@ test.group('Child process', () => {
2020
`
2121
)
2222

23-
const childProcess = run(fs.basePath, { script: 'foo.ts', scriptArgs: [], nodeArgs: [] })
23+
const childProcess = runNode(fs.basePath, { script: 'foo.ts', scriptArgs: [], nodeArgs: [] })
2424
const payload = await pEvent(childProcess, 'message', { rejectionEvents: ['error'] })
2525

2626
await pEvent(childProcess, 'close', { rejectionEvents: ['error'] })
@@ -37,7 +37,7 @@ test.group('Child process', () => {
3737
`
3838
)
3939

40-
const childProcess = run(fs.basePath, {
40+
const childProcess = runNode(fs.basePath, {
4141
script: 'foo.ts',
4242
scriptArgs: ['--watch', '--foo=bar'],
4343
nodeArgs: [],
@@ -57,7 +57,7 @@ test.group('Child process', () => {
5757
`
5858
)
5959

60-
const childProcess = run(fs.basePath, {
60+
const childProcess = runNode(fs.basePath, {
6161
script: 'foo.ts',
6262
scriptArgs: ['--watch', '--foo=bar'],
6363
nodeArgs: ['--throw-deprecation'],
@@ -85,7 +85,7 @@ test.group('Child process', () => {
8585
`
8686
)
8787

88-
const childProcess = run(fs.basePath, { script: 'foo.ts', scriptArgs: [], nodeArgs: [] })
88+
const childProcess = runNode(fs.basePath, { script: 'foo.ts', scriptArgs: [], nodeArgs: [] })
8989
await pEvent(childProcess, 'close', { rejectionEvents: ['error'] })
9090
assert.equal(childProcess.exitCode, 0)
9191
})
@@ -98,7 +98,7 @@ test.group('Child process', () => {
9898
`
9999
)
100100

101-
const childProcess = run(fs.basePath, { script: 'foo.ts', scriptArgs: [], nodeArgs: [] })
101+
const childProcess = runNode(fs.basePath, { script: 'foo.ts', scriptArgs: [], nodeArgs: [] })
102102

103103
await pEvent(childProcess, 'close', { rejectionEvents: ['error'] })
104104
assert.equal(childProcess.exitCode, 1)
@@ -114,7 +114,7 @@ test.group('Child process', () => {
114114
`
115115
)
116116

117-
const childProcess = run(fs.basePath, { script: 'foo.ts', scriptArgs: [], nodeArgs: [] })
117+
const childProcess = runNode(fs.basePath, { script: 'foo.ts', scriptArgs: [], nodeArgs: [] })
118118
try {
119119
await childProcess
120120
} catch {

0 commit comments

Comments
 (0)