Skip to content

Commit

Permalink
feat: pretty cli logging
Browse files Browse the repository at this point in the history
  • Loading branch information
jxom committed Nov 19, 2023
1 parent bbcc55b commit d449506
Show file tree
Hide file tree
Showing 10 changed files with 156 additions and 42 deletions.
Binary file added bun.lockb
Binary file not shown.
2 changes: 0 additions & 2 deletions create-vocs/init.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
import { dirname, resolve } from 'node:path'
import { fileURLToPath } from 'node:url'
import { intro, log, outro, text } from '@clack/prompts'
// @ts-expect-error
import { detect } from 'detect-package-manager'
import { default as fs } from 'fs-extra'
import pc from 'picocolors'

Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
"bun-types": "^1.0.6",
"fs-extra": "^11.1.1",
"globby": "^13.2.2",
"ora": "^7.0.1",
"rimraf": "^5.0.5",
"simple-git-hooks": "^2.9.0",
"typescript": "^5.2.2"
Expand Down
10 changes: 7 additions & 3 deletions src/app/components/Outline.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -106,14 +106,16 @@ export function Outline({
const observer = new IntersectionObserver(([entry]) => {
if (!active.current) return

if (entry.isIntersecting) setActiveId(items[items.length - 1].id)
else setActiveId(items[items.length - 2].id)
const lastItemId = items[items.length - 1].id

if (entry.isIntersecting) setActiveId(lastItemId)
else if (activeId === lastItemId) setActiveId(items[items.length - 2].id)
})

observer.observe(document.querySelector('[data-bottom-observer]')!)

return () => observer.disconnect()
}, [items])
}, [activeId, items])

