dsebastien_obsidian-cli-rest/scripts/build.ts
2026-02-21 09:00:36 +01:00

170 lines
4.8 KiB
TypeScript

import { existsSync, mkdirSync, readdirSync, watch } from 'node:fs'
import { join } from 'node:path'
import { parseArgs } from 'node:util'
import { $ } from 'bun'
import { Glob } from 'bun'
// Read package.json to get plugin name
const packageJson = (await Bun.file('package.json').json()) as { name: string }
// Exported constants for testing
export const SRC = 'src'
export const DIST = 'dist'
export const ASSETS_SRC = `${SRC}/assets`
export const STYLES_SRC = `${SRC}/styles.src.css`
export const STYLES_OUT = `${DIST}/styles.css`
export const PLUGIN_ID = packageJson.name
export const BANNER = `/*
THIS IS A GENERATED/BUNDLED FILE BY BUN.
If you want to view the source, please visit the github repository of this plugin.
*/
`
export const EXTERNAL_MODULES = [
'obsidian',
'electron',
'@codemirror/autocomplete',
'@codemirror/collab',
'@codemirror/commands',
'@codemirror/language',
'@codemirror/lint',
'@codemirror/search',
'@codemirror/state',
'@codemirror/view',
'@lezer/common',
'@lezer/highlight',
'@lezer/lr'
]
const { values } = parseArgs({
args: Bun.argv,
options: {
prod: {
type: 'boolean',
default: false
}
},
strict: true,
allowPositionals: true
})
const isProd = values.prod
export function ensureDistDir(): void {
if (!existsSync(DIST)) {
mkdirSync(DIST, { recursive: true })
}
}
async function buildStyles(): Promise<void> {
console.log('Building Tailwind CSS...')
try {
const minifyFlag = isProd ? '--minify' : ''
await $`bunx @tailwindcss/cli -i ${STYLES_SRC} -o ${STYLES_OUT} ${minifyFlag}`.quiet()
console.log('CSS build succeeded.')
} catch (error) {
console.error('CSS build failed:', error)
if (isProd) {
throw error
}
}
}
async function buildJs(): Promise<void> {
console.log(`Building plugin in ${isProd ? 'production' : 'development'} mode...`)
const { success, logs } = await Bun.build({
banner: BANNER,
entrypoints: [`${SRC}/main.ts`],
outdir: DIST,
external: EXTERNAL_MODULES,
format: 'cjs',
target: 'node',
minify: isProd,
sourcemap: isProd ? false : 'inline',
throw: isProd
})
if (success) {
console.log('JS build succeeded.')
} else {
console.error('JS build failed.')
console.error(logs)
}
}
async function copyAssets(): Promise<void> {
console.log('Copying assets...')
const glob = new Glob('**/*')
for await (const file of glob.scan({ cwd: ASSETS_SRC, onlyFiles: true })) {
const src = join(ASSETS_SRC, file)
const dest = join(DIST, file)
await Bun.write(dest, Bun.file(src))
console.log(`${file}`)
}
// Also copy manifest.json and versions.json to dist
await Bun.write(join(DIST, 'manifest.json'), Bun.file('manifest.json'))
console.log(' ✓ manifest.json')
await Bun.write(join(DIST, 'versions.json'), Bun.file('versions.json'))
console.log(' ✓ versions.json')
}
async function copyDistToPluginDir(pluginDir: string): Promise<void> {
if (!existsSync(pluginDir)) {
console.log(`Creating plugin directory: ${pluginDir}`)
mkdirSync(pluginDir, { recursive: true })
}
console.log(`Copying dist to ${pluginDir}...`)
const distFiles = readdirSync(DIST)
for (const file of distFiles) {
const src = join(DIST, file)
const dest = join(pluginDir, file)
await Bun.write(dest, Bun.file(src))
console.log(`${file}`)
}
// Create .hotreload file for hot-reload plugin support
await Bun.write(join(pluginDir, '.hotreload'), '')
console.log(' ✓ .hotreload')
}
async function copyToTestVault(): Promise<void> {
const testVaultPluginDir = join('test-vault', '.obsidian', 'plugins', PLUGIN_ID)
await copyDistToPluginDir(testVaultPluginDir)
}
async function copyToVault(): Promise<void> {
const vaultPath = process.env['OBSIDIAN_VAULT_LOCATION']
if (!vaultPath) {
console.log(
'Tip: Set OBSIDIAN_VAULT_LOCATION to auto-copy the plugin to your vault after each build.'
)
return
}
const pluginDir = join(vaultPath, '.obsidian', 'plugins', PLUGIN_ID)
await copyDistToPluginDir(pluginDir)
}
async function build(): Promise<void> {
ensureDistDir()
await Promise.all([buildJs(), buildStyles(), copyAssets()])
if (!isProd) {
await copyToTestVault()
await copyToVault()
}
}
// Only run if executed directly
if (import.meta.main) {
await build()
if (!isProd) {
watch(`${SRC}`, { recursive: true }, async (event, path) => {
console.log(`Detected ${event} in ${SRC}/${path}`)
await build()
})
}
}