Skip to content

Commit

Permalink
feat: supper base option in dev mode
Browse files Browse the repository at this point in the history
  • Loading branch information
kermanx committed Jan 29, 2025
1 parent e871f43 commit c836bc7
Show file tree
Hide file tree
Showing 4 changed files with 32 additions and 16 deletions.
1 change: 1 addition & 0 deletions docs/builtin/cli.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ Start a local server for Slidev.
Options:

- `--port`, `-p` (`number`, default: `3030`): port number.
- `--base` (`string`, default: `/`): base URL (see https://vitejs.dev/config/shared-options.html#base).
- `--open`, `-o` (`boolean`, default: `false`): open in the browser.
- `--remote [password]` (`string`): listen to the public host and enable remote control, if a value is passed then the presenter mode is private and only accessible by passing the given password in the URL query `password` parameter.
- `--bind` (`string`, default: `0.0.0.0`): specify which IP addresses the server should listen on in the remote mode.
Expand Down
38 changes: 24 additions & 14 deletions packages/slidev/node/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -99,18 +99,24 @@ cli.command(
alias: 'f',
default: false,
type: 'boolean',
describe: 'force the optimizer to ignore the cache and re-bundle ',
describe: 'force the optimizer to ignore the cache and re-bundle',
})
.option('bind', {
type: 'string',
default: '0.0.0.0',
describe: 'specify which IP addresses the server should listen on in remote mode',
})
.option('base', {
type: 'string',
describe: 'base URL. Example: /demo/',
default: '/',
})
.strict()
.help(),
async ({ entry, theme, port: userPort, open, log, remote, tunnel, force, inspect, bind }) => {
async ({ entry, theme, port: userPort, open, log, remote, tunnel, force, inspect, bind, base }) => {
let server: ViteDevServer | undefined
let port = 3030
base = `/${base.replaceAll('/', '')}/`

let lastRemoteUrl: string | undefined

Expand All @@ -126,7 +132,7 @@ cli.command(
async function initServer() {
if (server)
await server.close()
const options = await resolveOptions({ entry, remote, theme, inspect }, 'dev')
const options = await resolveOptions({ entry, remote, theme, inspect, base }, 'dev')
const host = remote !== undefined ? bind : 'localhost'
port = userPort || await getPort({
port: 3030,
Expand All @@ -150,6 +156,7 @@ cli.command(
force,
},
logLevel: log as LogLevel,
base,
},
{
async loadData(loadedSource) {
Expand Down Expand Up @@ -201,7 +208,7 @@ cli.command(
if (remote)
publicIp = await import('public-ip').then(r => r.publicIpv4())

lastRemoteUrl = printInfo(options, port, remote, tunnelUrl, publicIp)
lastRemoteUrl = printInfo(options, port, base, remote, tunnelUrl, publicIp)
}

async function openTunnel(port: number) {
Expand All @@ -225,7 +232,7 @@ cli.command(
name: 'o',
fullname: 'open',
action() {
openBrowser(`http://localhost:${port}`)
openBrowser(`http://localhost:${port}${base}`)
},
},
{
Expand Down Expand Up @@ -334,7 +341,7 @@ cli.command(
})
.option('base', {
type: 'string',
describe: 'output base',
describe: 'output base. Example: /demo/',
})
.option('download', {
alias: 'd',
Expand All @@ -353,7 +360,7 @@ cli.command(
const { build } = await import('./commands/build')

for (const entryFile of entry as unknown as string[]) {
const options = await resolveOptions({ entry: entryFile, theme, inspect, download }, 'build')
const options = await resolveOptions({ entry: entryFile, theme, inspect, download, base }, 'build')

printInfo(options)
await build(
Expand Down Expand Up @@ -621,10 +628,13 @@ function exportOptions<T>(args: Argv<T>) {
function printInfo(
options: ResolvedSlidevOptions,
port?: number,
base?: string,
remote?: string,
tunnelUrl?: string,
publicIp?: string,
) {
const baseUrl = port && `http://localhost:${bold(port + (base?.slice(0, -1) || ''))}`

console.log()
console.log()
console.log(` ${cyan('●') + blue('■') + yellow('▲')}`)
Expand All @@ -637,22 +647,22 @@ function printInfo(
console.log(dim(' css engine ') + blue('unocss'))
console.log(dim(' entry ') + dim(path.normalize(path.dirname(options.entry)) + path.sep) + path.basename(options.entry))

if (port) {
if (baseUrl) {
const query = remote ? `?password=${remote}` : ''
const presenterPath = `${options.data.config.routerMode === 'hash' ? '/#/' : '/'}presenter/${query}`
const entryPath = `${options.data.config.routerMode === 'hash' ? '/#/' : '/'}entry${query}/`
const overviewPath = `${options.data.config.routerMode === 'hash' ? '/#/' : '/'}overview${query}/`
console.log()
console.log(`${dim(' public slide show ')} > ${cyan(`http://localhost:${bold(port)}/`)}`)
console.log(`${dim(' public slide show ')} > ${cyan(`${baseUrl}/`)}`)
if (query)
console.log(`${dim(' private slide show ')} > ${cyan(`http://localhost:${bold(port)}/${query}`)}`)
console.log(`${dim(' private slide show ')} > ${cyan(`${baseUrl}/${query}`)}`)
if (options.utils.define.__SLIDEV_FEATURE_PRESENTER__)
console.log(`${dim(' presenter mode ')} > ${blue(`http://localhost:${bold(port)}${presenterPath}`)}`)
console.log(`${dim(' slides overview ')} > ${blue(`http://localhost:${bold(port)}${overviewPath}`)}`)
console.log(`${dim(' presenter mode ')} > ${blue(`${baseUrl}${presenterPath}`)}`)
console.log(`${dim(' slides overview ')} > ${blue(`${baseUrl}${overviewPath}`)}`)
if (options.utils.define.__SLIDEV_FEATURE_BROWSER_EXPORTER__)
console.log(`${dim(' export slides')} > ${blue(`http://localhost:${bold(port)}/export/`)}`)
console.log(`${dim(' export slides')} > ${blue(`${baseUrl}/export/`)}`)
if (options.inspect)
console.log(`${dim(' vite inspector')} > ${yellow(`http://localhost:${bold(port)}/__inspect/`)}`)
console.log(`${dim(' vite inspector')} > ${yellow(`${baseUrl}/__inspect/`)}`)

let lastRemoteUrl = ''

Expand Down
4 changes: 2 additions & 2 deletions packages/slidev/node/setups/indexHtml.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ function toAttrValue(unsafe: unknown) {
return JSON.stringify(escapeHtml(String(unsafe)))
}

export default function setupIndexHtml({ mode, entry, clientRoot, userRoot, roots, data }: Omit<ResolvedSlidevOptions, 'utils'>): string {
export default function setupIndexHtml({ mode, entry, clientRoot, userRoot, roots, data, base }: Omit<ResolvedSlidevOptions, 'utils'>): string {
let main = readFileSync(join(clientRoot, 'index.html'), 'utf-8')
let head = ''
let body = ''
Expand Down Expand Up @@ -56,7 +56,7 @@ export default function setupIndexHtml({ mode, entry, clientRoot, userRoot, root
main = main.replace('<html lang="en">', `<html lang="${data.headmatter.lang}">`)

main = main
.replace('__ENTRY__', toAtFS(join(clientRoot, 'main.ts')))
.replace('__ENTRY__', (base?.slice(0, -1) ?? '') + toAtFS(join(clientRoot, 'main.ts')))
.replace('<!-- head -->', head)
.replace('<!-- body -->', body)

Expand Down
5 changes: 5 additions & 0 deletions packages/types/src/options.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,11 @@ export interface SlidevEntryOptions {
* Build with --download option
*/
download?: boolean

/**
* Base URL in dev or build mode
*/
base?: string
}

export interface ResolvedSlidevOptions extends RootsInfo, SlidevEntryOptions {
Expand Down

0 comments on commit c836bc7

Please sign in to comment.