// Intersection observers are a bit unreliable for fast scrolling,
// use scroll event listener to sync active item.
Expand Down Expand Up @@ -151,6 +153,8 @@ export function Outline({

if (items.length === 0) return null

console.log(activeId)

const levelItems = items.filter((item) => item.level === minLevel)
return (
<aside className={styles.root}>
Expand Down
53 changes: 51 additions & 2 deletions src/cli/commands/build.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,53 @@
export async function build() {
import ora from 'ora'
import pc from 'picocolors'
import { createLogger } from 'vite'
import type { BuildParameters as BuildParameters_ } from '../../vite/build.js'
import { version } from '../version.js'

export type BuildParameters = Pick<BuildParameters_, 'logLevel' | 'outDir'>

export async function build({ logLevel, outDir }: BuildParameters) {
const { build } = await import('../../vite/build.js')
await build()

const useLogger = logLevel !== 'info'

const start = Date.now()

const logger = createLogger('info', { allowClearScreen: true })

const spinner = {
client: ora('building bundles...\n'),
prerender: ora('prerendering pages...\n'),
}

logger.clearScreen('info')
logger.info('')
logger.info(` ${pc.blue('[building]')} ${pc.bold('vocs')}@${pc.dim(`v${version}`)}\n`)
await build({
hooks: {
onClientBuildStart: () => {
if (useLogger) spinner.client.start()
},
onClientBuildEnd: () => {
if (useLogger) spinner.client.succeed('bundles built')
else logger.info('')
},
onPrerenderBuildStart: () => {
if (useLogger) spinner.prerender.start()
},
onPrerenderBuildEnd: () => {
if (useLogger) spinner.prerender.succeed('prerendered pages')
},
onScriptsBuildEnd: () => {
if (!useLogger) logger.info('')
},
},
logger,
logLevel,
outDir,
})

const end = Date.now()
const time = end - start
logger.info(`\n ${pc.green('[built]')} in ${time / 1000}s`)
}
15 changes: 13 additions & 2 deletions src/cli/commands/dev.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,19 @@
import pc from 'picocolors'
import { createLogger } from 'vite'
import { version } from '../version.js'

type DevParameters = { host?: boolean }

export async function dev(params: DevParameters = {}) {
export async function dev(_: any, { host }: DevParameters = {}) {
const { createDevServer } = await import('../../vite/dev-server.js')
const server = await createDevServer({ host: params.host })

const server = await createDevServer({ host })
await server.listen()

const logger = createLogger()
logger.clearScreen('info')
logger.info('')
logger.info(` ${pc.green('[running]')} ${pc.bold('vocs')}@${pc.dim(`v${version}`)}`)
logger.info('')
server.printUrls()
}
10 changes: 10 additions & 0 deletions src/cli/commands/preview.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,15 @@
import pc from 'picocolors'
import { createLogger } from 'vite'
import { version } from '../version.js'

export async function preview() {
const { preview } = await import('../../vite/preview.js')
const server = await preview()

const logger = createLogger()
logger.clearScreen('info')
logger.info('')
logger.info(` ${pc.green('[running]')} ${pc.bold('vocs')}@${pc.dim(`v${version}`)}`)
logger.info('')
server.printUrls()
}
6 changes: 5 additions & 1 deletion src/cli/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,11 @@ export const cli = cac('vocs')

cli.command('[root]').alias('dev').option('-h, --host', 'Expose host URL').action(dev)
cli.command('init').option('-n, --name [name]', 'Name of project').action(init)
cli.command('build').action(build)
cli
.command('build')
.option('-l, --logLevel [level]', 'info | warn | error | silent')
.option('-o, --outDir [dir]', 'output directory (default: dist)')
.action(build)
cli.command('preview').action(preview)

cli.help()
Expand Down
87 changes: 60 additions & 27 deletions src/vite/build.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,46 +7,79 @@ import { prerender } from './plugins/prerender.js'

const __dirname = dirname(fileURLToPath(import.meta.url))

type BuildParameters = {
export type BuildParameters = {
logger?: vite.Logger
hooks?: {
onClientBuildStart?: () => void
onClientBuildEnd?: (
output: vite.Rollup.RollupOutput | vite.Rollup.RollupOutput[] | vite.Rollup.RollupWatcher,
) => void
onPrerenderBuildStart?: () => void
onPrerenderBuildEnd?: (
output: vite.Rollup.RollupOutput | vite.Rollup.RollupOutput[] | vite.Rollup.RollupWatcher,
) => void
onScriptsBuildStart?: () => void
onScriptsBuildEnd?: () => void
}
logLevel?: vite.LogLevel
outDir?: string
}

export async function build({ outDir = 'dist' }: BuildParameters = {}) {
export async function build({
logger,
hooks,
logLevel = 'silent',
outDir = 'dist',
}: BuildParameters = {}) {
// client
await vite.build({
build: {
emptyOutDir: true,
outDir: resolve(outDir),
},
root: __dirname,
})
await Promise.all([
(async () => {
hooks?.onClientBuildStart?.()
const output = await vite.build({
build: {
emptyOutDir: true,
outDir: resolve(outDir),
},
root: __dirname,
logLevel,
})
hooks?.onClientBuildEnd?.(output)
return output
})(),
(async () => {
hooks?.onScriptsBuildStart?.()
await vite.build({
build: {
lib: {
formats: ['iife'],
name: 'theme',
entry: [resolve(__dirname, '../app/utils/initializeTheme.ts')],
},
minify: true,
outDir: resolve(outDir),
emptyOutDir: false,
},
configFile: undefined,
logLevel,
})
hooks?.onScriptsBuildEnd?.()
})(),
])

// server
await vite.build({
// prerender
hooks?.onPrerenderBuildStart?.()
const output_prerender = await vite.build({
build: {
emptyOutDir: false,
outDir: resolve(outDir),
ssr: resolve(__dirname, '../app/index.server.tsx'),
},
plugins: [prerender({ outDir })],
logLevel,
plugins: [prerender({ logger: logLevel === 'info' ? logger : undefined, outDir })],
root: __dirname,
})
hooks?.onPrerenderBuildEnd?.(output_prerender)

// copy public folder
fs.copySync(resolve(__dirname, '../app/public'), resolve(outDir))

// initialize theme script
await vite.build({
build: {
lib: {
formats: ['iife'],
name: 'theme',
entry: [resolve(__dirname, '../app/utils/initializeTheme.ts')],
},
minify: true,
outDir: resolve(outDir),
emptyOutDir: false,
},
configFile: undefined,
})
}
14 changes: 9 additions & 5 deletions src/vite/plugins/prerender.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
import { mkdirSync, readFileSync, readdirSync, writeFileSync } from 'node:fs'
import { dirname, resolve } from 'node:path'
import type { PluginOption } from 'vite'
import { dirname, relative, resolve } from 'node:path'
import pc from 'picocolors'
import { type Logger, type PluginOption } from 'vite'

const root = process.cwd()

type PrerenderPluginParameters = { outDir?: string }
type PrerenderPluginParameters = { logger?: Logger; outDir?: string }

export function prerender({ outDir = 'dist' }: PrerenderPluginParameters): PluginOption {
export function prerender({ logger, outDir = 'dist' }: PrerenderPluginParameters): PluginOption {
return {
name: 'prerender',
async closeBundle() {
Expand All @@ -18,6 +19,7 @@ export function prerender({ outDir = 'dist' }: PrerenderPluginParameters): Plugi
// Get routes to prerender.
const routes = getRoutes(resolve(root, 'docs'))

logger?.info(`\n${pc.green('✓')} ${routes.length} pages prerendered.`)
// Prerender each route.
for (const route of routes) {
const { head, body } = await mod.prerender(route)
Expand All @@ -31,7 +33,9 @@ export function prerender({ outDir = 'dist' }: PrerenderPluginParameters): Plugi

if (!isDir(pathDir)) mkdirSync(pathDir, { recursive: true })
writeFileSync(path, html)
console.log('Prerendered:', path)

const fileName = path.split('/').pop()!
logger?.info(`${pc.dim(relative(root, path).replace(fileName, ''))}${pc.cyan(fileName)}`)
}
},
}
Expand Down

0 comments on commit d449506

Please sign in to comment.