@bndynet/vue-site 0.1.1 → 0.1.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +49 -2
- package/bin/vue-site.mjs +52 -6
- package/dist/create-app.d.ts +1 -1
- package/dist/index.es.js +15 -5
- package/dist/types.d.ts +15 -2
- package/package.json +1 -2
package/README.md
CHANGED
|
@@ -67,6 +67,8 @@ Add `"dev": "vue-site dev"` (or `vs dev`) in `package.json` scripts if you like.
|
|
|
67
67
|
| `links` | Header links: Lucide `icon` + `link`, optional `title` |
|
|
68
68
|
| `packageRepository` | Usually set by CLI from `package.json`; omit when using `createSiteApp` alone |
|
|
69
69
|
| `env` | Dev/build options — see below |
|
|
70
|
+
| `bootstrap` | Optional path from site root (e.g. `./bootstrap.ts`) — module loaded once before the Vue app |
|
|
71
|
+
| `configureApp` | Optional `(app) => void \| Promise<void>` after router install, before `mount` (see [Local packages in `configureApp`](#local-packages-in-configureapp)) |
|
|
70
72
|
|
|
71
73
|
### `NavItem`
|
|
72
74
|
|
|
@@ -94,9 +96,36 @@ Add `"dev": "vue-site dev"` (or `vs dev`) in `package.json` scripts if you like.
|
|
|
94
96
|
| `port` | Dev server port |
|
|
95
97
|
| `outDir` | Build output (relative to site root; default `{folder}-dist`) |
|
|
96
98
|
| `customElements` | Tag prefixes for custom elements (e.g. `['chat-', 'i-']`) |
|
|
97
|
-
| `watchPackages` | Local packages
|
|
99
|
+
| `watchPackages` | Local packages — see [env.watchPackages](#envwatchpackages) |
|
|
98
100
|
| `vite` | Vite overrides (not `root`); framework merges aliases, `server.fs.allow`, `build.outDir`, etc. |
|
|
99
101
|
|
|
102
|
+
### `env.watchPackages`
|
|
103
|
+
|
|
104
|
+
- **String** — package name only (e.g. workspace symlink / `npm link`). Dependency pre-bundling is skipped; file watching follows Vite defaults.
|
|
105
|
+
- **`{ name, entryPath }`** — `name` must match the import specifier (e.g. `@scope/pkg`). `entryPath` is **relative to the directory where you run the CLI** (the folder that contains `site.config.*`). Vite resolves that package to your **source entry** for dev HMR and adds the package directory to `server.fs.allow`.
|
|
106
|
+
- If you use **`env.vite.resolve.alias` as an array** (`{ find, replacement }[]`), the CLI still merges `watchPackages` aliases correctly (object-only spread would break this).
|
|
107
|
+
- **Do not** add a **top-level value import** of the same package in `site.config.ts` if it is listed here — the config preload runs in Node and would resolve `node_modules`, while the app uses Vite. Use **`configureApp` + dynamic `import()`** instead (see next section).
|
|
108
|
+
|
|
109
|
+
### Local packages in `configureApp`
|
|
110
|
+
|
|
111
|
+
`configureApp` may be **`async`** so you can `await import('your-package')` after the router is installed. That dynamic import runs in the browser under Vite, so it respects `watchPackages` and does not run during CLI config loading.
|
|
112
|
+
|
|
113
|
+
```typescript
|
|
114
|
+
export default defineConfig({
|
|
115
|
+
env: {
|
|
116
|
+
watchPackages: [{ name: '@acme/widgets', entryPath: '../widgets/src/index.ts' }],
|
|
117
|
+
},
|
|
118
|
+
async configureApp(app) {
|
|
119
|
+
const w = await import('@acme/widgets')
|
|
120
|
+
w.register(app)
|
|
121
|
+
},
|
|
122
|
+
})
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
### Dev server filesystem access
|
|
126
|
+
|
|
127
|
+
The CLI allows `server.fs` reads under the site root, the installed `vue-site` package directory, the **parent** of the site root (for `../…` imports), and — when it would not widen to the filesystem root — the **grandparent** (common in monorepos, e.g. `../../packages/...`). Add more paths with `env.vite.server.fs.allow` if needed. Entries from `watchPackages` with `{ entryPath }` also extend `fs.allow` for those package trees.
|
|
128
|
+
|
|
100
129
|
## Library mode
|
|
101
130
|
|
|
102
131
|
Own `index.html` + Vite setup:
|
|
@@ -106,9 +135,12 @@ import { createSiteApp } from '@bndynet/vue-site'
|
|
|
106
135
|
import '@bndynet/vue-site/style.css'
|
|
107
136
|
import config from './site.config'
|
|
108
137
|
|
|
109
|
-
createSiteApp(config)
|
|
138
|
+
const app = await createSiteApp(config)
|
|
139
|
+
app.mount('#app')
|
|
110
140
|
```
|
|
111
141
|
|
|
142
|
+
Use a top-level `await` in your entry (or an async IIFE): `createSiteApp` is async and **awaits** `configureApp` when it returns a `Promise`. If you set optional `bootstrap` in config, that module loads before the app is created; if you omit `bootstrap`, that step is skipped.
|
|
143
|
+
|
|
112
144
|
Exports: `createSiteApp`, `defineConfig`, `useTheme`, `useSiteConfig`, `themeRefKey`. Types: `SiteConfig`, `SiteEnvConfig`, `SiteViteConfig`, `SiteExternalLink`, `NavItem`, `ThemeConfig`, `ThemeOption`, `ThemePaletteVars`, `ResolvedNavItem`.
|
|
113
145
|
|
|
114
146
|
### Theme in Vue pages (`useTheme`)
|
|
@@ -151,6 +183,21 @@ npm run dev # watch-build lib + example site
|
|
|
151
183
|
npm run build # `dist/` + `example/example-dist`
|
|
152
184
|
```
|
|
153
185
|
|
|
186
|
+
### Using a local build in another project
|
|
187
|
+
|
|
188
|
+
The published entry points at `dist/`. After changing library **source** under `src/`, run `npm run build:lib` (or `build:lib:watch`) before the consumer sees updates. Changes to **`bin/vue-site.mjs`** apply on the next `vue-site` run without a lib rebuild.
|
|
189
|
+
|
|
190
|
+
```bash
|
|
191
|
+
cd /path/to/vue-site
|
|
192
|
+
npm install && npm run build:lib
|
|
193
|
+
npm link
|
|
194
|
+
|
|
195
|
+
cd /path/to/consumer
|
|
196
|
+
npm link @bndynet/vue-site
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
You do not need to run `npm link` again after editing files; the symlink stays. Use `npm unlink @bndynet/vue-site` and `npm install` in the consumer when done.
|
|
200
|
+
|
|
154
201
|
## License
|
|
155
202
|
|
|
156
203
|
MIT
|
package/bin/vue-site.mjs
CHANGED
|
@@ -20,8 +20,29 @@ function resolvePkgDir(pkg) {
|
|
|
20
20
|
const vuePath = resolvePkgDir('vue')
|
|
21
21
|
const vueRouterPath = resolvePkgDir('vue-router')
|
|
22
22
|
const cwd = process.cwd()
|
|
23
|
+
/** Lets `import('../file.md?raw')` work when `site.config` lives in a subfolder (README next to cwd). In-repo, ../ often falls under pkgDir; from npm install it does not, so we allow cwd's parent explicitly. */
|
|
24
|
+
const cwdParent = resolve(cwd, '..')
|
|
25
|
+
/** Two levels up: monorepos (`apps/docs` importing `../../packages/...`). Omitted when that would be the FS root (too permissive for dev). */
|
|
26
|
+
const cwdGrandparent = resolve(cwd, '../..')
|
|
23
27
|
const command = process.argv[2] || 'dev'
|
|
24
28
|
|
|
29
|
+
function isLikelyFilesystemRoot(dir) {
|
|
30
|
+
if (dir === '/' || dir === '//') return true
|
|
31
|
+
if (process.platform === 'win32') {
|
|
32
|
+
return /^[a-zA-Z]:[\\/]$/i.test(dir)
|
|
33
|
+
}
|
|
34
|
+
return false
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const defaultServerFsAllow = [cwd, pkgDir, cwdParent]
|
|
38
|
+
if (
|
|
39
|
+
cwdGrandparent !== cwdParent &&
|
|
40
|
+
cwdGrandparent !== cwd &&
|
|
41
|
+
!isLikelyFilesystemRoot(cwdGrandparent)
|
|
42
|
+
) {
|
|
43
|
+
defaultServerFsAllow.push(cwdGrandparent)
|
|
44
|
+
}
|
|
45
|
+
|
|
25
46
|
const configCandidates = [
|
|
26
47
|
'site.config.ts',
|
|
27
48
|
'site.config.js',
|
|
@@ -104,7 +125,10 @@ const entryCode = [
|
|
|
104
125
|
`import '${pkgDir.replace(/\\/g, '/')}/dist/style.css'`,
|
|
105
126
|
`import siteConfig from '/${foundConfig}'`,
|
|
106
127
|
`import { repositoryUrl } from '${VIRTUAL_PACKAGE}'`,
|
|
107
|
-
|
|
128
|
+
`;(async () => {`,
|
|
129
|
+
` const app = await createSiteApp({ ...siteConfig, packageRepository: repositoryUrl })`,
|
|
130
|
+
` app.mount('#app')`,
|
|
131
|
+
`})()`,
|
|
108
132
|
].join('\n')
|
|
109
133
|
|
|
110
134
|
const htmlTemplate = `<!DOCTYPE html>
|
|
@@ -227,10 +251,16 @@ async function buildViteConfig() {
|
|
|
227
251
|
watchPatterns.push(`!**/node_modules/${pkg}/**`)
|
|
228
252
|
} else {
|
|
229
253
|
const entryAbs = resolve(cwd, pkg.entryPath)
|
|
230
|
-
const entryDir = entryAbs
|
|
254
|
+
const entryDir = dirname(entryAbs)
|
|
255
|
+
if (!fs.existsSync(entryAbs)) {
|
|
256
|
+
console.warn(
|
|
257
|
+
`[vue-site] env.watchPackages: entry not found (entryPath is relative to the directory where you run the CLI):\n ${entryAbs}\n package: ${pkg.name}`,
|
|
258
|
+
)
|
|
259
|
+
}
|
|
231
260
|
excludeNames.push(pkg.name)
|
|
232
261
|
localAliases[pkg.name] = entryAbs
|
|
233
|
-
|
|
262
|
+
const dirForGlob = entryDir.replace(/\\/g, '/')
|
|
263
|
+
watchPatterns.push(`!${dirForGlob}/**`)
|
|
234
264
|
fsAllowPaths.push(entryDir)
|
|
235
265
|
}
|
|
236
266
|
}
|
|
@@ -253,9 +283,22 @@ async function buildViteConfig() {
|
|
|
253
283
|
},
|
|
254
284
|
}
|
|
255
285
|
if (Object.keys(localAliases).length) {
|
|
286
|
+
const prevAlias = userViteRest.resolve?.alias
|
|
287
|
+
const extraPairs = Object.entries(localAliases).map(([find, replacement]) => ({
|
|
288
|
+
find,
|
|
289
|
+
replacement,
|
|
290
|
+
}))
|
|
291
|
+
let mergedAlias
|
|
292
|
+
if (prevAlias == null) {
|
|
293
|
+
mergedAlias = { ...localAliases }
|
|
294
|
+
} else if (Array.isArray(prevAlias)) {
|
|
295
|
+
mergedAlias = [...prevAlias, ...extraPairs]
|
|
296
|
+
} else {
|
|
297
|
+
mergedAlias = { ...prevAlias, ...localAliases }
|
|
298
|
+
}
|
|
256
299
|
userViteRest.resolve = {
|
|
257
300
|
...userViteRest.resolve,
|
|
258
|
-
alias:
|
|
301
|
+
alias: mergedAlias,
|
|
259
302
|
}
|
|
260
303
|
}
|
|
261
304
|
if (fsAllowPaths.length) {
|
|
@@ -285,7 +328,7 @@ async function buildViteConfig() {
|
|
|
285
328
|
open: true,
|
|
286
329
|
...(port != null && { port }),
|
|
287
330
|
fs: {
|
|
288
|
-
allow:
|
|
331
|
+
allow: defaultServerFsAllow,
|
|
289
332
|
},
|
|
290
333
|
},
|
|
291
334
|
build: {
|
|
@@ -324,7 +367,10 @@ import { createSiteApp } from '${pkgDir.replace(/\\/g, '/')}/dist/index.es.js'
|
|
|
324
367
|
import '${pkgDir.replace(/\\/g, '/')}/dist/style.css'
|
|
325
368
|
import siteConfig from './${foundConfig}'
|
|
326
369
|
import { repositoryUrl } from '${VIRTUAL_PACKAGE}'
|
|
327
|
-
|
|
370
|
+
;(async () => {
|
|
371
|
+
const app = await createSiteApp({ ...siteConfig, packageRepository: repositoryUrl })
|
|
372
|
+
app.mount('#app')
|
|
373
|
+
})()
|
|
328
374
|
</script>
|
|
329
375
|
</body>
|
|
330
376
|
</html>`
|
package/dist/create-app.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
import { SiteConfig } from './types';
|
|
2
|
-
export declare function createSiteApp(config: SiteConfig): import('vue').App<Element
|
|
2
|
+
export declare function createSiteApp(config: SiteConfig): Promise<import('vue').App<Element>>;
|
package/dist/index.es.js
CHANGED
|
@@ -38128,8 +38128,18 @@ const CS = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
|
|
|
38128
38128
|
};
|
|
38129
38129
|
}
|
|
38130
38130
|
});
|
|
38131
|
-
function
|
|
38131
|
+
function lA(e) {
|
|
38132
|
+
const a = e.trim();
|
|
38133
|
+
if (!a) throw new Error("[vue-site] bootstrap path is empty");
|
|
38134
|
+
return a.startsWith("/") ? a : "/" + a.replace(/^\.\//, "");
|
|
38135
|
+
}
|
|
38136
|
+
async function sA(e) {
|
|
38137
|
+
if (e.bootstrap == null || String(e.bootstrap).trim() === "") return;
|
|
38138
|
+
await import(lA(String(e.bootstrap)));
|
|
38139
|
+
}
|
|
38140
|
+
async function fA(e) {
|
|
38132
38141
|
var d, h, s, y;
|
|
38142
|
+
await sA(e);
|
|
38133
38143
|
const a = GI(e.nav), c = fS(a), o = ["light", "dark", ...((h = (d = e.theme) == null ? void 0 : d.extraThemes) == null ? void 0 : h.filter((f) => f.id !== "light" && f.id !== "dark").map((f) => f.id)) ?? []], i = bS(e.theme), u = me("light");
|
|
38134
38144
|
mS(
|
|
38135
38145
|
u,
|
|
@@ -38139,15 +38149,15 @@ function pA(e) {
|
|
|
38139
38149
|
(y = e.theme) == null ? void 0 : y.colors
|
|
38140
38150
|
), document.title = e.title;
|
|
38141
38151
|
const r = tL(hA);
|
|
38142
|
-
return r.provide(XI, u), r.provide(dI, { config: e, resolvedNav: a }), r.use(c), r;
|
|
38152
|
+
return r.provide(XI, u), r.provide(dI, { config: e, resolvedNav: a }), r.use(c), e.configureApp && await Promise.resolve(e.configureApp(r)), r;
|
|
38143
38153
|
}
|
|
38144
|
-
function
|
|
38154
|
+
function MA(e) {
|
|
38145
38155
|
return e;
|
|
38146
38156
|
}
|
|
38147
38157
|
export {
|
|
38148
38158
|
eI as builtinThemePalettes,
|
|
38149
|
-
|
|
38150
|
-
|
|
38159
|
+
fA as createSiteApp,
|
|
38160
|
+
MA as defineConfig,
|
|
38151
38161
|
XI as themeRefKey,
|
|
38152
38162
|
Rt as useSiteConfig,
|
|
38153
38163
|
xS as useTheme
|
package/dist/types.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Component } from 'vue';
|
|
1
|
+
import { App, Component } from 'vue';
|
|
2
2
|
import { UserConfig as ViteUserConfig } from 'vite';
|
|
3
3
|
export interface NavItem {
|
|
4
4
|
label: string;
|
|
@@ -65,7 +65,7 @@ export interface SiteEnvConfig {
|
|
|
65
65
|
/**
|
|
66
66
|
* Local packages to watch for source changes and exclude from pre-bundling.
|
|
67
67
|
* - `string` -- symlinked package name (npm workspaces / npm link)
|
|
68
|
-
* - `{ name, entryPath }` -- resolve imports to a source entry file so Vite compiles it directly (
|
|
68
|
+
* - `{ name, entryPath }` -- resolve imports to a source entry file so Vite compiles it directly; `entryPath` is relative to the directory where you run `vue-site` (the folder that contains `site.config.*`)
|
|
69
69
|
*/
|
|
70
70
|
watchPackages?: (string | {
|
|
71
71
|
name: string;
|
|
@@ -97,6 +97,19 @@ export interface SiteConfig {
|
|
|
97
97
|
packageRepository?: string | null;
|
|
98
98
|
/** Development / build environment configuration */
|
|
99
99
|
env?: SiteEnvConfig;
|
|
100
|
+
/**
|
|
101
|
+
* Optional. Path to a module under the site root (Vite `root`), loaded once **before** the Vue app
|
|
102
|
+
* is created. Omit or leave unset to skip. Use for global side effects (polyfills, telemetry,
|
|
103
|
+
* `window` setup). Relative to root, e.g. `./bootstrap.ts` or `src/bootstrap.ts` (resolved as
|
|
104
|
+
* `/bootstrap.ts`, `/src/bootstrap.ts`).
|
|
105
|
+
*/
|
|
106
|
+
bootstrap?: string;
|
|
107
|
+
/**
|
|
108
|
+
* Called after the app is created, context is provided, and the router is installed — before
|
|
109
|
+
* `createSiteApp` resolves (call `.mount()` after `await`). Use for `app.use()`, global directives, etc.
|
|
110
|
+
* May return a Promise (e.g. after `await import()` of a package listed in `env.watchPackages`).
|
|
111
|
+
*/
|
|
112
|
+
configureApp?: (app: App) => void | Promise<void>;
|
|
100
113
|
}
|
|
101
114
|
export interface ResolvedNavItem extends NavItem {
|
|
102
115
|
resolvedPath: string;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bndynet/vue-site",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.3",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "A configurable Vue 3 site framework with sidebar navigation, markdown rendering, and theme switching.",
|
|
6
6
|
"repository": {
|
|
@@ -50,7 +50,6 @@
|
|
|
50
50
|
},
|
|
51
51
|
"devDependencies": {
|
|
52
52
|
"@types/markdown-it": "^14.1.0",
|
|
53
|
-
"concurrently": "^9.2.1",
|
|
54
53
|
"rimraf": "^6.1.3",
|
|
55
54
|
"typescript": "~5.7.0",
|
|
56
55
|
"vite-plugin-dts": "^4.5.0",
|