bojuvue
BojuVue 보주뷰 
BojuVue is a Vue 3 component library including a download button that serves each visitor the right build for their OS. Works in any Vue 3 app; VitePress-aware variants at a second import path, zero VitePress overhead in the generic build.
See it live — every component rendered, not just described.
Install
npm install bojuvue
Usage
Import the stylesheet once, anywhere in your app's entry point — components render with no button skin, no dropdown panel background, and raw-size icons without it:
import 'bojuvue/style.css'
<script setup>
import { BVPlatformButton } from 'bojuvue'
</script>
<template>
<BVPlatformButton
manifest-url="/platformButton.json"
fallback-href="https://github.com/you/app/releases"
/>
</template>
Works as-is in any Vue 3 app. Building a VitePress site instead? Swap the import for
bojuvue/vitepress to get real VPButton theme styling, and register it once so every
.md page can use it with no per-page import:
// .vitepress/theme/index.ts
import DefaultTheme from 'vitepress/theme'
import { BVPlatformButton, BVMoreButton, BVButton, BVIconButton } from 'bojuvue/vitepress'
import 'bojuvue/style.css'
export default {
extends: DefaultTheme,
enhanceApp({ app }) {
app.component('BVPlatformButton', BVPlatformButton)
app.component('BVMoreButton', BVMoreButton)
app.component('BVButton', BVButton)
app.component('BVIconButton', BVIconButton)
},
}
The same stylesheet covers every component from both import paths — one import is enough regardless of which paths you use.
VitePress SSR builds
If your site does a production SSR build (VitePress's default vitepress build), add
this package's Vite plugin to your own .vitepress/config.mts so the build doesn't
break:
// .vitepress/config.mts
import { defineConfig } from 'vitepress'
import { bojuvue } from 'bojuvue/vite'
export default defineConfig({
vite: { plugins: [bojuvue()] },
})
Without it, importing anything from bojuvue/vitepress can break your SSR build,
because Vite externalizes node_modules dependencies by default during an SSR build —
which means this package's own internal vitepress/theme import gets resolved by
Node's raw module loader instead of Vite's, and that fails. The plugin tells Vite to
bundle this package through its own resolver instead, the same way your site's own
theme code already resolves an identical import successfully. See
#70 for the full failure mode.
No component API changes — this is the only thing that changes.
Then in any .md page, no import needed:
<BVPlatformButton manifest-url="platformButton.json" />
Your manifest (public/platformButton.json) — put one entry under platforms for each
platform you ship for:
{
"platforms": {
"windows": { "href": "https://example.com/app.msi" },
"macos": { "href": "https://example.com/app.dmg" },
"linux": { "href": "https://example.com/app.tar.gz" }
}
}
Documentation -- props reference, live demos, full setup guide, every component.
What's in the package
Published to npm as bojuvue. It exists so that VitePress sites can share one set of landing-page components instead of duplicating them per repo. This repo gets updated, the package gets published, and every consuming site picks it up with npm update.
- BVPlatformButton — reads the visitor's OS from the browser, fetches a manifest you host, and links to the right download. No manifest entry for a platform? The button hides itself, or shows a fallback link if you provide one. VitePress sites get real
VPButtonstyling frombojuvue/vitepress; plain Vue 3 apps use the same prop surface without any VitePress dependency. - BVMoreButton — an overflow dropdown for the secondary links every project needs (repo, report a bug, request a feature) without letting them outweigh your primary call-to-action. Visible-text mode ("More...") or a compact icon-only "⋯" button; VitePress sites get real
VPButtonstyling for free viabojuvue/vitepress, same asBVPlatformButton. - BVButton — VitePress's own
VPButtonprop shape, usable in any Vue 3 app. The primitive the others build on. - BVIconButton —
BVButtonwith an optional inline SVG icon in addition to, or in place of, the button text.
Every component exports from bojuvue. Components with VitePress-specific builds are located at bojuvue/vitepress — same exported name, resolves VitePress-specific values and renders through real VitePress components. vitepress is an optional peer dependency: installing the package alone never requires it.
Why not a monorepo workspace?
npm/yarn/pnpm workspaces already solve "share a component across projects" for free, and if every consuming site lived in this repo, that would be the right answer — skip this package entirely.
It only holds while that's true. The moment a consuming site is a separate repo — a different site, a client's project, a repo you don't control — a workspace can't reach across that boundary. There's no shared package.json to add an entry to, no symlinked node_modules to rely on. Publishing is what still works: a versioned package on the registry that any repo, anywhere, can npm install and npm update.
That's the actual reason this exists — not "components in a folder," but components that survive the boundary between repos.
Contributing
See CONTRIBUTING.md for development setup, the branch and commit conventions, and step-by-step instructions for adding a new component.
Contributions / Contact
- Please file an issue, or grab a fork, hack away, and submit a pull request.
- Contact me at linkedin.com/in/scottkirvan/
- You can also find me on Discord — I'm cptvideo.
Credits
BojuVue — Copyright (c) 2026 Scott Kirvan. MIT License.
Scaffolded from ScooterGitTemplate.
Related Packages
Version History
| Version | Released | Vue | License |
|---|---|---|---|
| 0.4.3 | ^3.5.41 | MIT | |
| 0.4.2 | ^3.5.41 | MIT | |
| 0.4.1 | ^3.5.41 | MIT | |
| 0.4.0 | ^3.5.41 | MIT | |
| 0.3.2 | ^3.5.41 | MIT | |
| 0.2.1 | ^3.5.41 | MIT |