@bndynet/vue-site 0.1.2 → 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 CHANGED
@@ -68,7 +68,7 @@ Add `"dev": "vue-site dev"` (or `vs dev`) in `package.json` scripts if you like.
68
68
  | `packageRepository` | Usually set by CLI from `package.json`; omit when using `createSiteApp` alone |
69
69
  | `env` | Dev/build options — see below |
70
70
  | `bootstrap` | Optional path from site root (e.g. `./bootstrap.ts`) — module loaded once before the Vue app |
71
- | `configureApp` | Optional `(app) => void` after router install, before `mount` |
71
+ | `configureApp` | Optional `(app) => void \| Promise<void>` after router install, before `mount` (see [Local packages in `configureApp`](#local-packages-in-configureapp)) |
72
72
 
73
73
  ### `NavItem`
74
74
 
@@ -96,9 +96,36 @@ Add `"dev": "vue-site dev"` (or `vs dev`) in `package.json` scripts if you like.
96
96
  | `port` | Dev server port |
97
97
  | `outDir` | Build output (relative to site root; default `{folder}-dist`) |
98
98
  | `customElements` | Tag prefixes for custom elements (e.g. `['chat-', 'i-']`) |
99
- | `watchPackages` | Local packages: package name string, or `{ name, entryPath }` for source HMR |
99
+ | `watchPackages` | Local packages see [env.watchPackages](#envwatchpackages) |
100
100
  | `vite` | Vite overrides (not `root`); framework merges aliases, `server.fs.allow`, `build.outDir`, etc. |
101
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
+
102
129
  ## Library mode
103
130
 
104
131
  Own `index.html` + Vite setup:
@@ -112,7 +139,7 @@ const app = await createSiteApp(config)
112
139
  app.mount('#app')
113
140
  ```
114
141
 
115
- Use a top-level `await` in your entry (or an async IIFE): `createSiteApp` is async. If you set optional `bootstrap` in config, that module loads before the app is created; if you omit `bootstrap`, that step is skipped.
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.
116
143
 
117
144
  Exports: `createSiteApp`, `defineConfig`, `useTheme`, `useSiteConfig`, `themeRefKey`. Types: `SiteConfig`, `SiteEnvConfig`, `SiteViteConfig`, `SiteExternalLink`, `NavItem`, `ThemeConfig`, `ThemeOption`, `ThemePaletteVars`, `ResolvedNavItem`.
118
145
 
@@ -156,6 +183,21 @@ npm run dev # watch-build lib + example site
156
183
  npm run build # `dist/` + `example/example-dist`
157
184
  ```
158
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
+
159
201
  ## License
160
202
 
161
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',
@@ -230,10 +251,16 @@ async function buildViteConfig() {
230
251
  watchPatterns.push(`!**/node_modules/${pkg}/**`)
231
252
  } else {
232
253
  const entryAbs = resolve(cwd, pkg.entryPath)
233
- const entryDir = entryAbs.replace(/\/[^/]+$/, '')
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
+ }
234
260
  excludeNames.push(pkg.name)
235
261
  localAliases[pkg.name] = entryAbs
236
- watchPatterns.push(`!${entryDir}/**`)
262
+ const dirForGlob = entryDir.replace(/\\/g, '/')
263
+ watchPatterns.push(`!${dirForGlob}/**`)
237
264
  fsAllowPaths.push(entryDir)
238
265
  }
239
266
  }
@@ -256,9 +283,22 @@ async function buildViteConfig() {
256
283
  },
257
284
  }
258
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
+ }
259
299
  userViteRest.resolve = {
260
300
  ...userViteRest.resolve,
261
- alias: { ...userViteRest.resolve?.alias, ...localAliases },
301
+ alias: mergedAlias,
262
302
  }
263
303
  }
264
304
  if (fsAllowPaths.length) {
@@ -288,7 +328,7 @@ async function buildViteConfig() {
288
328
  open: true,
289
329
  ...(port != null && { port }),
290
330
  fs: {
291
- allow: [cwd, pkgDir],
331
+ allow: defaultServerFsAllow,
292
332
  },
293
333
  },
294
334
  build: {
package/dist/index.es.js CHANGED
@@ -38138,9 +38138,9 @@ async function sA(e) {
38138
38138
  await import(lA(String(e.bootstrap)));
38139
38139
  }
38140
38140
  async function fA(e) {
38141
- var d, h, s, y, f;
38141
+ var d, h, s, y;
38142
38142
  await sA(e);
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((k) => k.id !== "light" && k.id !== "dark").map((k) => k.id)) ?? []], i = bS(e.theme), u = me("light");
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");
38144
38144
  mS(
38145
38145
  u,
38146
38146
  ((s = e.theme) == null ? void 0 : s.default) ?? "light",
@@ -38149,7 +38149,7 @@ async function fA(e) {
38149
38149
  (y = e.theme) == null ? void 0 : y.colors
38150
38150
  ), document.title = e.title;
38151
38151
  const r = tL(hA);
38152
- return r.provide(XI, u), r.provide(dI, { config: e, resolvedNav: a }), r.use(c), (f = e.configureApp) == null || f.call(e, r), 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;
38153
38153
  }
38154
38154
  function MA(e) {
38155
38155
  return e;
package/dist/types.d.ts CHANGED
@@ -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 (e.g. `'../my-lib/src/index.ts'`)
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;
@@ -107,8 +107,9 @@ export interface SiteConfig {
107
107
  /**
108
108
  * Called after the app is created, context is provided, and the router is installed — before
109
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`).
110
111
  */
111
- configureApp?: (app: App) => void;
112
+ configureApp?: (app: App) => void | Promise<void>;
112
113
  }
113
114
  export interface ResolvedNavItem extends NavItem {
114
115
  resolvedPath: string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bndynet/vue-site",
3
- "version": "0.1.2",
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": {