Skip to content

Commit 19d6abf

Browse files
committed
Migrate to domstack-sync
1 parent 30cbfda commit 19d6abf

7 files changed

Lines changed: 125 additions & 98 deletions

File tree

bin.js

Lines changed: 22 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ import { readPackage } from 'read-pkg'
1919
import { addPackageDependencies } from 'write-package'
2020

2121
import { copyFile } from './lib/helpers/copy-file.js'
22-
import { DomStack } from './index.js'
22+
import { DomStack, createLogger } from './index.js'
2323
import { DomStackAggregateError } from './lib/helpers/domstack-aggregate-error.js'
2424
import { generateTreeData } from './lib/helpers/generate-tree-data.js'
2525
import { askYesNo } from './lib/helpers/cli-prompt.js'
@@ -201,6 +201,8 @@ domstack eject actions:
201201

202202
/** @type {DomStackOpts} */
203203
const opts = {}
204+
const logger = createLogger('info')
205+
opts.logger = logger
204206

205207
if (argv['ignore']) opts.ignore = String(argv['ignore']).split(',')
206208
if (argv['target']) opts.target = String(argv['target']).split(',')
@@ -219,11 +221,10 @@ domstack eject actions:
219221

220222
async function quit () {
221223
if (domStack.watching) {
222-
const results = await domStack.stopWatching()
223-
console.log(results)
224-
console.log('watching stopped')
224+
await domStack.stopWatching()
225+
logger.info('Watching stopped')
225226
}
226-
console.log('\nquitting cleanly')
227+
logger.info('Quitting cleanly')
227228
process.exit(0)
228229
}
229230

@@ -258,22 +259,24 @@ domstack eject actions:
258259
process.exit(1)
259260
}
260261
} else {
261-
const initialResults = await domStack.watch({
262+
await domStack.watch({
262263
serve: !argv['watch-only'],
264+
onInitialBuild: (initialResults) => {
265+
console.log(tree(generateTreeData(cwd, src, dest, initialResults)))
266+
if (initialResults?.warnings?.length > 0) {
267+
console.log(
268+
'\nThere were build warnings:\n'
269+
)
270+
}
271+
for (const warning of initialResults?.warnings) {
272+
if ('message' in warning) {
273+
console.log(` ${warning.message}`)
274+
} else {
275+
console.warn(warning)
276+
}
277+
}
278+
},
263279
})
264-
console.log(tree(generateTreeData(cwd, src, dest, initialResults)))
265-
if (initialResults?.warnings?.length > 0) {
266-
console.log(
267-
'\nThere were build warnings:\n'
268-
)
269-
}
270-
for (const warning of initialResults?.warnings) {
271-
if ('message' in warning) {
272-
console.log(` ${warning.message}`)
273-
} else {
274-
console.warn(warning)
275-
}
276-
}
277280
}
278281
}
279282

examples/default-layout/package.json

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,17 +7,11 @@
77
"start": "npm run watch",
88
"build": "npm run clean && domstack",
99
"clean": "rm -rf public && mkdir -p public",
10-
"watch": "npm run clean && run-p watch:*",
11-
"watch:serve": "browser-sync start --server 'public' --files 'public'",
12-
"watch:domstack": "npm run build -- --watch"
10+
"watch": "npm run clean && domstack --watch"
1311
},
1412
"dependencies": {
1513
"@domstack/static": "file:../../."
1614
},
17-
"devDependencies": {
18-
"browser-sync": "^2.26.7",
19-
"npm-run-all2": "^6.0.0"
20-
},
2115
"keywords": [],
2216
"author": "Bret Comnes <bcomnes@gmail.com> (https://bret.io/)",
2317
"license": "MIT"

examples/string-layouts/package.json

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,17 +6,11 @@
66
"start": "npm run watch",
77
"build": "npm run clean && domstack",
88
"clean": "rm -rf public && mkdir -p public",
9-
"watch": "npm run clean && run-p watch:*",
10-
"watch:serve": "browser-sync start --server 'public' --files 'public'",
11-
"watch:domstack": "npm run build -- --watch"
9+
"watch": "npm run clean && domstack --watch"
1210
},
1311
"author": "Bret Comnes <bcomnes@gmail.com> (https://bret.io/)",
1412
"license": "MIT",
1513
"dependencies": {
1614
"@domstack/static": "file:../../."
17-
},
18-
"devDependencies": {
19-
"browser-sync": "^2.26.7",
20-
"npm-run-all2": "^6.0.0"
2115
}
2216
}

