kirbyup 4.0.0-alpha.5 → 4.0.0-alpha.7

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
@@ -2,25 +2,31 @@
2
2
 
3
3
  # kirbyup
4
4
 
5
- [![npm version](https://img.shields.io/npm/v/kirbyup?color=a1b858&label=)](https://www.npmjs.com/package/kirbyup)
6
-
7
- The official bundler for Kirby Panel plugins with zero-config usage and built-in HMR.
5
+ The official bundler for Kirby Panel plugins. Zero-config, built-in HMR.
8
6
 
9
7
  - [✨  Release Notes](https://github.com/johannschopplich/kirbyup/releases)
10
8
  - [📖  Read the documentation](https://kirbyup.getkirby.com)
11
9
 
12
10
  ## Key Features
13
11
 
14
- - 🔄 [Hot module replacement](https://kirbyup.getkirby.com/guide/getting-started.html#development)
15
- - 🎒 PostCSS support
16
- - 🧭 Add custom path aliases
17
- - 🔌 Run actions based on environment variables
18
- - 🦔 [Extends Vite with `kirbyup.config.js`](https://kirbyup.getkirby.com/guide/config-file)
12
+ - 🔄 [Hot Module Replacement](https://kirbyup.getkirby.com/guide/getting-started.html#development)
13
+ - 🎒 [PostCSS & Sass](https://kirbyup.getkirby.com/guide/postcss)
14
+ - 🧩 [kirbyuse Integration](https://kirbyup.getkirby.com/guide/kirbyuse)
15
+ - 🔌 [Environment Variables](https://kirbyup.getkirby.com/guide/environment-variables)
16
+ - 🦔 [Configuration File](https://kirbyup.getkirby.com/guide/config-file)
17
+ - 🧭 [Path Aliases](https://kirbyup.getkirby.com/guide/path-aliases)
18
+
19
+ ## Requirements
20
+
21
+ - **Node.js 24+**: paired with a package manager (pnpm, npm, or yarn).
22
+ - **Kirby 6 or newer**: kirbyup 4.x targets the Vue 3-based Panel runtime introduced in Kirby 6. For Kirby 4 or 5 plugins, use kirbyup 3.x.
19
23
 
20
24
  ## Setup
21
25
 
22
26
  > [!TIP]
23
- > [📖 Read the documentation](https://kirbyup.getkirby.com)
27
+ > Skip starting from scratch and pick one of the following starters:
28
+ > - [`eslint`](./examples/eslint)
29
+ > - [`unocss`](./examples/unocss)
24
30
 
25
31
  ```bash
26
32
  # pnpm
@@ -28,16 +34,12 @@ pnpm add -D kirbyup
28
34
 
29
35
  # npm
30
36
  npm i -D kirbyup
31
- ```
32
37
 
33
- ## Basic Usage
34
-
35
- > [!TIP]
36
- > [📖 Read the documentation](https://kirbyup.getkirby.com) or skip starting from scratch and pick one of the following starters:
37
- > - [`eslint`](./examples/eslint)
38
- > - [`tailwindcss`](./examples/tailwindcss)
38
+ # yarn
39
+ yarn add -D kirbyup
40
+ ```
39
41
 
40
- Having installed kirbyup, you can add the following scripts as shortcuts to the commands you will use most often:
42
+ After installation, add these scripts to your `package.json`:
41
43
 
42
44
  ```json
43
45
  {
@@ -46,18 +48,18 @@ Having installed kirbyup, you can add the following scripts as shortcuts to the
46
48
  "build": "kirbyup src/index.js"
47
49
  },
48
50
  "devDependencies": {
49
- "kirbyup": "^3.4.0"
51
+ "kirbyup": "^4.0.0-alpha.6"
50
52
  }
51
53
  }
52
54
  ```
53
55
 
54
- ## 💻 Development
56
+ ## Development
55
57
 
56
58
  1. Clone this repository
57
59
  2. Enable [Corepack](https://github.com/nodejs/corepack) using `corepack enable`
58
60
  3. Install dependencies using `pnpm install`
59
- 4. Run `pnpm run dev:prepare`
60
- 5. Start development server using `pnpm run dev`
61
+ 4. Build with `pnpm run build`
62
+ 5. Run tests with `pnpm test`
61
63
 
62
64
  ## License
63
65
 
@@ -1,4 +1,4 @@
1
- import { r as UserConfig } from "../types-CFhX3iS8.mjs";
1
+ import { r as UserConfig } from "../types-3hN383nZ.mjs";
2
2
 
3
3
  //#region src/client/config.d.ts
4
4
  declare function defineConfig(config: UserConfig): UserConfig;
@@ -2,6 +2,5 @@
2
2
  function defineConfig(config) {
3
3
  return config;
4
4
  }
5
-
6
5
  //#endregion
7
- export { defineConfig };
6
+ export { defineConfig };
@@ -1,7 +1,15 @@
1
1
  //#region src/client/plugin.ts
2
- const kirbyup = Object.freeze({ import(glob) {
3
- const modules = glob;
4
- return Object.entries(modules).reduce((accumulator, [path, component]) => {
2
+ const kirbyup = Object.freeze({
3
+ /**
4
+ * Auto-import Kirby Panel components, transformed by
5
+ * kirbyup's glob-import plugin for Vite.
6
+ *
7
+ * @example
8
+ * kirbyup.import('./components/blocks/*.vue')
9
+ */
10
+ import(glob) {
11
+ if (typeof glob === "string") throw new TypeError("[kirbyup] kirbyup.import() requires the kirbyup build pipeline. The call must be transformed at build time by the kirbyup:glob-import plugin.");
12
+ return Object.entries(glob).reduce((accumulator, [path, component]) => {
5
13
  accumulator[getComponentName(path)] = component.default;
6
14
  return accumulator;
7
15
  }, {});
@@ -9,6 +17,5 @@ const kirbyup = Object.freeze({ import(glob) {
9
17
  function getComponentName(path) {
10
18
  return path.substring(path.lastIndexOf("/") + 1, path.lastIndexOf(".")).toLowerCase();
11
19
  }
12
-
13
20
  //#endregion
14
- export { kirbyup };
21
+ export { kirbyup };
package/dist/node/cli.mjs CHANGED
@@ -1,6 +1,5 @@
1
- import { a as version, i as name, n as serve, r as handleError, t as build } from "../node-B8aLFfzt.mjs";
1
+ import { a as version, i as name, n as serve, r as handleError, t as build } from "../node-BAAmufwc.mjs";
2
2
  import { cac } from "cac";
3
-
4
3
  //#region src/node/cli-start.ts
5
4
  async function startCli(cwd = process.cwd(), argv = process.argv) {
6
5
  const cli = cac(name);
@@ -36,10 +35,8 @@ async function startCli(cwd = process.cwd(), argv = process.argv) {
36
35
  cli.parse(argv, { run: false });
37
36
  await cli.runMatchedCommand();
38
37
  }
39
-
40
38
  //#endregion
41
39
  //#region src/node/cli.ts
42
40
  startCli().catch(handleError);
43
-
44
41
  //#endregion
45
- export { };
42
+ export {};
@@ -1,4 +1,4 @@
1
- import { n as ServeOptions, t as BuildOptions } from "../types-CFhX3iS8.mjs";
1
+ import { n as ServeOptions, t as BuildOptions } from "../types-3hN383nZ.mjs";
2
2
  import { ViteDevServer } from "vite";
3
3
 
4
4
  //#region src/node/index.d.ts
@@ -1,3 +1,2 @@
1
- import { n as serve, t as build } from "../node-B8aLFfzt.mjs";
2
-
3
- export { build, serve };
1
+ import { n as serve, t as build } from "../node-BAAmufwc.mjs";
2
+ export { build, serve };
@@ -0,0 +1,480 @@
1
+ import * as fs from "node:fs";
2
+ import * as fsp from "node:fs/promises";
3
+ import vuePlugin from "@vitejs/plugin-vue";
4
+ import vueJsxPlugin from "@vitejs/plugin-vue-jsx";
5
+ import { consola } from "consola";
6
+ import { colors } from "consola/utils";
7
+ import { basename, dirname, normalize, relative, resolve } from "pathe";
8
+ import { debounce } from "perfect-debounce";
9
+ import { build, createFilter, createLogger, createServer, mergeConfig, normalizePath } from "vite";
10
+ import * as vueCompilerSfc from "vue/compiler-sfc";
11
+ import { loadConfig } from "c12";
12
+ import postcssrcLoad from "postcss-load-config";
13
+ import { gzipSync } from "node:zlib";
14
+ import MagicString from "magic-string";
15
+ import { stripLiteral } from "strip-literal";
16
+ import { isIP } from "node:net";
17
+ //#region package.json
18
+ var name = "kirbyup";
19
+ var version = "4.0.0-alpha.7";
20
+ //#endregion
21
+ //#region src/node/config.ts
22
+ function loadConfig$1(cwd = process.cwd()) {
23
+ return loadConfig({
24
+ cwd,
25
+ name: "kirbyup",
26
+ rcFile: false,
27
+ packageJson: false
28
+ });
29
+ }
30
+ async function resolvePostCSSConfig(cwd) {
31
+ try {
32
+ return await postcssrcLoad(void 0, void 0, { stopDir: cwd });
33
+ } catch (error) {
34
+ if (!error.message.includes("No PostCSS Config found")) throw error;
35
+ }
36
+ }
37
+ //#endregion
38
+ //#region src/node/errors.ts
39
+ var PrettyError = class extends Error {
40
+ constructor(message) {
41
+ super(message);
42
+ this.name = this.constructor.name;
43
+ Error.captureStackTrace(this, this.constructor);
44
+ }
45
+ };
46
+ function handleError(error) {
47
+ consola.error(error.message);
48
+ process.exitCode = 1;
49
+ }
50
+ //#endregion
51
+ //#region src/node/plugins/build-cleanup.ts
52
+ function kirbyupBuildCleanupPlugin(options) {
53
+ let config;
54
+ let devIndexPath;
55
+ return {
56
+ name: "kirbyup:build-cleanup",
57
+ configResolved(resolvedConfig) {
58
+ config = resolvedConfig;
59
+ devIndexPath = resolve(config.root, options.outDir, "index.dev.js");
60
+ },
61
+ writeBundle() {
62
+ if (options.watch) return;
63
+ if (fs.existsSync(devIndexPath)) fs.unlinkSync(devIndexPath);
64
+ }
65
+ };
66
+ }
67
+ //#endregion
68
+ //#region src/node/utils.ts
69
+ function toArray(array) {
70
+ array ??= [];
71
+ return Array.isArray(array) ? array : [array];
72
+ }
73
+ async function printFileInfo({ root, outDir, filePath, content, type, maxLength }) {
74
+ const prettyOutDir = `${normalize(relative(root, outDir))}/`;
75
+ const kibs = content.length / 1024;
76
+ const compressedKibs = gzipSync(content).length / 1024;
77
+ const writeColor = type === "chunk" ? colors.cyan : colors.magenta;
78
+ consola.log(colors.white(colors.dim(prettyOutDir)) + writeColor(filePath.padEnd(maxLength + 2)) + colors.dim(`${kibs.toFixed(2)} kB / gzip: ${compressedKibs.toFixed(2)} KiB`));
79
+ }
80
+ //#endregion
81
+ //#region src/node/plugins/full-reload.ts
82
+ /**
83
+ * Triggers a full browser reload when files matching the given globs change.
84
+ * Vite forces chokidar's `disableGlobbing: true` by default; this plugin
85
+ * resets it so glob strings passed to `watcher.add` are expanded by chokidar.
86
+ */
87
+ function kirbyupFullReloadPlugin(paths) {
88
+ return {
89
+ name: "kirbyup:full-reload",
90
+ apply: "serve",
91
+ config() {
92
+ return { server: { watch: { disableGlobbing: false } } };
93
+ },
94
+ configureServer({ watcher, ws, config: { root, logger } }) {
95
+ const files = toArray(paths).map((p) => resolve(root, p));
96
+ const matches = createFilter(files);
97
+ watcher.add(files);
98
+ const reload = (path) => {
99
+ if (!matches(path)) return;
100
+ setTimeout(() => ws.send({
101
+ type: "full-reload",
102
+ path: "*"
103
+ }), 0);
104
+ logger.info(`${colors.green("full reload")} ${colors.dim(relative(root, path))}`, {
105
+ clear: true,
106
+ timestamp: true
107
+ });
108
+ };
109
+ watcher.on("add", reload);
110
+ watcher.on("change", reload);
111
+ }
112
+ };
113
+ }
114
+ //#endregion
115
+ //#region src/node/plugins/glob-import.ts
116
+ /**
117
+ * Transforms `kirbyup.import(<path>)` to `kirbyup.import(import.meta.glob(<path>, { eager: true }))`.
118
+ *
119
+ * Must run before Vite's own `import.meta.glob` plugin (also `enforce: 'pre'`),
120
+ * otherwise the emitted call is never expanded.
121
+ */
122
+ function kirbyupGlobImportPlugin() {
123
+ let config;
124
+ return {
125
+ name: "kirbyup:glob-import",
126
+ enforce: "pre",
127
+ configResolved(resolvedConfig) {
128
+ config = resolvedConfig;
129
+ },
130
+ transform(code) {
131
+ if (!code.includes("kirbyup.import")) return;
132
+ const kirbyupImportRE = /\bkirbyup\.import\s*\(\s*('[^']+'|"[^"]+"|`[^`]+`)\s*\)/dg;
133
+ const cleanCode = stripLiteral(code);
134
+ let s;
135
+ for (const match of cleanCode.matchAll(kirbyupImportRE)) {
136
+ const { 0: exp, index } = match;
137
+ const [argStart, argEnd] = match.indices[1];
138
+ const rawPath = code.slice(argStart, argEnd);
139
+ if (!s) s = new MagicString(code);
140
+ s.overwrite(index, index + exp.length, `kirbyup.import(import.meta.glob(${rawPath}, { eager: true }))`);
141
+ }
142
+ if (s) return {
143
+ code: s.toString(),
144
+ map: config.build.sourcemap ? s.generateMap({ hires: true }) : void 0
145
+ };
146
+ }
147
+ };
148
+ }
149
+ //#endregion
150
+ //#region src/node/utils/server.ts
151
+ function resolveOriginFromServerOptions(serverOptions, port, fallbackHostname) {
152
+ const protocol = serverOptions?.https && (typeof serverOptions.https === "boolean" || Object.keys(serverOptions.https).length > 0) ? "https" : "http";
153
+ const configuredHost = normalizeHost(serverOptions?.host);
154
+ return `${protocol}://${formatHostname(configuredHost || fallbackHostname || "localhost")}${(configuredHost ? hostIncludesPort(configuredHost) : false) || protocol === "http" && port === 80 || protocol === "https" && port === 443 ? "" : `:${port}`}`;
155
+ }
156
+ function normalizeHost(host) {
157
+ if (host === false || host === void 0) return;
158
+ if (host === true) return "0.0.0.0";
159
+ return host;
160
+ }
161
+ function formatHostname(host) {
162
+ if (!host) return "localhost";
163
+ if (host.startsWith("[") && host.endsWith("]")) return host;
164
+ return isIP(host) === 6 ? `[${host}]` : host;
165
+ }
166
+ function hostIncludesPort(host) {
167
+ if (host.startsWith("[")) {
168
+ const closingIndex = host.indexOf("]");
169
+ return closingIndex > -1 && host.slice(closingIndex + 1).startsWith(":");
170
+ }
171
+ if (isIP(host) === 6) return false;
172
+ return host.includes(":");
173
+ }
174
+ //#endregion
175
+ //#region src/node/plugins/runtime/hmr-shim.js?raw
176
+ var hmr_shim_default = "/* eslint-disable no-undef */\nimport 'vue'\n\nif (typeof __VUE_HMR_RUNTIME__ !== 'undefined') {\n const originalReload = __VUE_HMR_RUNTIME__.reload\n\n __VUE_HMR_RUNTIME__.reload = function (id, newComp) {\n const plugins = window.panel && window.panel.plugins\n const app = window.panel && window.panel.app\n\n if (\n plugins\n && app\n && plugins.components\n && typeof plugins.resolveComponentExtension === 'function'\n && typeof plugins.resolveComponentRender === 'function'\n && typeof plugins.resolveComponentMixins === 'function'\n ) {\n for (const name in plugins.components) {\n const pluginComp = plugins.components[name]\n if (\n pluginComp.__hmrId === id\n || (newComp.__file && pluginComp.__file === newComp.__file)\n ) {\n plugins.resolveComponentExtension(app, name, newComp)\n plugins.resolveComponentRender(newComp)\n plugins.resolveComponentMixins(newComp)\n break\n }\n }\n }\n\n return originalReload.call(this, id, newComp)\n }\n}\nelse {\n console.warn(\n '[kirbyup] Vue HMR runtime not detected; component changes will fall back to full page reload. The Kirby Panel may be loading a production build of Vue.',\n )\n}\n";
177
+ //#endregion
178
+ //#region src/node/plugins/runtime/vue-stub.js?raw
179
+ var vue_stub_default = "const __kirbyupVueImportMapEl = typeof document !== 'undefined'\n ? document.querySelector('script[type=\"importmap\"]')\n : null\nconst __kirbyupVueImports = __kirbyupVueImportMapEl\n ? (() => {\n try {\n return JSON.parse(__kirbyupVueImportMapEl.textContent || '{}').imports || {}\n }\n // eslint-disable-next-line unused-imports/no-unused-vars\n catch (_) {\n return {}\n }\n })()\n : {}\nconst __kirbyupVueUrl = __kirbyupVueImports.vue\nif (!__kirbyupVueUrl) {\n throw new Error(\n '[kirbyup] No \"vue\" entry found in the page <script type=\"importmap\">. Ensure Kirby\\'s Panel is loaded with v6 import maps enabled.',\n )\n}\n// eslint-disable-next-line no-unused-vars, antfu/no-top-level-await\nconst __kirbyupVueModule = await import(/* @vite-ignore */ __kirbyupVueUrl)\n";
180
+ //#endregion
181
+ //#region src/node/plugins/utils.ts
182
+ /**
183
+ * Vue's `reload` does `Object.assign(record.initialDef, newComp)`, which would
184
+ * overwrite Kirby's in-place mutations on the stored definition. The shim
185
+ * re-runs Kirby's plugin helpers on `newComp` first; see
186
+ * https://github.com/getkirby/kirby/blob/v6/develop/panel/src/panel/plugins.ts
187
+ * ("expose helper functions for kirbyup"). `rerender` is not wrapped: in Vue 3
188
+ * it only swaps a render function, leaving Kirby's mutations untouched.
189
+ */
190
+ const __HMR_SHIM_CODE__ = hmr_shim_default;
191
+ /**
192
+ * Reads Kirby's panel-vue URL at runtime from the page's
193
+ * `<script type="importmap">` and dynamic-imports it; the browser's module
194
+ * map dedups by URL, so plugin SFCs share Kirby's Vue instance (and
195
+ * `__VUE_HMR_RUNTIME__`). Top-level await lets consumers keep using ordinary
196
+ * `import { ... } from 'vue'` syntax.
197
+ */
198
+ function buildVueStubCode(namedExports) {
199
+ if (namedExports.length === 0) return vue_stub_default;
200
+ return vue_stub_default + `\nexport const {\n${namedExports.map((name) => ` ${name},`).join("\n")}\n} = __kirbyupVueModule\n`;
201
+ }
202
+ //#endregion
203
+ //#region src/node/plugins/hmr.ts
204
+ const SHIM_ID = "\0kirbyup:hmr-shim";
205
+ const SHIM_PUBLIC_ID = SHIM_ID.slice(1);
206
+ const VUE_STUB_ID = "\0kirbyup:vue-stub";
207
+ const VUE_STUB_PUBLIC_ID = VUE_STUB_ID.slice(1);
208
+ const VUE_NOT_FOUND_STUB = `throw new Error('[kirbyup] Cannot resolve "vue" from the plugin project. Make sure "vue" is installed as a dependency.')\n`;
209
+ function kirbyupHmrPlugin(options) {
210
+ let config;
211
+ let entry;
212
+ let entryId;
213
+ let devIndexPath;
214
+ let vueStubCode;
215
+ return {
216
+ name: "kirbyup:hmr",
217
+ apply: "serve",
218
+ enforce: "pre",
219
+ config() {
220
+ return {
221
+ optimizeDeps: { exclude: ["vue"] },
222
+ resolve: { alias: [{
223
+ find: /^vue$/,
224
+ replacement: VUE_STUB_ID
225
+ }] }
226
+ };
227
+ },
228
+ async configResolved(resolvedConfig) {
229
+ config = resolvedConfig;
230
+ entry = resolve(config.root, options.entry);
231
+ entryId = normalizePath(entry);
232
+ devIndexPath = resolve(config.root, options.outDir ?? "", "index.dev.js");
233
+ try {
234
+ const vueModule = await import("vue");
235
+ const namedExports = Object.keys(vueModule).filter((name) => name !== "default");
236
+ vueStubCode = namedExports.length > 0 ? buildVueStubCode(namedExports) : void 0;
237
+ } catch {
238
+ vueStubCode = void 0;
239
+ }
240
+ },
241
+ resolveId(source) {
242
+ if (source === SHIM_ID || source === SHIM_PUBLIC_ID) return SHIM_ID;
243
+ if (source === VUE_STUB_ID || source === VUE_STUB_PUBLIC_ID) return VUE_STUB_ID;
244
+ },
245
+ load(id) {
246
+ if (id === SHIM_ID) return {
247
+ code: __HMR_SHIM_CODE__,
248
+ map: null,
249
+ moduleType: "js"
250
+ };
251
+ if (id === VUE_STUB_ID) return {
252
+ code: vueStubCode ?? VUE_NOT_FOUND_STUB,
253
+ map: null,
254
+ moduleType: "js"
255
+ };
256
+ },
257
+ transform(code, id) {
258
+ if (normalizePath(id.split("?")[0]) !== entryId) return;
259
+ if (code.includes(SHIM_PUBLIC_ID)) return;
260
+ return {
261
+ code: `import ${JSON.stringify(SHIM_ID)}\n${code}`,
262
+ map: null
263
+ };
264
+ },
265
+ configureServer(server) {
266
+ if (!server.httpServer) return;
267
+ server.httpServer.once("listening", async () => {
268
+ const entryPath = entry.replace(`${config.root}/`, "");
269
+ const baseUrl = getDevBaseUrl(server, config);
270
+ const entryUrl = new URL(entryPath, baseUrl).href;
271
+ const pm = detectPackageManager(config.root);
272
+ await fsp.writeFile(devIndexPath, getViteProxyModule(entryUrl, pm));
273
+ });
274
+ },
275
+ async closeBundle() {
276
+ await fsp.rm(devIndexPath, { force: true });
277
+ }
278
+ };
279
+ }
280
+ function getViteProxyModule(entryUrl, packageManager) {
281
+ return `
282
+ try {
283
+ await import("${entryUrl}");
284
+ } catch (error) {
285
+ console.error(
286
+ "[kirbyup] Couldn't connect to the development server at ${entryUrl}. Run \`${packageManager} run serve\` to start Vite or build the plugin with \`${packageManager} run build\` so Kirby uses the production version."
287
+ );
288
+ throw error;
289
+ }
290
+ `.trimStart();
291
+ }
292
+ function getDevBaseUrl(server, config) {
293
+ const { address, port } = server.httpServer.address();
294
+ const origin = config.server?.origin ?? server.resolvedUrls?.local?.[0] ?? server.resolvedUrls?.network?.[0] ?? resolveOriginFromServerOptions(config.server, port, address);
295
+ const base = config.base ?? "/";
296
+ return new URL(base, origin).href;
297
+ }
298
+ function detectPackageManager(cwd) {
299
+ if (fs.existsSync(resolve(cwd, "pnpm-lock.yaml"))) return "pnpm";
300
+ if (fs.existsSync(resolve(cwd, "bun.lock")) || fs.existsSync(resolve(cwd, "bun.lockb"))) return "bun";
301
+ if (fs.existsSync(resolve(cwd, "yarn.lock"))) return "yarn";
302
+ if (fs.existsSync(resolve(cwd, "deno.lock"))) return "deno";
303
+ return "npm";
304
+ }
305
+ //#endregion
306
+ //#region src/node/index.ts
307
+ const DEV_OUTPUT_FILENAME = "index.dev.js";
308
+ const SUPPRESSED_WARNING_PREFIX = "\n(!) build.outDir";
309
+ const logLevel = "warn";
310
+ function getViteConfig(command, options, { kirbyupConfig, postCssConfig, logger }) {
311
+ const aliasDir = resolve(options.cwd, dirname(options.entry));
312
+ const { alias = {}, vite } = kirbyupConfig;
313
+ const userConfig = vite ?? {};
314
+ const sharedConfig = {
315
+ resolve: { alias: {
316
+ "~/": `${aliasDir}/`,
317
+ "@/": `${aliasDir}/`,
318
+ ...alias
319
+ } },
320
+ plugins: [
321
+ vuePlugin({ compiler: vueCompilerSfc }),
322
+ vueJsxPlugin(),
323
+ kirbyupGlobImportPlugin()
324
+ ],
325
+ build: { copyPublicDir: false },
326
+ ...postCssConfig && { css: { postcss: {
327
+ ...postCssConfig.options,
328
+ plugins: postCssConfig.plugins
329
+ } } },
330
+ envDir: options.cwd,
331
+ envPrefix: ["VITE_", "KIRBYUP_"],
332
+ customLogger: logger,
333
+ logLevel
334
+ };
335
+ if (command === "serve") {
336
+ const { port, watch } = options;
337
+ const inferredOrigin = userConfig.server?.origin ?? resolveOriginFromServerOptions(userConfig.server, port, "localhost");
338
+ return mergeConfig(mergeConfig(sharedConfig, {
339
+ plugins: [kirbyupHmrPlugin(options), watch && kirbyupFullReloadPlugin(watch)].filter(Boolean),
340
+ build: { rollupOptions: { input: resolve(options.cwd, options.entry) } },
341
+ server: {
342
+ port,
343
+ strictPort: true,
344
+ origin: inferredOrigin,
345
+ cors: true
346
+ }
347
+ }), userConfig);
348
+ }
349
+ const mode = options.watch ? "development" : "production";
350
+ return mergeConfig(mergeConfig(sharedConfig, {
351
+ mode,
352
+ plugins: [kirbyupBuildCleanupPlugin(options)],
353
+ build: {
354
+ lib: {
355
+ entry: resolve(options.cwd, options.entry),
356
+ formats: ["es"],
357
+ fileName: () => options.watch ? DEV_OUTPUT_FILENAME : "index.js"
358
+ },
359
+ minify: mode === "production",
360
+ outDir: options.outDir,
361
+ emptyOutDir: false,
362
+ rollupOptions: {
363
+ external: ["vue"],
364
+ output: { assetFileNames: "index.[ext]" }
365
+ }
366
+ }
367
+ }), userConfig);
368
+ }
369
+ async function generate(options, context) {
370
+ const config = getViteConfig("build", options, context);
371
+ let result;
372
+ try {
373
+ result = await build(config);
374
+ } catch (error) {
375
+ if (!options.watch) throw error;
376
+ consola.error(error);
377
+ }
378
+ if (!result || options.watch) return;
379
+ const { output } = toArray(result)[0];
380
+ const maxLength = Math.max(0, ...output.map((item) => item.fileName.length));
381
+ for (const item of output) {
382
+ const content = item.type === "chunk" ? item.code : await fsp.readFile(resolve(options.outDir, item.fileName), "utf8");
383
+ await printFileInfo({
384
+ root: options.cwd,
385
+ outDir: options.outDir,
386
+ filePath: item.fileName,
387
+ content,
388
+ type: item.type,
389
+ maxLength
390
+ });
391
+ }
392
+ }
393
+ async function build$1(options) {
394
+ assertEntryExists(options);
395
+ const { cwd } = options;
396
+ const { config, configFile } = await loadConfig$1(cwd);
397
+ const postCssConfig = await resolvePostCSSConfig(cwd);
398
+ const context = {
399
+ kirbyupConfig: config ?? {},
400
+ postCssConfig,
401
+ logger: createKirbyupLogger()
402
+ };
403
+ consola.log(colors.green(`${name} v${version}`));
404
+ consola.start(`Building ${colors.cyan(options.entry)}`);
405
+ await generate(options, context);
406
+ consola.success("Build successful");
407
+ if (!options.watch) return;
408
+ const { watch } = await import("chokidar");
409
+ const debouncedBuild = debounce(() => {
410
+ generate(options, context).catch(handleError);
411
+ }, 100);
412
+ const ignored = [
413
+ "**/{.git,node_modules}/**",
414
+ "index.{css,js}",
415
+ DEV_OUTPUT_FILENAME
416
+ ];
417
+ const watchPaths = options.watch === true ? dirname(options.entry) : toArray(options.watch);
418
+ consola.info(`Watching for changes in ${toArray(watchPaths).map((i) => colors.cyan(i)).join(", ")}`);
419
+ const watcher = watch(watchPaths, {
420
+ ignoreInitial: true,
421
+ ignorePermissionErrors: true,
422
+ ignored,
423
+ cwd
424
+ });
425
+ const devOutputPath = resolve(options.outDir, DEV_OUTPUT_FILENAME);
426
+ const cleanup = async () => {
427
+ await watcher.close().catch(() => {});
428
+ await fsp.rm(devOutputPath, { force: true }).catch(() => {});
429
+ };
430
+ process.once("exit", () => {
431
+ try {
432
+ fs.rmSync(devOutputPath, { force: true });
433
+ } catch {}
434
+ });
435
+ const onShutdown = () => {
436
+ cleanup().finally(() => process.exit(0));
437
+ };
438
+ process.once("SIGINT", onShutdown);
439
+ process.once("SIGTERM", onShutdown);
440
+ if (configFile) watcher.add(configFile);
441
+ watcher.on("all", async (type, file) => {
442
+ if (configFile === resolve(cwd, file)) {
443
+ context.kirbyupConfig = (await loadConfig$1(cwd)).config ?? {};
444
+ consola.info(`${colors.cyan(basename(file))} changed, setting new config`);
445
+ } else consola.log(`${colors.green(type)} ${colors.white(colors.dim(file))}`);
446
+ debouncedBuild();
447
+ });
448
+ }
449
+ async function serve(options) {
450
+ assertEntryExists(options);
451
+ const { cwd } = options;
452
+ const { config } = await loadConfig$1(cwd);
453
+ const postCssConfig = await resolvePostCSSConfig(cwd);
454
+ const context = {
455
+ kirbyupConfig: config ?? {},
456
+ postCssConfig,
457
+ logger: createKirbyupLogger()
458
+ };
459
+ consola.log(colors.green(`${name} v${version}`));
460
+ consola.info("Starting development server…");
461
+ const server = await createServer(getViteConfig("serve", options, context));
462
+ await server.listen();
463
+ consola.success(`Server is listening on :${server.config.server.port}`);
464
+ return server;
465
+ }
466
+ function createKirbyupLogger() {
467
+ const baseLogger = createLogger(logLevel);
468
+ return {
469
+ ...baseLogger,
470
+ warn(msg, options) {
471
+ if (msg.startsWith(SUPPRESSED_WARNING_PREFIX)) return;
472
+ baseLogger.warn(msg, options);
473
+ }
474
+ };
475
+ }
476
+ function assertEntryExists(options) {
477
+ if (!fs.existsSync(resolve(options.cwd, options.entry))) throw new PrettyError(`Cannot find "${options.entry}"`);
478
+ }
479
+ //#endregion
480
+ export { version as a, name as i, serve as n, handleError as r, build$1 as t };
package/package.json CHANGED
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "name": "kirbyup",
3
3
  "type": "module",
4
- "version": "4.0.0-alpha.5",
5
- "packageManager": "pnpm@10.25.0",
4
+ "version": "4.0.0-alpha.7",
5
+ "packageManager": "pnpm@10.33.3",
6
6
  "description": "Zero-config bundler for Kirby Panel plugins",
7
7
  "author": {
8
8
  "name": "Johann Schopplich",
@@ -57,7 +57,7 @@
57
57
  "dist"
58
58
  ],
59
59
  "engines": {
60
- "node": ">=18"
60
+ "node": ">=24"
61
61
  },
62
62
  "scripts": {
63
63
  "build": "tsdown",
@@ -71,32 +71,32 @@
71
71
  "test:types": "tsc --noEmit"
72
72
  },
73
73
  "dependencies": {
74
- "@vitejs/plugin-vue": "^6.0.2",
75
- "@vitejs/plugin-vue-jsx": "^5.1.2",
76
- "@vue/compiler-sfc": "^3.5.25",
77
- "c12": "^3.3.2",
78
- "cac": "^6.7.14",
74
+ "@vitejs/plugin-vue": "^6.0.6",
75
+ "@vitejs/plugin-vue-jsx": "^5.1.5",
76
+ "@vue/compiler-sfc": "^3.5.34",
77
+ "c12": "^4.0.0-beta.4",
78
+ "cac": "^7.0.0",
79
79
  "chokidar": "^5.0.0",
80
80
  "consola": "^3.4.2",
81
81
  "magic-string": "^0.30.21",
82
- "nypm": "^0.6.2",
83
82
  "pathe": "^2.0.3",
84
- "perfect-debounce": "^2.0.0",
85
- "postcss": "^8.5.6",
83
+ "perfect-debounce": "^2.1.0",
84
+ "postcss": "^8.5.14",
86
85
  "postcss-load-config": "^6.0.1",
87
- "sass": "^1.95.1",
88
- "vite": "^7.2.7",
89
- "vite-plugin-full-reload": "^1.2.0",
90
- "vue": "^3.5.25"
86
+ "sass": "^1.99.0",
87
+ "strip-literal": "^3.1.0",
88
+ "vite": "^8.0.10",
89
+ "vue": "^3.5.34"
91
90
  },
92
91
  "devDependencies": {
93
- "@antfu/eslint-config": "^6.6.1",
94
- "@types/node": "^24.10.2",
95
- "bumpp": "^10.3.2",
96
- "eslint": "^9.39.1",
97
- "tinyglobby": "^0.2.15",
98
- "tsdown": "^0.17.2",
99
- "typescript": "^5.9.3",
100
- "vitest": "^4.0.15"
92
+ "@antfu/eslint-config": "^8.2.0",
93
+ "@types/node": "^24.12.2",
94
+ "bumpp": "^11.0.1",
95
+ "eslint": "^10.3.0",
96
+ "eslint-flat-config-utils": "^3.2.0",
97
+ "tsdown": "^0.21.10",
98
+ "typescript": "^6.0.3",
99
+ "unplugin-raw": "^0.7.0",
100
+ "vitest": "^4.1.5"
101
101
  }
102
102
  }
@@ -1,496 +0,0 @@
1
- import * as fs from "node:fs";
2
- import * as fsp from "node:fs/promises";
3
- import vuePlugin from "@vitejs/plugin-vue";
4
- import vueJsxPlugin from "@vitejs/plugin-vue-jsx";
5
- import { consola } from "consola";
6
- import { colors } from "consola/utils";
7
- import { basename, dirname, normalize, relative, resolve } from "pathe";
8
- import { debounce } from "perfect-debounce";
9
- import { build, createLogger, mergeConfig } from "vite";
10
- import fullReloadPlugin from "vite-plugin-full-reload";
11
- import * as vueCompilerSfc from "vue/compiler-sfc";
12
- import { loadConfig } from "c12";
13
- import postcssrc from "postcss-load-config";
14
- import { detectPackageManager } from "nypm";
15
- import { isIP } from "node:net";
16
- import { Buffer } from "node:buffer";
17
- import { promisify } from "node:util";
18
- import { gzip } from "node:zlib";
19
-
20
- //#region package.json
21
- var name = "kirbyup";
22
- var version = "4.0.0-alpha.5";
23
-
24
- //#endregion
25
- //#region src/node/config.ts
26
- function loadConfig$1(cwd = process.cwd()) {
27
- return loadConfig({
28
- cwd,
29
- name: "kirbyup",
30
- rcFile: false,
31
- packageJson: false
32
- });
33
- }
34
- async function resolvePostCSSConfig(cwd) {
35
- try {
36
- return await postcssrc(void 0, void 0, { stopDir: cwd });
37
- } catch (error) {
38
- if (!error.message.includes("No PostCSS Config found")) throw error;
39
- }
40
- }
41
-
42
- //#endregion
43
- //#region src/node/errors.ts
44
- var PrettyError = class extends Error {
45
- constructor(message) {
46
- super(message);
47
- this.name = this.constructor.name;
48
- if (typeof Error.captureStackTrace === "function") Error.captureStackTrace(this, this.constructor);
49
- else this.stack = new Error(message).stack;
50
- }
51
- };
52
- function handleError(error) {
53
- consola.error(error.message);
54
- process.exitCode = 1;
55
- }
56
-
57
- //#endregion
58
- //#region src/node/plugins/build-cleanup.ts
59
- function kirbyupBuildCleanupPlugin(options) {
60
- let config;
61
- let devIndexPath;
62
- return {
63
- name: "kirbyup:build-cleanup",
64
- configResolved(resolvedConfig) {
65
- config = resolvedConfig;
66
- devIndexPath = resolve(config.root, options.outDir, "index.dev.mjs");
67
- },
68
- writeBundle() {
69
- if (fs.existsSync(devIndexPath)) fs.unlinkSync(devIndexPath);
70
- }
71
- };
72
- }
73
-
74
- //#endregion
75
- //#region src/node/utils/server.ts
76
- function resolveOriginFromServerOptions(serverOptions, port, fallbackHostname) {
77
- const protocol = serverOptions?.https && (typeof serverOptions.https === "boolean" || Object.keys(serverOptions.https).length > 0) ? "https" : "http";
78
- const configuredHost = normalizeHost(serverOptions?.host);
79
- return `${protocol}://${formatHostname(configuredHost || fallbackHostname || "localhost")}${(configuredHost ? hostIncludesPort(configuredHost) : false) || !needsExplicitPort(protocol, port) ? "" : `:${port}`}`;
80
- }
81
- function ensureTrailingSlash(url) {
82
- return url.endsWith("/") ? url : `${url}/`;
83
- }
84
- function normalizeHost(host) {
85
- if (host === false || host === void 0) return;
86
- if (host === true) return "0.0.0.0";
87
- return host;
88
- }
89
- function formatHostname(host) {
90
- if (!host) return "localhost";
91
- if (host.startsWith("[") && host.endsWith("]")) return host;
92
- return isIP(host) === 6 ? `[${host}]` : host;
93
- }
94
- function hostIncludesPort(host) {
95
- if (host.startsWith("[")) {
96
- const closingIndex = host.indexOf("]");
97
- return closingIndex > -1 && host.slice(closingIndex + 1).startsWith(":");
98
- }
99
- if (isIP(host) === 6) return false;
100
- return host.includes(":");
101
- }
102
- function needsExplicitPort(protocol, port) {
103
- if (protocol === "http") return port !== 80;
104
- return port !== 443;
105
- }
106
-
107
- //#endregion
108
- //#region src/node/plugins/utils.ts
109
- /**
110
- * This code is injected into Vue 3 components to wrap the global HMR runtime.
111
- *
112
- * All `.vue` components register themselves with the HMR runtime (`__VUE_HMR_RUNTIME__`),
113
- * which stores their component definitions in a map. When a module is updated, the runtime
114
- * applies changes to the stored definition and re-renders component instances.
115
- *
116
- * In Vue 3, the HMR map structure is:
117
- * ```js
118
- * {
119
- * [id]: { initialDef: ComponentDefinition, instances: Set<ComponentInstance> }
120
- * }
121
- * ```
122
- *
123
- * However, Kirby does not register the exact object exported from a `.vue` file.
124
- * Instead, it creates a new object and merges the definition in:
125
- * https://github.com/getkirby/kirby/blob/main/panel/public/js/plugins.js
126
- *
127
- * After HMR changes, the runtime updates the stored definition and re-renders instances,
128
- * but since they are derived from Kirby's modified object (not the stored definition),
129
- * updates may not apply correctly.
130
- *
131
- * To fix this, we wrap `__VUE_HMR_RUNTIME__.rerender()` and `__VUE_HMR_RUNTIME__.reload()`:
132
- *
133
- * 1. **Before updates**, we check if the component belongs to a Kirby plugin by matching
134
- * the `__hmrId` or `__file` properties against registered plugin components.
135
- *
136
- * 2. **If matched**, we look up the actual component definition used by Kirby
137
- * (`window.panel.app.config.globalProperties.$root.$options.components`)
138
- * and update the HMR map's reference to point to it.
139
- *
140
- * 3. **For section components** (detected by `k-*-section` name pattern), we add a
141
- * `$_isSection` flag for special treatment in `$_applyKirbyModifications()`.
142
- *
143
- * `$_applyKirbyModifications()`:
144
- *
145
- * Kirby modifies component definitions before registration:
146
- * - Adds the section mixin to section components
147
- * - Gives templates priority over render functions
148
- * - Resolves component names in `extends` to their definition objects
149
- *
150
- * When a module hot reloads, Vue 3 receives a fresh component definition missing
151
- * these modifications. We re-apply them to ensure the runtime doesn't prune them
152
- * when patching the stored definition with the updated one.
153
- *
154
- * This code uses a singleton pattern (`__KIRBYUP_HMR_WRAPPED__`) to ensure the
155
- * wrapper is installed only once, even though it's injected into every component.
156
- */
157
- const __HMR_INJECTION_CODE__ = `
158
- /** - injected by kirbyup for Vue 3 HMR - */
159
- if (typeof __VUE_HMR_RUNTIME__ !== 'undefined' && !window.__KIRBYUP_HMR_WRAPPED__) {
160
- window.__KIRBYUP_HMR_WRAPPED__ = true;
161
-
162
- const originalRerender = __VUE_HMR_RUNTIME__.rerender;
163
- const originalReload = __VUE_HMR_RUNTIME__.reload;
164
-
165
- __VUE_HMR_RUNTIME__.rerender = function(id, newRender) {
166
- $_syncKirbyComponent(id);
167
- return originalRerender.call(this, id, newRender);
168
- };
169
-
170
- __VUE_HMR_RUNTIME__.reload = function(id, newComp) {
171
- const record = $_getHmrRecord(id);
172
- if (record) {
173
- $_syncKirbyComponent(id, record.initialDef);
174
- $_applyKirbyModifications(record.initialDef, newComp);
175
- }
176
- return originalReload.call(this, id, newComp);
177
- };
178
-
179
- function $_getHmrRecord(id) {
180
- // Vue 3's HMR map is not exposed, so we maintain our own parallel map
181
- // by wrapping \`createRecord\` to track component definitions
182
- if (!window.__KIRBYUP_MAP__) {
183
- window.__KIRBYUP_MAP__ = new Map();
184
- const originalCreate = __VUE_HMR_RUNTIME__.createRecord;
185
- __VUE_HMR_RUNTIME__.createRecord = function(id, initialDef) {
186
- window.__KIRBYUP_MAP__.set(id, { initialDef });
187
- return originalCreate.call(this, id, initialDef);
188
- };
189
- }
190
- return window.__KIRBYUP_MAP__.get(id);
191
- }
192
-
193
- function $_syncKirbyComponent(id, activeDef) {
194
- const pluginComponents = window.panel?.plugins?.components;
195
- const usedComponentDefs = window.panel?.app?.config?.globalProperties?.$root?.$options?.components;
196
-
197
- if (!pluginComponents || !usedComponentDefs) return;
198
-
199
- const record = $_getHmrRecord(id);
200
- if (!record) return;
201
-
202
- for (const componentName in pluginComponents) {
203
- const pluginComp = pluginComponents[componentName];
204
-
205
- if (pluginComp.__hmrId === id || pluginComp.__file === record.initialDef?.__file) {
206
- const usedDef = usedComponentDefs[componentName];
207
-
208
- if (usedDef && record.initialDef !== usedDef) {
209
- record.initialDef = usedDef;
210
- }
211
-
212
- if (activeDef && typeof activeDef.$_isSection !== 'boolean') {
213
- activeDef.$_isSection = /^k-.*-section$/.test(componentName);
214
- }
215
-
216
- break;
217
- }
218
- }
219
- }
220
-
221
- function $_applyKirbyModifications(activeDef, newDef) {
222
- const usedComponentDefs = window.panel?.app?.config?.globalProperties?.$root?.$options?.components;
223
-
224
- if (!usedComponentDefs) return;
225
-
226
- // Give templates priority over render functions
227
- if (newDef.template) {
228
- newDef.render = null;
229
- }
230
-
231
- // Re-apply section mixin for section components
232
- if (activeDef.$_isSection) {
233
- newDef.$_isSection = true;
234
- if (!newDef.mixins?.[0]?.methods?.load) {
235
- const sectionMixin = activeDef.mixins?.[0];
236
- if (sectionMixin) {
237
- newDef.mixins = [sectionMixin, ...(newDef.mixins || [])];
238
- }
239
- }
240
- }
241
-
242
- // Resolve component name in extends to definition object
243
- if (typeof newDef.extends === 'string') {
244
- if (newDef.extends === activeDef.extends?.name) {
245
- newDef.extends = activeDef.extends;
246
- } else if (usedComponentDefs[newDef.extends]) {
247
- newDef.extends = usedComponentDefs[newDef.extends];
248
- } else {
249
- newDef.extends = null;
250
- }
251
- }
252
- }
253
- }
254
- /** -- */
255
- `;
256
-
257
- //#endregion
258
- //#region src/node/plugins/hmr.ts
259
- function kirbyupHmrPlugin(options) {
260
- let config;
261
- let entry;
262
- let devIndexPath;
263
- return {
264
- name: "kirbyup:hmr",
265
- apply: "serve",
266
- configResolved(resolvedConfig) {
267
- config = resolvedConfig;
268
- entry = resolve(config.root, options.entry);
269
- devIndexPath = resolve(config.root, options.outDir ?? "", "index.dev.mjs");
270
- },
271
- transform(code, id) {
272
- if (!id.endsWith(".vue")) return;
273
- if (!code.includes("__VUE_HMR_RUNTIME__.createRecord")) return;
274
- const injectionPoint = code.indexOf("import.meta.hot.accept");
275
- if (injectionPoint === -1) return;
276
- return {
277
- code: `${code.slice(0, injectionPoint) + __HMR_INJECTION_CODE__}\n${code.slice(injectionPoint)}`,
278
- map: null
279
- };
280
- },
281
- configureServer(server) {
282
- if (!server.httpServer) return;
283
- server.httpServer.once("listening", async () => {
284
- const entryPath = entry.replace(`${config.root}/`, "");
285
- const baseUrl = getDevBaseUrl(server, config);
286
- const entryUrl = new URL(entryPath, baseUrl).href;
287
- const pm = await detectPackageManager(config.root);
288
- await fsp.writeFile(devIndexPath, getViteProxyModule(entryUrl, pm));
289
- });
290
- },
291
- async closeBundle() {
292
- await fsp.rm(devIndexPath, { force: true });
293
- }
294
- };
295
- }
296
- /**
297
- * Proxy the JS file to "forward" the plugin script loaded by Kirby to the Vite server
298
- */
299
- function getViteProxyModule(entryUrl, packageManager) {
300
- const pm = packageManager?.name || "npm";
301
- return `
302
- try {
303
- await import("${entryUrl}");
304
- } catch (error) {
305
- console.error(
306
- "[kirbyup] Couldn't connect to the development server at ${entryUrl}. Run \`${pm} run serve\` to start Vite or build the plugin with \`${pm} run build\` so Kirby uses the production version."
307
- );
308
- throw error;
309
- }
310
- `.trimStart();
311
- }
312
- function getDevBaseUrl(server, config) {
313
- const { address, port } = server.httpServer.address();
314
- const normalizedOrigin = ensureTrailingSlash(config.server?.origin ?? server.resolvedUrls?.local?.[0] ?? server.resolvedUrls?.network?.[0] ?? resolveOriginFromServerOptions(config.server, port, address));
315
- const base = config.base ?? "/";
316
- return new URL(base, normalizedOrigin).href;
317
- }
318
-
319
- //#endregion
320
- //#region src/node/utils.ts
321
- const compress = promisify(gzip);
322
- function toArray(array) {
323
- array ??= [];
324
- return Array.isArray(array) ? array : [array];
325
- }
326
- async function getCompressedSize(code) {
327
- return ` / gzip: ${((await compress(typeof code === "string" ? code : Buffer.from(code))).length / 1024).toFixed(2)} KiB`;
328
- }
329
- async function printFileInfo({ root, outDir, filePath, content, type, maxLength }) {
330
- const prettyOutDir = `${normalize(relative(root, resolve(root, outDir)))}/`;
331
- const kibs = content.length / 1024;
332
- const compressedSize = await getCompressedSize(content);
333
- const writeColor = type === "chunk" ? colors.cyan : colors.magenta;
334
- consola.log(colors.white(colors.dim(prettyOutDir)) + writeColor(filePath.padEnd(maxLength + 2)) + colors.dim(`${kibs.toFixed(2)} kB${compressedSize}`));
335
- }
336
-
337
- //#endregion
338
- //#region src/node/index.ts
339
- const DEV_OUTPUT_FILENAME = "index.dev.js";
340
- let resolvedKirbyupConfig;
341
- let resolvedPostCssConfig;
342
- const logLevel = "warn";
343
- const logger = createLogger(logLevel);
344
- const loggerWarn = logger.warn;
345
- logger.warn = (msg, options) => {
346
- if (msg.includes("(!) build.outDir")) return;
347
- loggerWarn(msg, options);
348
- };
349
- function getViteConfig(command, options) {
350
- const aliasDir = resolve(options.cwd, dirname(options.entry));
351
- const { alias = {}, vite } = resolvedKirbyupConfig;
352
- const userConfig = vite ?? {};
353
- const sharedConfig = {
354
- resolve: { alias: {
355
- "~/": `${aliasDir}/`,
356
- "@/": `${aliasDir}/`,
357
- ...alias
358
- } },
359
- plugins: [vuePlugin({ compiler: vueCompilerSfc }), vueJsxPlugin()],
360
- build: { copyPublicDir: false },
361
- ...resolvedPostCssConfig && { css: { postcss: resolvedPostCssConfig } },
362
- envDir: options.cwd,
363
- envPrefix: ["VITE_", "KIRBYUP_"],
364
- customLogger: logger,
365
- logLevel
366
- };
367
- if (command === "serve") {
368
- const { port, watch } = options;
369
- const inferredOrigin = userConfig.server?.origin ?? resolveOriginFromServerOptions(userConfig.server, port, "localhost");
370
- return mergeConfig(mergeConfig(sharedConfig, {
371
- plugins: [kirbyupHmrPlugin(options), watch && fullReloadPlugin(watch)].filter(Boolean),
372
- build: { rollupOptions: { input: resolve(options.cwd, options.entry) } },
373
- server: {
374
- port,
375
- strictPort: true,
376
- origin: inferredOrigin
377
- }
378
- }), userConfig);
379
- }
380
- const mode = options.watch ? "development" : "production";
381
- return mergeConfig(mergeConfig(sharedConfig, {
382
- mode,
383
- plugins: [kirbyupBuildCleanupPlugin(options)],
384
- build: {
385
- lib: {
386
- entry: resolve(options.cwd, options.entry),
387
- formats: ["es"],
388
- fileName: () => options.watch ? DEV_OUTPUT_FILENAME : "index.js"
389
- },
390
- minify: mode === "production",
391
- outDir: options.outDir,
392
- emptyOutDir: false,
393
- rollupOptions: {
394
- external: ["vue"],
395
- output: { assetFileNames: "index.[ext]" }
396
- }
397
- }
398
- }), userConfig);
399
- }
400
- async function generate(options) {
401
- const config = getViteConfig("build", options);
402
- let result;
403
- try {
404
- result = await build(config);
405
- } catch (error) {
406
- if (config.mode === "production") throw error;
407
- else consola.error(error);
408
- }
409
- if (result && !options.watch) {
410
- const { output } = toArray(result)[0];
411
- let maxLength = 0;
412
- for (const chunkFile in output) {
413
- const fileNameLength = output[chunkFile].fileName.length;
414
- if (fileNameLength > maxLength) maxLength = fileNameLength;
415
- }
416
- for (const { fileName, type, code } of output) {
417
- const content = code || await fsp.readFile(resolve(options.outDir, fileName), "utf8");
418
- await printFileInfo({
419
- root: options.cwd,
420
- outDir: options.outDir,
421
- filePath: fileName,
422
- content,
423
- type,
424
- maxLength
425
- });
426
- }
427
- }
428
- return result;
429
- }
430
- async function build$1(options) {
431
- assertEntryExists(options);
432
- const { cwd } = options;
433
- const { config, configFile } = await loadConfig$1(cwd);
434
- resolvedKirbyupConfig = config ?? {};
435
- resolvedPostCssConfig = await resolvePostCSSConfig(cwd);
436
- consola.log(colors.green(`${name} v${version}`));
437
- consola.start(`Building ${colors.cyan(options.entry)}`);
438
- if (options.watch) consola.info("Running in watch mode");
439
- await generate(options);
440
- consola.success("Build successful");
441
- if (!options.watch) return;
442
- const { watch } = await import("chokidar");
443
- const debouncedBuild = debounce(async () => {
444
- generate(options).catch(handleError);
445
- }, 100);
446
- const ignored = [
447
- "**/{.git,node_modules}/**",
448
- "index.{css,js}",
449
- DEV_OUTPUT_FILENAME
450
- ];
451
- const watchPaths = typeof options.watch === "boolean" ? dirname(options.entry) : Array.isArray(options.watch) ? options.watch.filter((path) => typeof path === "string") : options.watch;
452
- consola.info(`Watching for changes in ${toArray(watchPaths).map((i) => colors.cyan(i)).join(", ")}`);
453
- const watcher = watch(watchPaths, {
454
- ignoreInitial: true,
455
- ignorePermissionErrors: true,
456
- ignored,
457
- cwd
458
- });
459
- const devOutputPath = resolve(options.outDir, DEV_OUTPUT_FILENAME);
460
- const cleanup = async () => {
461
- await watcher.close().catch(() => {});
462
- await fsp.rm(devOutputPath, { force: true }).catch(() => {});
463
- };
464
- process.once("exit", () => {
465
- try {
466
- fs.rmSync(devOutputPath, { force: true });
467
- } catch {}
468
- });
469
- const onShutdown = () => void cleanup().finally(() => process.exit(0));
470
- process.once("SIGINT", onShutdown);
471
- process.once("SIGTERM", onShutdown);
472
- if (configFile) watcher.add(configFile);
473
- watcher.on("all", async (type, file) => {
474
- if (configFile === resolve(cwd, file)) {
475
- resolvedKirbyupConfig = (await loadConfig$1(cwd)).config ?? {};
476
- consola.info(`${colors.cyan(basename(file))} changed, setting new config`);
477
- } else consola.log(`${colors.green(type)} ${colors.white(colors.dim(file))}`);
478
- debouncedBuild();
479
- });
480
- }
481
- async function serve(options) {
482
- assertEntryExists(options);
483
- const { cwd } = options;
484
- const { config } = await loadConfig$1(cwd);
485
- resolvedKirbyupConfig = config ?? {};
486
- resolvedPostCssConfig = await resolvePostCSSConfig(cwd);
487
- consola.log(colors.green(`${name} v${version}`));
488
- consola.info(`Development server unavailable. Use watch mode for now: ${colors.cyan(`kirbyup build ${options.entry} --watch`)}`);
489
- throw new PrettyError("HMR is not yet implemented for Kirby 6 plugins. Please use watch mode instead.");
490
- }
491
- function assertEntryExists(options) {
492
- if (!fs.existsSync(resolve(options.cwd, options.entry))) throw new PrettyError(`Cannot find "${options.entry}"`);
493
- }
494
-
495
- //#endregion
496
- export { version as a, name as i, serve as n, handleError as r, build$1 as t };