index.js

Lines changed: 61 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
* @import { GlobalDataFunction, AsyncGlobalDataFunction, WorkerBuildStepResult, GlobalDataFunctionParams } from './lib/build-pages/index.js'
1212
* @import { BuildOptions, BuildContext } from 'esbuild'
1313
* @import { PageInfo, TemplateInfo } from './lib/identify-pages.js'
14+
* @import { BsInstance } from '@domstack/sync'
1415
*/
1516
import { once } from 'events'
1617
import assert from 'node:assert'
@@ -21,7 +22,7 @@ import makeArray from 'make-array'
2122
import ignore from 'ignore'
2223
import { watch as cpxWatch } from 'cpx2'
2324
import { inspect } from 'util'
24-
import browserSync from 'browser-sync'
25+
import { createLogger as createSyncLogger, createServer } from '@domstack/sync'
2526
import { find } from '@11ty/dependency-tree-typescript'
2627

2728
import { getCopyGlob } from './lib/build-static/index.js'
@@ -50,6 +51,13 @@ import { ensureDest } from './lib/helpers/ensure-dest.js'
5051
import { DomStackAggregateError } from './lib/helpers/domstack-aggregate-error.js'
5152

5253
export { PageData } from './lib/build-pages/page-data.js'
54+
export { wrapPinoLogger } from '@domstack/sync'
55+
56+
const LOG_PREFIX = '[domstack]'
57+
58+
export function createLogger (level = 'info', streams = {}, options = {}) {
59+
return createSyncLogger(level, streams, { prefix: LOG_PREFIX, ...options })
60+
}
5361

5462
/**
5563
* @typedef {BuildOptions} BuildOptions
@@ -154,9 +162,10 @@ export class DomStack {
154162
/** @type {Readonly<CurrentOpts & { ignore: string[] }>} */ opts
155163
/** @type {FSWatcher?} */ #watcher = null
156164
/** @type {any[]?} */ #cpxWatchers = null
157-
/** @type {browserSync.BrowserSyncInstance?} */ #browserSyncServer = null
165+
/** @type {BsInstance?} */ #syncServer = null
158166
/** @type {BuildContext?} */ #esbuildContext = null
159167
/** @type {SiteData?} */ #siteData = null
168+
/** @type {ReturnType<typeof createLogger>} */ #logger
160169

161170
// Watch maps (rebuilt after every full rebuild)
162171
/** @type {Map<string, Set<string>>} depFilepath → Set<layoutName> */
@@ -192,17 +201,19 @@ export class DomStack {
192201
this.#src = src
193202
this.#dest = dest
194203

195-
const copyDirs = opts?.copy ?? []
204+
const { logger, ...buildOpts } = opts
205+
const copyDirs = buildOpts?.copy ?? []
196206

197-
this.opts = {
198-
...opts,
207+
this.opts = /** @type {Readonly<CurrentOpts & { ignore: string[] }>} */ ({
208+
...buildOpts,
199209
ignore: [
200210
...DEFAULT_IGNORES,
201211
basename(dest),
202212
...copyDirs.map(dir => basename(dir)),
203-
...makeArray(opts.ignore),
213+
...makeArray(buildOpts.ignore),
204214
],
205-
}
215+
})
216+
this.#logger = logger ?? createLogger('info')
206217

207218
if (copyDirs && copyDirs.length > 0) {
208219
const absDest = resolve(this.#dest)
@@ -229,10 +240,12 @@ export class DomStack {
229240
* Build and watch a domstack build
230241
* @param {object} [params]
231242
* @param {boolean} params.serve
243+
* @param {(results: Results) => void | Promise<void>} [params.onInitialBuild]
232244
* @return {Promise<Results>}
233245
*/
234246
async watch ({
235247
serve,
248+
onInitialBuild,
236249
} = {
237250
serve: true,
238251
}) {
@@ -268,7 +281,7 @@ export class DomStack {
268281
pageBuildResults,
269282
}
270283
buildLogger(report)
271-
console.log('Initial JS, CSS and Page Build Complete')
284+
this.#logger.info('Initial JS, CSS and page build complete')
272285
} catch (err) {
273286
errorLogger(err)
274287
if (!(err instanceof DomStackAggregateError)) throw new Error('Non-aggregate error thrown', { cause: err })
@@ -278,38 +291,29 @@ export class DomStack {
278291
// Build watch maps after initial build
279292
await this.#rebuildMaps(siteData)
280293

281-
// ── Copy watchers & browser-sync ─────────────────────────────────────
294+
// ── Copy watchers & dev server ───────────────────────────────────────
282295
const copyDirs = getCopyDirs(this.opts.copy)
283296

284297
this.#cpxWatchers = [
285298
cpxWatch(getCopyGlob(this.#src), this.#dest, { ignore: this.opts.ignore }),
286299
...copyDirs.map(copyDir => cpxWatch(copyDir, this.#dest))
287300
]
288-
if (serve) {
289-
const bs = browserSync.create()
290-
this.#browserSyncServer = bs
291-
bs.watch(basename(this.#dest), { ignoreInitial: true }).on('change', bs.reload)
292-
bs.init({
293-
server: this.#dest,
294-
})
295-
}
296-
297-
this.#cpxWatchers.forEach(w => {
298-
w.on('watch-ready', () => {
299-
console.log('Copy watcher ready')
300301

301-
w.on('copy', (/** @type{{ srcPath: string, dstPath: string }} */e) => {
302-
console.log(`Copy ${e.srcPath} to ${e.dstPath}`)
303-
})
302+
const copyWatchersReady = this.#cpxWatchers.map(async w => {
303+
w.on('copy', (/** @type{{ srcPath: string, dstPath: string }} */e) => {
304+
this.#logger.info({ srcPath: e.srcPath, dstPath: e.dstPath }, 'Copy file')
305+
})
304306

305-
w.on('remove', (/** @type{{ path: string }} */e) => {
306-
console.log(`Remove ${e.path}`)
307-
})
307+
w.on('remove', (/** @type{{ path: string }} */e) => {
308+
this.#logger.info({ path: e.path }, 'Remove file')
309+
})
308310

309-
w.on('watch-error', (/** @type{Error} */err) => {
310-
console.log(`Copy error: ${err.message}`)
311-
})
311+
w.on('watch-error', (/** @type{Error} */err) => {
312+
this.#logger.error({ err }, 'Copy error')
312313
})
314+
315+
await once(w, 'watch-ready')
316+
this.#logger.info('Copy watcher ready')
313317
})
314318

315319
// ── Chokidar watcher ─────────────────────────────────────────────────
@@ -340,7 +344,20 @@ export class DomStack {
340344

341345
this.#watcher = watcher
342346

343-
await once(watcher, 'ready')
347+
await Promise.all([
348+
...copyWatchersReady,
349+
once(watcher, 'ready'),
350+
])
351+
352+
await onInitialBuild?.(report)
353+
354+
if (serve) {
355+
this.#syncServer = await createServer({
356+
server: this.#dest,
357+
files: basename(this.#dest),
358+
logger: this.#logger.child({ component: 'sync' }, { prefix: '[domstack-sync]' }),
359+
})
360+
}
344361

345362
const enqueue = (/** @type {() => Promise<void>} */ fn) => {
346363
this.#buildLock = this.#buildLock.then(() => fn().catch(errorLogger))
@@ -367,7 +384,7 @@ export class DomStack {
367384
* Used for structural changes (add/unlink), global.vars.*, esbuild.settings.*.
368385
*/
369386
async #fullRebuild () {
370-
console.log('Triggering full rebuild...')
387+
this.#logger.info('Triggering full rebuild')
371388
// Dispose the old esbuild context
372389
if (this.#esbuildContext) {
373390
await this.#esbuildContext.dispose()
@@ -377,8 +394,7 @@ export class DomStack {
377394
const siteData = await identifyPages(this.#src, this.opts)
378395

379396
if (siteData.errors.length > 0) {
380-
console.error('identifyPages errors:')
381-
for (const err of siteData.errors) console.error(' ', err.message)
397+
this.#logger.error({ errors: siteData.errors.map(err => err.message) }, 'identifyPages errors')
382398
return
383399
}
384400

@@ -415,13 +431,12 @@ export class DomStack {
415431
)
416432

417433
if (isEsbuildEntry) {
418-
console.log(`"${changedBasename}" ${event}, restarting esbuild...`)
434+
this.#logger.info({ file: changedBasename, event }, 'Restarting esbuild')
419435

420436
// Re-identify pages to discover the new/removed entry point
421437
const siteData = await identifyPages(this.#src, this.opts)
422438
if (siteData.errors.length > 0) {
423-
console.error('identifyPages errors:')
424-
for (const err of siteData.errors) console.error(' ', err.message)
439+
this.#logger.error({ errors: siteData.errors.map(err => err.message) }, 'identifyPages errors')
425440
return
426441
}
427442

@@ -476,7 +491,7 @@ export class DomStack {
476491
await this.#rebuildMaps(siteData)
477492
} else {
478493
// Non-esbuild file: structural change (page, layout, template, config, etc.)
479-
console.log(`"${changedBasename}" ${event}, triggering full rebuild...`)
494+
this.#logger.info({ file: changedBasename, event }, 'Triggering full rebuild')
480495
return this.#fullRebuild()
481496
}
482497
}
@@ -640,19 +655,19 @@ export class DomStack {
640655

641656
// 2. global.vars.* → full rebuild (esbuild restart + all pages)
642657
if (globalVarsNames.some(n => changedBasename === n)) {
643-
console.log(`"${changedBasename}" changed, triggering full rebuild...`)
658+
this.#logger.info({ file: changedBasename }, 'Triggering full rebuild')
644659
return this.#fullRebuild()
645660
}
646661

647662
// 3. global.data.* → full page rebuild (no esbuild restart)
648663
if (globalDataNames.some(n => changedBasename === n)) {
649-
console.log(`"${changedBasename}" changed, rebuilding all pages...`)
664+
this.#logger.info({ file: changedBasename }, 'Rebuilding all pages')
650665
return this.#runPageBuild(siteData)
651666
}
652667

653668
// 4. esbuild.settings.* → full rebuild
654669
if (esbuildSettingsNames.some(n => changedBasename === n)) {
655-
console.log(`"${changedBasename}" changed, triggering full rebuild...`)
670+
this.#logger.info({ file: changedBasename }, 'Triggering full rebuild')
656671
return this.#fullRebuild()
657672
}
658673

@@ -667,7 +682,7 @@ export class DomStack {
667682
// esbuild's own watcher handles these. Stable filenames mean page HTML doesn't
668683
// change, so no page rebuild is needed.
669684
if (this.#esbuildEntryPoints.has(changedPath)) {
670-
console.log(`"${changedBasename}" changed, esbuild will handle rebundling.`)
685+
this.#logger.info({ file: changedBasename }, 'Esbuild will handle rebundling')
671686
return
672687
}
673688

@@ -681,7 +696,7 @@ export class DomStack {
681696
const pageFilterPaths = Array.from(affectedPages).map(p => p.pageFile.filepath)
682697
return this.#runPageBuild(siteData, pageFilterPaths, [])
683698
}
684-
console.log(`"${changedBasename}" changed but no pages use layout "${layoutName}", skipping.`)
699+
this.#logger.info({ file: changedBasename, layout: layoutName }, 'Layout changed but no pages use it; skipping')
685700
return
686701
}
687702
// Not a registered layout — fall through to dep checks
@@ -741,7 +756,7 @@ export class DomStack {
741756
}
742757

743758
// 13. No matching rule — skip.
744-
console.log(`"${changedBasename}" changed but did not match any rebuild rule, skipping.`)
759+
this.#logger.info({ file: changedBasename }, 'Changed file did not match any rebuild rule; skipping')
745760
}
746761

747762
async stopWatching () {
@@ -756,8 +771,8 @@ export class DomStack {
756771
await this.#esbuildContext.dispose()
757772
this.#esbuildContext = null
758773
}
759-
this.#browserSyncServer?.exit() // This will kill the process
760-
this.#browserSyncServer = null
774+
await this.#syncServer?.exit()
775+
this.#syncServer = null
761776
}
762777

763778
/**

lib/builder.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ import { ensureDest } from './helpers/ensure-dest.js'
5151
* @property {string[]|undefined} [target=[]] - Array of target strings to pass to esbuild
5252
* @property {boolean|undefined} [buildDrafts=false] - Build draft files with the published:false variable
5353
* @property {string[]|undefined} [copy=[]] - Array of paths to copy their contents into the dest directory
54+
* @property {import('@domstack/sync').Logger|undefined} [logger] - Logger used for build/watch output
5455
*/
5556

5657
/**

0 commit comments

Comments
 (0)