@hybridly/vite 0.10.0-beta.13 → 0.10.0-beta.15

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/dist/index.mjs CHANGED
@@ -1,269 +1,23 @@
1
1
  import { r as __toESM } from "./_chunks/rolldown-runtime.mjs";
2
- import { t as require_src } from "./_chunks/libs/debug.mjs";
3
2
  import { t as require_cjs } from "./_chunks/libs/deepmerge.mjs";
4
- import { t as isPlainObject } from "./_chunks/libs/is-plain-object.mjs";
5
- import "./_chunks/libs/throttle-debounce.mjs";
6
- import { t as require_lodash_clonedeep } from "./_chunks/libs/lodash.clonedeep.mjs";
7
- import fs from "node:fs";
3
+ import { t as isPlainObject } from "./_chunks/libs/es-toolkit.mjs";
4
+ import "./_chunks/libs/@clickbar/dot-diver.mjs";
5
+ import { t as require_src } from "./_chunks/libs/debug.mjs";
8
6
  import path from "node:path";
9
- import colors from "picocolors";
10
- import { loadEnv } from "vite";
11
- import os from "node:os";
7
+ import fs from "node:fs";
12
8
  import { exec } from "node:child_process";
13
9
  import { promisify } from "node:util";
14
- import MagicString from "magic-string";
10
+ import { loadEnv } from "vite";
15
11
  import run from "vite-plugin-run";
16
12
  import vue from "@vitejs/plugin-vue";
17
- //#region src/config/env.ts
18
- let phpExecutable;
19
- let devEnvironment;
20
- /**
21
- * Gets all environment variables, including `.env` ones.
22
- */
23
- function getEnv() {
24
- return {
25
- ...process.env,
26
- ...loadEnv("mock", process.cwd(), "")
27
- };
28
- }
29
- async function getPhpExecutable() {
30
- if (phpExecutable) return phpExecutable;
31
- const env = getEnv();
32
- const php = (env.PHP_EXECUTABLE_PATH ?? "php").split(" ");
33
- if (!env.PHP_EXECUTABLE_PATH) {
34
- const devEnvironment = await determineDevEnvironment();
35
- if (devEnvironment === "ddev") php.unshift("ddev");
36
- else if (devEnvironment === "lando") php.unshift("lando");
37
- }
38
- return phpExecutable = php;
39
- }
40
- async function determineDevEnvironment() {
41
- if (devEnvironment) return devEnvironment;
42
- if (fs.existsSync(`${process.cwd()}/.ddev`)) devEnvironment = "ddev";
43
- else if (fs.existsSync(`${process.cwd()}/.lando.yml`)) devEnvironment = "lando";
44
- else devEnvironment = "native";
45
- return devEnvironment;
46
- }
47
- //#endregion
48
- //#region src/laravel/utils.ts
49
- function isIpv6(address) {
50
- return address.family === "IPv6" || address.family === 6;
51
- }
52
- //#endregion
53
- //#region src/laravel/dev-env.ts
54
- /**
55
- * Resolves the path to the Herd or Valet configuration directory.
56
- */
57
- function determineDevelopmentEnvironmentConfigPath() {
58
- const herdConfigPath = path.resolve(os.homedir(), "Library", "Application Support", "Herd", "config", "valet");
59
- if (fs.existsSync(herdConfigPath)) return herdConfigPath;
60
- return path.resolve(os.homedir(), ".config", "valet");
61
- }
62
- /**
63
- * Resolves the Herd or Valet host for the current directory.
64
- */
65
- function resolveDevelopmentEnvironmentHost(configPath) {
66
- const configFile = path.resolve(configPath, "config.json");
67
- if (!fs.existsSync(configFile)) return;
68
- const config = JSON.parse(fs.readFileSync(configFile, "utf-8"));
69
- return `${path.basename(process.cwd())}.${config.tld}`;
70
- }
71
- /**
72
- * Resolves the Herd or Valet server config for the given host.
73
- */
74
- function resolveDevelopmentEnvironmentServerConfig() {
75
- const configPath = determineDevelopmentEnvironmentConfigPath();
76
- const host = resolveDevelopmentEnvironmentHost(configPath);
77
- if (!host) return;
78
- const keyPath = path.resolve(configPath, "Certificates", `${host}.key`);
79
- const certPath = path.resolve(configPath, "Certificates", `${host}.crt`);
80
- if (!fs.existsSync(keyPath) || !fs.existsSync(certPath)) return;
81
- return {
82
- hmr: { host },
83
- host,
84
- https: {
85
- key: fs.readFileSync(keyPath),
86
- cert: fs.readFileSync(certPath)
87
- }
88
- };
89
- }
90
- /**
91
- * Resolves the server config from the environment.
92
- */
93
- function resolveEnvironmentServerConfig(env) {
94
- if (!env.VITE_DEV_SERVER_KEY && !env.VITE_DEV_SERVER_CERT) return;
95
- if (!fs.existsSync(env.VITE_DEV_SERVER_KEY) || !fs.existsSync(env.VITE_DEV_SERVER_CERT)) throw new Error(`Unable to find the certificate files specified in your environment. Ensure you have correctly configured VITE_DEV_SERVER_KEY: [${env.VITE_DEV_SERVER_KEY}] and VITE_DEV_SERVER_CERT: [${env.VITE_DEV_SERVER_CERT}].`);
96
- const host = resolveHostFromEnv(env);
97
- return {
98
- hmr: { host },
99
- host,
100
- https: {
101
- key: fs.readFileSync(env.VITE_DEV_SERVER_KEY),
102
- cert: fs.readFileSync(env.VITE_DEV_SERVER_CERT)
103
- }
104
- };
105
- }
106
- /**
107
- * Resolve the host name from the environment.
108
- */
109
- function resolveHostFromEnv(env) {
110
- if (env.VITE_DEV_SERVER_KEY) return env.VITE_DEV_SERVER_KEY;
111
- try {
112
- return new URL(env.APP_URL).host;
113
- } catch {
114
- throw new Error(`Unable to determine the host from the environment's APP_URL: [${env.APP_URL}].`);
115
- }
116
- }
117
- //#endregion
118
- //#region src/laravel/index.ts
119
- let exitHandlersBound = false;
120
- function laravel(options, hybridlyConfig) {
121
- let viteDevServerUrl;
122
- let resolvedConfig;
123
- let userConfig;
124
- const publicDirectory = "public";
125
- const buildDirectory = "build";
126
- const hotFile = path.join(publicDirectory, "hot");
127
- return {
128
- name: "hybridly:laravel",
129
- enforce: "post",
130
- config: (config, { command, mode }) => {
131
- userConfig = config;
132
- const ssr = !!userConfig.build?.ssr;
133
- const env = loadEnv(mode, userConfig.envDir || process.cwd(), "");
134
- const assetUrl = env.ASSET_URL ?? "";
135
- const base = `${assetUrl + (!assetUrl.endsWith("/") ? "/" : "") + buildDirectory}/`;
136
- const serverConfig = command === "serve" ? resolveEnvironmentServerConfig(env) ?? resolveDevelopmentEnvironmentServerConfig() : void 0;
137
- ensureCommandShouldRunInEnvironment(command, env);
138
- return {
139
- base: userConfig.base ?? (command === "build" ? base : ""),
140
- publicDir: userConfig.publicDir ?? false,
141
- build: {
142
- manifest: ssr === true ? false : userConfig.build?.manifest ?? "manifest.json",
143
- outDir: userConfig.build?.outDir ?? path.join(publicDirectory, buildDirectory),
144
- rollupOptions: { input: resolveInput(config, hybridlyConfig, ssr) },
145
- assetsInlineLimit: userConfig.build?.assetsInlineLimit ?? 0
146
- },
147
- server: {
148
- origin: userConfig.server?.origin ?? "http://__laravel_vite_placeholder__.test",
149
- cors: userConfig.server?.cors ?? { origin: userConfig.server?.origin ?? [
150
- /^https?:\/\/(?:(?:[^:]+\.)?localhost|127\.0\.0\.1|\[::1\])(?::\d+)?$/,
151
- ...env.APP_URL ? [env.APP_URL] : [],
152
- /^https?:\/\/.*\.test(:\d+)?$/
153
- ] },
154
- ...process.env.LARAVEL_SAIL ? {
155
- host: userConfig.server?.host ?? "0.0.0.0",
156
- port: userConfig.server?.port ?? (env.VITE_PORT ? Number.parseInt(env.VITE_PORT) : 5173),
157
- strictPort: userConfig.server?.strictPort ?? true
158
- } : void 0,
159
- ...serverConfig ? {
160
- host: userConfig.server?.host ?? serverConfig.host,
161
- hmr: userConfig.server?.hmr === false ? false : {
162
- ...serverConfig.hmr,
163
- ...userConfig.server?.hmr === true ? {} : userConfig.server?.hmr
164
- },
165
- https: userConfig.server?.https ?? serverConfig.https
166
- } : void 0
167
- }
168
- };
169
- },
170
- configResolved(config) {
171
- resolvedConfig = config;
172
- },
173
- transform(code) {
174
- if (resolvedConfig.command === "serve") return code.replace(/http:\/\/__laravel_vite_placeholder__\.test/g, viteDevServerUrl);
175
- },
176
- configureServer(server) {
177
- const envDir = resolvedConfig.envDir || process.cwd();
178
- const appUrl = loadEnv(resolvedConfig.mode, envDir, "APP_URL").APP_URL ?? "undefined";
179
- if (!["test", "ci"].includes(resolvedConfig.mode)) server.httpServer?.once("listening", async () => {
180
- const address = server.httpServer?.address();
181
- const isAddressInfo = (x) => typeof x === "object";
182
- if (isAddressInfo(address)) {
183
- viteDevServerUrl = resolveDevServerUrl(address, server.config, userConfig);
184
- fs.writeFileSync(hotFile, `${viteDevServerUrl}${server.config.base.replace(/\/$/, "")}`);
185
- if (!hybridlyConfig.versions) return;
186
- let registered = `${colors.bold(hybridlyConfig.components.views.length)} ${colors.dim("views")}, `;
187
- registered += `${colors.bold(hybridlyConfig.components.layouts.length)} ${colors.dim("layouts")}, `;
188
- const latest = hybridlyConfig.versions.is_latest ? "" : colors.dim(`(${colors.yellow(`${hybridlyConfig.versions.latest} is available`)})`);
189
- let version = `${colors.yellow(`v${hybridlyConfig.versions.composer}`)} ${colors.dim("(composer)")}, `;
190
- version += `${colors.yellow(`v${hybridlyConfig.versions.npm}`)} ${colors.dim("(npm)")}`;
191
- version += ` — ${colors.yellow("this may lead to undefined behavior")}`;
192
- const devEnvironment = await determineDevEnvironment();
193
- setTimeout(() => {
194
- server.config.logger.info(`\n ${colors.magenta(`${colors.bold("HYBRIDLY")} v${hybridlyConfig.versions.composer}`)} ${latest}`);
195
- server.config.logger.info("");
196
- server.config.logger.info(` ${colors.green("➜")} ${colors.bold("URL")}: ${colors.cyan(hybridlyConfig.routing.url)}`);
197
- server.config.logger.info(` ${colors.green("➜")} ${colors.bold("Registered")}: ${registered}`);
198
- if (devEnvironment !== "native") server.config.logger.info(` ${colors.green("➜")} ${colors.bold("Development environment")}: ${colors.cyan(devEnvironment)}`);
199
- if (hybridlyConfig.versions.composer !== hybridlyConfig.versions.npm) server.config.logger.info(` ${colors.yellow("➜")} ${colors.bold("Version mismatch")}: ${version}`);
200
- }, 100);
201
- }
202
- });
203
- if (!exitHandlersBound) {
204
- function clean() {
205
- if (fs.existsSync(hotFile)) fs.rmSync(hotFile);
206
- }
207
- process.on("exit", clean);
208
- process.on("SIGINT", () => process.exit());
209
- process.on("SIGTERM", () => process.exit());
210
- process.on("SIGHUP", () => process.exit());
211
- exitHandlersBound = true;
212
- }
213
- return () => server.middlewares.use((req, res, next) => {
214
- if (req.url === "/index.html") {
215
- res.writeHead(302, { Location: appUrl });
216
- res.end();
217
- }
218
- next();
219
- });
220
- }
221
- };
222
- }
223
- /**
224
- * Validates the command can run in the given environment.
225
- */
226
- function ensureCommandShouldRunInEnvironment(command, env) {
227
- if (command === "build" || env.LARAVEL_BYPASS_ENV_CHECK === "1" || !!env.TEST || !!env.VITEST) return;
228
- if (typeof env.LARAVEL_VAPOR !== "undefined") throw new TypeError("You should not run the Vite HMR server on Vapor. You should build your assets for production instead. To disable this ENV check you may set LARAVEL_BYPASS_ENV_CHECK=1");
229
- if (typeof env.LARAVEL_FORGE !== "undefined") throw new TypeError("You should not run the Vite HMR server in your Forge deployment script. You should build your assets for production instead. To disable this ENV check you may set LARAVEL_BYPASS_ENV_CHECK=1");
230
- if (typeof env.LARAVEL_ENVOYER !== "undefined") throw new TypeError("You should not run the Vite HMR server in your Envoyer hook. You should build your assets for production instead. To disable this ENV check you may set LARAVEL_BYPASS_ENV_CHECK=1");
231
- if (typeof env.CI !== "undefined") throw new TypeError("You should not run the Vite HMR server in CI environments. You should build your assets for production instead. To disable this ENV check you may set LARAVEL_BYPASS_ENV_CHECK=1");
232
- }
233
- /**
234
- * Resolves input files.
235
- */
236
- function resolveInput(userConfig, hybridlyConfig, _ssr) {
237
- return userConfig.build?.rollupOptions?.input ?? hybridlyConfig.architecture.application_main_path;
238
- }
239
- /**
240
- * Resolves the dev server URL from the server address and configuration.
241
- */
242
- function resolveDevServerUrl(address, config, userConfig) {
243
- const configHmrProtocol = typeof config.server.hmr === "object" ? config.server.hmr.protocol : null;
244
- const clientProtocol = configHmrProtocol ? configHmrProtocol === "wss" ? "https" : "http" : null;
245
- const serverProtocol = config.server.https ? "https" : "http";
246
- const protocol = clientProtocol ?? serverProtocol;
247
- const configHmrHost = typeof config.server.hmr === "object" ? config.server.hmr.host : null;
248
- const configHost = typeof config.server.host === "string" ? config.server.host : null;
249
- const sailHost = process.env.LARAVEL_SAIL && !userConfig.server?.host ? "localhost" : null;
250
- const serverAddress = isIpv6(address) ? `[${address.address}]` : address.address;
251
- return `${protocol}://${configHmrHost ?? sailHost ?? configHost ?? serverAddress}:${(typeof config.server.hmr === "object" ? config.server.hmr.clientPort : null) ?? address.port}`;
252
- }
253
- //#endregion
13
+ import colors from "picocolors";
14
+ import os from "node:os";
15
+ import MagicString from "magic-string";
254
16
  //#region src/constants.ts
255
17
  const LAYOUT_PLUGIN_NAME = "vite:hybridly:layout";
256
18
  const CONFIG_PLUGIN_NAME = "vite:hybridly:config";
257
19
  const RESOLVED_CONFIG_VIRTUAL_MODULE_ID = `\0virtual:hybridly/config`;
258
20
  //#endregion
259
- //#region src/utils.ts
260
- var import_src = /* @__PURE__ */ __toESM(require_src(), 1);
261
- const execSync = promisify(exec);
262
- const debug$1 = {
263
- config: (0, import_src.default)(CONFIG_PLUGIN_NAME),
264
- layout: (0, import_src.default)(LAYOUT_PLUGIN_NAME)
265
- };
266
- //#endregion
267
21
  //#region src/typegen/index.ts
268
22
  function generateTsConfig(options, config) {
269
23
  const tsconfig = {
@@ -277,18 +31,22 @@ function generateTsConfig(options, config) {
277
31
  sourceMap: true,
278
32
  resolveJsonModule: true,
279
33
  esModuleInterop: true,
34
+ rootDir: "../",
280
35
  allowSyntheticDefaultImports: true,
281
- lib: ["esnext", "dom"],
36
+ lib: [
37
+ "esnext",
38
+ "dom",
39
+ "dom.iterable"
40
+ ],
282
41
  types: [
283
42
  "vite/client",
284
43
  "hybridly/client",
285
44
  ...options.tsconfig?.types ?? []
286
45
  ],
287
- baseUrl: "..",
288
46
  paths: {
289
- "#/*": [".hybridly/*"],
290
- "~/*": ["./*"],
291
- "@/*": [`./${config.architecture.root_directory}/*`]
47
+ "#/*": ["./*"],
48
+ "~/*": ["../*"],
49
+ "@/*": [`../${config.architecture.root_directory}/*`]
292
50
  }
293
51
  },
294
52
  include: [
@@ -341,55 +99,12 @@ declare module 'vue' {
341
99
  }
342
100
  `, "vue-extension.d.ts");
343
101
  }
344
- async function generateRouteDefinitionFile(options, config) {
345
- const routing = config?.routing;
346
- if (!routing) return;
347
- debug$1.config("Writing types for routing:", routing);
348
- const routes = Object.fromEntries(Object.entries(routing.routes).map(([key, route]) => {
349
- const bindings = route.bindings ? Object.fromEntries(Object.entries(route.bindings).map(([key]) => [key, "__key_placeholder__"])) : void 0;
350
- return [key, {
351
- ...route.uri ? { uri: route.uri } : {},
352
- ...route.domain ? { domain: route.domain } : {},
353
- ...route.wheres ? { wheres: route.wheres } : {},
354
- ...route.bindings ? { bindings } : {}
355
- }];
356
- }));
357
- write(`
358
- /* eslint-disable */
359
- /* prettier-ignore */
360
- // This file has been automatically generated by Hybridly
361
- // Modifications will be discarded
362
-
363
- declare module 'hybridly' {
364
- export interface GlobalRouteCollection {
365
- url: '__URL__'
366
- routes: __ROUTES__
367
- }
368
- }
369
-
370
- export {}
371
- `.replace("__URL__", routing?.url ?? "").replace("__ROUTES__", JSON.stringify(routes).replaceAll("\"__key_placeholder__\"", "any")), "routes.d.ts");
372
- }
373
102
  function write(data, filename) {
374
103
  const hybridlyPath = path.resolve(process.cwd(), ".hybridly");
375
104
  if (!fs.existsSync(hybridlyPath)) fs.mkdirSync(hybridlyPath);
376
105
  fs.writeFileSync(path.resolve(hybridlyPath, filename), data, { encoding: "utf-8" });
377
106
  }
378
107
  //#endregion
379
- //#region src/config/load.ts
380
- async function loadConfiguration() {
381
- try {
382
- const { stdout } = await execSync(`${(await getPhpExecutable()).join(" ")} artisan hybridly:config`);
383
- return JSON.parse(stdout);
384
- } catch (e) {
385
- console.error("Could not load configuration from [php artisan hybridly:config].");
386
- if (e.stdout) console.error(e.stdout);
387
- if (await determineDevEnvironment() === "ddev") console.error("This is possibly caused by not starting ddev first.");
388
- else if (await determineDevEnvironment() === "lando") console.error("This is possibly caused by not starting lando first.");
389
- throw e;
390
- }
391
- }
392
- //#endregion
393
108
  //#region src/config/client.ts
394
109
  function getClientCode$1(config) {
395
110
  const paths = config.components.views.map(({ path }) => `"~/${path}"`).join(",");
@@ -406,11 +121,58 @@ function getClientCode$1(config) {
406
121
  `;
407
122
  }
408
123
  //#endregion
124
+ //#region src/utils.ts
125
+ const execSync = promisify(exec);
126
+ //#endregion
127
+ //#region src/config/env.ts
128
+ let phpExecutable;
129
+ let devEnvironment;
130
+ /**
131
+ * Gets all environment variables, including `.env` ones.
132
+ */
133
+ function getEnv() {
134
+ return {
135
+ ...process.env,
136
+ ...loadEnv("mock", process.cwd(), "")
137
+ };
138
+ }
139
+ async function getPhpExecutable() {
140
+ if (phpExecutable) return phpExecutable;
141
+ const env = getEnv();
142
+ const php = (env.PHP_EXECUTABLE_PATH ?? "php").split(" ");
143
+ if (!env.PHP_EXECUTABLE_PATH) {
144
+ const devEnvironment = await determineDevEnvironment();
145
+ if (devEnvironment === "ddev") php.unshift("ddev");
146
+ else if (devEnvironment === "lando") php.unshift("lando");
147
+ }
148
+ return phpExecutable = php;
149
+ }
150
+ async function determineDevEnvironment() {
151
+ if (devEnvironment) return devEnvironment;
152
+ if (fs.existsSync(`${process.cwd()}/.ddev`)) devEnvironment = "ddev";
153
+ else if (fs.existsSync(`${process.cwd()}/.lando.yml`)) devEnvironment = "lando";
154
+ else devEnvironment = "native";
155
+ return devEnvironment;
156
+ }
157
+ //#endregion
158
+ //#region src/config/load.ts
159
+ async function loadConfiguration() {
160
+ try {
161
+ const { stdout } = await execSync(`${(await getPhpExecutable()).join(" ")} artisan hybridly:config`);
162
+ return JSON.parse(stdout);
163
+ } catch (e) {
164
+ console.error("Could not load configuration from [php artisan hybridly:config].");
165
+ if (e.stdout) console.error(e.stdout);
166
+ if (await determineDevEnvironment() === "ddev") console.error("This is possibly caused by not starting ddev first.");
167
+ else if (await determineDevEnvironment() === "lando") console.error("This is possibly caused by not starting lando first.");
168
+ throw e;
169
+ }
170
+ }
171
+ //#endregion
409
172
  //#region src/config/index.ts
410
173
  var config_default = (options, config) => {
411
174
  generateTsConfig(options, config);
412
175
  generateLaravelIdeaHelper(config);
413
- generateRouteDefinitionFile(options, config);
414
176
  generateVueExtensionFile();
415
177
  return {
416
178
  name: CONFIG_PLUGIN_NAME,
@@ -435,7 +197,6 @@ var config_default = (options, config) => {
435
197
  }
436
198
  async function handleFileChange(file) {
437
199
  if (file.endsWith("config/hybridly.php")) return await forceRestart("Configuration file changed");
438
- if (/routes\/.*\.php/.test(file) || /routes\.php/.test(file)) return await forceRestart("Routing changed");
439
200
  if (/.*\.vue$/.test(file)) loadConfiguration().then((updatedConfig) => {
440
201
  if (didViewsOrLayoutsChange(updatedConfig, config)) forceRestart("View or layout changed");
441
202
  }).catch();
@@ -444,29 +205,362 @@ var config_default = (options, config) => {
444
205
  server.watcher.on("change", handleFileChange);
445
206
  server.watcher.on("unlink", handleFileChange);
446
207
  },
447
- resolveId(id) {
448
- if (id === "virtual:hybridly/config") return RESOLVED_CONFIG_VIRTUAL_MODULE_ID;
208
+ resolveId(id) {
209
+ if (id === "virtual:hybridly/config") return RESOLVED_CONFIG_VIRTUAL_MODULE_ID;
210
+ },
211
+ async load(id) {
212
+ if (id === RESOLVED_CONFIG_VIRTUAL_MODULE_ID) return getClientCode$1(config);
213
+ },
214
+ async handleHotUpdate(ctx) {
215
+ if (ctx.file.includes(".hybridly")) return [];
216
+ }
217
+ };
218
+ };
219
+ function didViewsOrLayoutsChange(updatedConfig, previousConfig) {
220
+ if (!previousConfig) return false;
221
+ return JSON.stringify(updatedConfig.components.views) !== JSON.stringify(previousConfig.components.views) || JSON.stringify(updatedConfig.components.layouts) !== JSON.stringify(previousConfig.components.layouts);
222
+ }
223
+ //#endregion
224
+ //#region src/integrations/run.ts
225
+ async function getRunOptions(options) {
226
+ if (options.run === false) return [];
227
+ const php = await getPhpExecutable();
228
+ return [
229
+ {
230
+ name: "Generate TypeScript definitions",
231
+ run: [
232
+ ...php,
233
+ "artisan",
234
+ "hybridly:types",
235
+ options.allowTypeGenerationFailures !== false ? "--allow-failures" : ""
236
+ ].filter(Boolean),
237
+ pattern: ["+(app|config|routes|src)/**/*.php"]
238
+ },
239
+ {
240
+ name: "Generate i18n",
241
+ run: [
242
+ ...php,
243
+ "artisan",
244
+ "hybridly:i18n"
245
+ ],
246
+ pattern: "lang/**/*.php"
247
+ },
248
+ ...options.run ?? []
249
+ ];
250
+ }
251
+ //#endregion
252
+ //#region src/integrations/unplugins.ts
253
+ /**
254
+ * Import map for auto-importing Hybridly utils.
255
+ */
256
+ const hybridlyImports = {
257
+ "hybridly/vue": [
258
+ "useProperty",
259
+ "setProperty",
260
+ "useRefinements",
261
+ "useTable",
262
+ "useBulkSelect",
263
+ "useProperties",
264
+ "useBackForward",
265
+ "useContext",
266
+ "useForm",
267
+ "useDialog",
268
+ "useHistoryState",
269
+ "createPaginator",
270
+ "registerHook",
271
+ "useRoute",
272
+ "useQueryParameter",
273
+ "useQueryParameters"
274
+ ],
275
+ "hybridly": [
276
+ "router",
277
+ "route",
278
+ "can",
279
+ "getRouterContext"
280
+ ]
281
+ };
282
+ //#endregion
283
+ //#region ../utils/src/utils.ts
284
+ var import_cjs = /* @__PURE__ */ __toESM(require_cjs(), 1);
285
+ function merge(x, y, options = {}) {
286
+ return (0, import_cjs.default)(x, y, {
287
+ arrayMerge: typeof options?.arrayMerge === "function" ? options.arrayMerge : options?.overwriteArray !== false ? (_, s) => s : void 0,
288
+ isMergeableObject: options?.mergePlainObjects ? isPlainObject : void 0
289
+ });
290
+ }
291
+ //#endregion
292
+ //#region ../utils/src/debug.ts
293
+ var import_src = /* @__PURE__ */ __toESM(require_src(), 1);
294
+ const debug = {
295
+ router: (0, import_src.default)("hybridly:core:router"),
296
+ queue: (0, import_src.default)("hybridly:core:router:queue"),
297
+ history: (0, import_src.default)("hybridly:core:history"),
298
+ url: (0, import_src.default)("hybridly:core:url"),
299
+ context: (0, import_src.default)("hybridly:core:context"),
300
+ external: (0, import_src.default)("hybridly:core:external"),
301
+ scroll: (0, import_src.default)("hybridly:core:scroll"),
302
+ hook: (0, import_src.default)("hybridly:core:hook"),
303
+ layout: (0, import_src.default)("hybridly:plugin:layout"),
304
+ config: (0, import_src.default)("hybridly:vite:config"),
305
+ plugin: (name, ...args) => (0, import_src.default)("hybridly:plugin").extend(name.replace("hybridly:", ""))(args.shift(), ...args),
306
+ adapter: (name, ...args) => (0, import_src.default)("hybridly:adapter").extend(name)(args.shift(), ...args)
307
+ };
308
+ //#endregion
309
+ //#region src/integrations/vue.ts
310
+ function getVueOptions(options) {
311
+ if (options.vue === false) return {};
312
+ return merge({
313
+ template: {
314
+ transformAssetUrls: {
315
+ base: null,
316
+ includeAbsolute: false
317
+ },
318
+ ...options.vue?.template
319
+ },
320
+ script: {
321
+ globalTypeFiles: [path.resolve(".hybridly/php-types.d.ts")],
322
+ defineModel: true,
323
+ ...options.vue?.script
324
+ }
325
+ }, options.vue ?? {}, { overwriteArray: false });
326
+ }
327
+ //#endregion
328
+ //#region src/kill-switch.ts
329
+ function killSwitch() {
330
+ let _enabled = false;
331
+ return {
332
+ name: "hybridly:build:kill-switch",
333
+ config: ({ mode }) => {
334
+ if (mode === "build") _enabled = true;
335
+ },
336
+ buildEnd: (error) => {
337
+ if (!_enabled) return;
338
+ if (error) {
339
+ console.error("Error when bundling");
340
+ console.error(error);
341
+ process.exit(1);
342
+ }
343
+ },
344
+ closeBundle: () => {
345
+ if (!_enabled) return;
346
+ process.exit(0);
347
+ }
348
+ };
349
+ }
350
+ //#endregion
351
+ //#region src/laravel/utils.ts
352
+ function isIpv6(address) {
353
+ return address.family === "IPv6" || address.family === 6;
354
+ }
355
+ //#endregion
356
+ //#region src/laravel/dev-env.ts
357
+ /**
358
+ * Resolves the path to the Herd or Valet configuration directory.
359
+ */
360
+ function determineDevelopmentEnvironmentConfigPath() {
361
+ const herdConfigPath = path.resolve(os.homedir(), "Library", "Application Support", "Herd", "config", "valet");
362
+ if (fs.existsSync(herdConfigPath)) return herdConfigPath;
363
+ return path.resolve(os.homedir(), ".config", "valet");
364
+ }
365
+ /**
366
+ * Resolves the Herd or Valet host for the current directory.
367
+ */
368
+ function resolveDevelopmentEnvironmentHost(configPath) {
369
+ const configFile = path.resolve(configPath, "config.json");
370
+ if (!fs.existsSync(configFile)) return;
371
+ const config = JSON.parse(fs.readFileSync(configFile, "utf-8"));
372
+ return `${path.basename(process.cwd())}.${config.tld}`;
373
+ }
374
+ /**
375
+ * Resolves the Herd or Valet server config for the given host.
376
+ */
377
+ function resolveDevelopmentEnvironmentServerConfig() {
378
+ const configPath = determineDevelopmentEnvironmentConfigPath();
379
+ const host = resolveDevelopmentEnvironmentHost(configPath);
380
+ if (!host) return;
381
+ const keyPath = path.resolve(configPath, "Certificates", `${host}.key`);
382
+ const certPath = path.resolve(configPath, "Certificates", `${host}.crt`);
383
+ if (!fs.existsSync(keyPath) || !fs.existsSync(certPath)) return;
384
+ return {
385
+ hmr: { host },
386
+ host,
387
+ https: {
388
+ key: fs.readFileSync(keyPath),
389
+ cert: fs.readFileSync(certPath)
390
+ }
391
+ };
392
+ }
393
+ /**
394
+ * Resolves the server config from the environment.
395
+ */
396
+ function resolveEnvironmentServerConfig(env) {
397
+ if (!env.VITE_DEV_SERVER_KEY && !env.VITE_DEV_SERVER_CERT) return;
398
+ if (!fs.existsSync(env.VITE_DEV_SERVER_KEY) || !fs.existsSync(env.VITE_DEV_SERVER_CERT)) throw new Error(`Unable to find the certificate files specified in your environment. Ensure you have correctly configured VITE_DEV_SERVER_KEY: [${env.VITE_DEV_SERVER_KEY}] and VITE_DEV_SERVER_CERT: [${env.VITE_DEV_SERVER_CERT}].`);
399
+ const host = resolveHostFromEnv(env);
400
+ return {
401
+ hmr: { host },
402
+ host,
403
+ https: {
404
+ key: fs.readFileSync(env.VITE_DEV_SERVER_KEY),
405
+ cert: fs.readFileSync(env.VITE_DEV_SERVER_CERT)
406
+ }
407
+ };
408
+ }
409
+ /**
410
+ * Resolve the host name from the environment.
411
+ */
412
+ function resolveHostFromEnv(env) {
413
+ if (env.VITE_DEV_SERVER_KEY) return env.VITE_DEV_SERVER_KEY;
414
+ try {
415
+ return new URL(env.APP_URL).host;
416
+ } catch {
417
+ throw new Error(`Unable to determine the host from the environment's APP_URL: [${env.APP_URL}].`);
418
+ }
419
+ }
420
+ //#endregion
421
+ //#region src/laravel/index.ts
422
+ let exitHandlersBound = false;
423
+ function laravel(options, hybridlyConfig) {
424
+ let viteDevServerUrl;
425
+ let resolvedConfig;
426
+ let userConfig;
427
+ const publicDirectory = "public";
428
+ const buildDirectory = "build";
429
+ const hotFile = path.join(publicDirectory, "hot");
430
+ return {
431
+ name: "hybridly:laravel",
432
+ enforce: "post",
433
+ config: (config, { command, mode }) => {
434
+ userConfig = config;
435
+ const ssr = !!userConfig.build?.ssr;
436
+ const env = loadEnv(mode, userConfig.envDir || process.cwd(), "");
437
+ const assetUrl = env.ASSET_URL ?? "";
438
+ const base = `${assetUrl + (!assetUrl.endsWith("/") ? "/" : "") + buildDirectory}/`;
439
+ const serverConfig = command === "serve" ? resolveEnvironmentServerConfig(env) ?? resolveDevelopmentEnvironmentServerConfig() : void 0;
440
+ ensureCommandShouldRunInEnvironment(command, env);
441
+ return {
442
+ base: userConfig.base ?? (command === "build" ? base : ""),
443
+ publicDir: userConfig.publicDir ?? false,
444
+ build: {
445
+ manifest: ssr === true ? false : userConfig.build?.manifest ?? "manifest.json",
446
+ outDir: userConfig.build?.outDir ?? path.join(publicDirectory, buildDirectory),
447
+ rollupOptions: { input: resolveInput(config, hybridlyConfig, ssr) },
448
+ assetsInlineLimit: userConfig.build?.assetsInlineLimit ?? 0
449
+ },
450
+ server: {
451
+ origin: userConfig.server?.origin ?? "http://__laravel_vite_placeholder__.test",
452
+ cors: userConfig.server?.cors ?? { origin: userConfig.server?.origin ?? [
453
+ /^https?:\/\/(?:(?:[^:]+\.)?localhost|127\.0\.0\.1|\[::1\])(?::\d+)?$/,
454
+ ...env.APP_URL ? [env.APP_URL] : [],
455
+ /^https?:\/\/.*\.test(:\d+)?$/
456
+ ] },
457
+ ...process.env.LARAVEL_SAIL ? {
458
+ host: userConfig.server?.host ?? "0.0.0.0",
459
+ port: userConfig.server?.port ?? (env.VITE_PORT ? Number.parseInt(env.VITE_PORT) : 5173),
460
+ strictPort: userConfig.server?.strictPort ?? true
461
+ } : void 0,
462
+ ...serverConfig ? {
463
+ host: userConfig.server?.host ?? serverConfig.host,
464
+ hmr: userConfig.server?.hmr === false ? false : {
465
+ ...serverConfig.hmr,
466
+ ...userConfig.server?.hmr === true ? {} : userConfig.server?.hmr
467
+ },
468
+ https: userConfig.server?.https ?? serverConfig.https
469
+ } : void 0
470
+ }
471
+ };
472
+ },
473
+ configResolved(config) {
474
+ resolvedConfig = config;
449
475
  },
450
- async load(id) {
451
- if (id === RESOLVED_CONFIG_VIRTUAL_MODULE_ID) return getClientCode$1(config);
476
+ transform(code) {
477
+ if (resolvedConfig.command === "serve") return code.replace(/http:\/\/__laravel_vite_placeholder__\.test/g, viteDevServerUrl);
452
478
  },
453
- async handleHotUpdate(ctx) {
454
- if (ctx.file.includes(".hybridly")) return [];
479
+ configureServer(server) {
480
+ const envDir = resolvedConfig.envDir || process.cwd();
481
+ const appUrl = loadEnv(resolvedConfig.mode, envDir, "APP_URL").APP_URL ?? "undefined";
482
+ if (!["test", "ci"].includes(resolvedConfig.mode)) server.httpServer?.once("listening", async () => {
483
+ const address = server.httpServer?.address();
484
+ const isAddressInfo = (x) => typeof x === "object";
485
+ if (isAddressInfo(address)) {
486
+ viteDevServerUrl = resolveDevServerUrl(address, server.config, userConfig);
487
+ fs.writeFileSync(hotFile, `${viteDevServerUrl}${server.config.base.replace(/\/$/, "")}`);
488
+ if (!hybridlyConfig.versions) return;
489
+ let registered = `${colors.bold(hybridlyConfig.components.views.length)} ${colors.dim("views")}, `;
490
+ registered += `${colors.bold(hybridlyConfig.components.layouts.length)} ${colors.dim("layouts")}, `;
491
+ const latest = hybridlyConfig.versions.is_latest ? "" : colors.dim(`(${colors.yellow(`${hybridlyConfig.versions.latest} is available`)})`);
492
+ let version = `${colors.yellow(`v${hybridlyConfig.versions.composer}`)} ${colors.dim("(composer)")}, `;
493
+ version += `${colors.yellow(`v${hybridlyConfig.versions.npm}`)} ${colors.dim("(npm)")}`;
494
+ version += ` — ${colors.yellow("this may lead to undefined behavior")}`;
495
+ const devEnvironment = await determineDevEnvironment();
496
+ setTimeout(() => {
497
+ server.config.logger.info(`\n ${colors.magenta(`${colors.bold("HYBRIDLY")} v${hybridlyConfig.versions.composer}`)} ${latest}`);
498
+ server.config.logger.info("");
499
+ server.config.logger.info(` ${colors.green("➜")} ${colors.bold("URL")}: ${colors.cyan(hybridlyConfig.routing.url)}`);
500
+ server.config.logger.info(` ${colors.green("➜")} ${colors.bold("Registered")}: ${registered}`);
501
+ if (devEnvironment !== "native") server.config.logger.info(` ${colors.green("➜")} ${colors.bold("Development environment")}: ${colors.cyan(devEnvironment)}`);
502
+ if (hybridlyConfig.versions.composer !== hybridlyConfig.versions.npm) server.config.logger.info(` ${colors.yellow("➜")} ${colors.bold("Version mismatch")}: ${version}`);
503
+ }, 100);
504
+ }
505
+ });
506
+ if (!exitHandlersBound) {
507
+ function clean() {
508
+ if (fs.existsSync(hotFile)) fs.rmSync(hotFile);
509
+ }
510
+ process.on("exit", clean);
511
+ process.on("SIGINT", () => process.exit());
512
+ process.on("SIGTERM", () => process.exit());
513
+ process.on("SIGHUP", () => process.exit());
514
+ exitHandlersBound = true;
515
+ }
516
+ return () => server.middlewares.use((req, res, next) => {
517
+ if (req.url === "/index.html") {
518
+ res.writeHead(302, { Location: appUrl });
519
+ res.end();
520
+ }
521
+ next();
522
+ });
455
523
  }
456
524
  };
457
- };
458
- function didViewsOrLayoutsChange(updatedConfig, previousConfig) {
459
- if (!previousConfig) return false;
460
- return JSON.stringify(updatedConfig.components.views) !== JSON.stringify(previousConfig.components.views) || JSON.stringify(updatedConfig.components.layouts) !== JSON.stringify(previousConfig.components.layouts);
525
+ }
526
+ /**
527
+ * Validates the command can run in the given environment.
528
+ */
529
+ function ensureCommandShouldRunInEnvironment(command, env) {
530
+ if (command === "build" || env.LARAVEL_BYPASS_ENV_CHECK === "1" || !!env.TEST || !!env.VITEST) return;
531
+ if (typeof env.LARAVEL_VAPOR !== "undefined") throw new TypeError("You should not run the Vite HMR server on Vapor. You should build your assets for production instead. To disable this ENV check you may set LARAVEL_BYPASS_ENV_CHECK=1");
532
+ if (typeof env.LARAVEL_FORGE !== "undefined") throw new TypeError("You should not run the Vite HMR server in your Forge deployment script. You should build your assets for production instead. To disable this ENV check you may set LARAVEL_BYPASS_ENV_CHECK=1");
533
+ if (typeof env.LARAVEL_ENVOYER !== "undefined") throw new TypeError("You should not run the Vite HMR server in your Envoyer hook. You should build your assets for production instead. To disable this ENV check you may set LARAVEL_BYPASS_ENV_CHECK=1");
534
+ if (typeof env.CI !== "undefined") throw new TypeError("You should not run the Vite HMR server in CI environments. You should build your assets for production instead. To disable this ENV check you may set LARAVEL_BYPASS_ENV_CHECK=1");
535
+ }
536
+ /**
537
+ * Resolves input files.
538
+ */
539
+ function resolveInput(userConfig, hybridlyConfig, _ssr) {
540
+ return userConfig.build?.rollupOptions?.input ?? hybridlyConfig.architecture.application_main_path;
541
+ }
542
+ /**
543
+ * Resolves the dev server URL from the server address and configuration.
544
+ */
545
+ function resolveDevServerUrl(address, config, userConfig) {
546
+ const configHmrProtocol = typeof config.server.hmr === "object" ? config.server.hmr.protocol : null;
547
+ const clientProtocol = configHmrProtocol ? configHmrProtocol === "wss" ? "https" : "http" : null;
548
+ const serverProtocol = config.server.https ? "https" : "http";
549
+ const protocol = clientProtocol ?? serverProtocol;
550
+ const configHmrHost = typeof config.server.hmr === "object" ? config.server.hmr.host : null;
551
+ const configHost = typeof config.server.host === "string" ? config.server.host : null;
552
+ const sailHost = process.env.LARAVEL_SAIL && !userConfig.server?.host ? "localhost" : null;
553
+ const serverAddress = isIpv6(address) ? `[${address.address}]` : address.address;
554
+ return `${protocol}://${configHmrHost ?? sailHost ?? configHost ?? serverAddress}:${(typeof config.server.hmr === "object" ? config.server.hmr.clientPort : null) ?? address.port}`;
461
555
  }
462
556
  //#endregion
463
557
  //#region src/layout/index.ts
464
- const TEMPLATE_LAYOUT_REGEX = /<template +layout(?: *= *['"]((?:[\w\/\-_,:](?:,\ )?)+)['"] *)?>/;
558
+ const TEMPLATE_LAYOUT_REGEX = /<template +layout(?: *= *['"]((?:[\w\/\-_,:.](?:,\ )?)+)['"] *)?>/;
465
559
  const LANG_REGEX = /lang=['"](\w+)['"]/;
466
560
  var layout_default = (options, config) => {
467
- const defaultLayoutName = options?.layout?.defaultLayoutName?.replace(".vue", "") ?? "default";
561
+ const defaultLayoutName = options?.layout?.defaultLayoutName?.replace(".layout.vue", "")?.replace(".vue", "") ?? "default";
468
562
  const templateRegExp = options?.layout?.templateRegExp ?? TEMPLATE_LAYOUT_REGEX;
469
- debug$1.layout("Resolved options:", { defaultLayoutName });
563
+ debug.layout("Resolved options:", { defaultLayoutName });
470
564
  return {
471
565
  name: LAYOUT_PLUGIN_NAME,
472
566
  enforce: "pre",
@@ -475,13 +569,22 @@ var layout_default = (options, config) => {
475
569
  const updatedCode = new MagicString(code).replace(templateRegExp, (_, layoutName) => {
476
570
  const [hasLang, lang] = code.match(LANG_REGEX) ?? [];
477
571
  const layouts = layoutName?.toString()?.replaceAll(" ", "").split(",") ?? [defaultLayoutName];
572
+ if (layouts.length === 1 && layouts.at(0) === "false") {
573
+ debug.layout(`User opted out of layouts`, { layouts });
574
+ return `
575
+ <script${hasLang ? ` lang="${lang}"` : ""}>
576
+ export default { layout: [] }
577
+ <\/script>
578
+ <template>
579
+ `.replace(/^\s+/gm, "");
580
+ }
478
581
  const importName = (i) => `__hybridly_layout_${i}`;
479
582
  const exports = layouts.map((_, i) => importName(i));
480
583
  const imports = layouts.reduce((imports, layoutName, i) => `
481
584
  ${imports}
482
585
  import ${importName(i)} from '${resolveLayoutImportPath(layoutName, config)}';
483
586
  `, "").trim();
484
- debug$1.layout(`Resolved layouts "${layouts.join(", ")}":`, {
587
+ debug.layout(`Resolved layouts "${layouts.join(", ")}":`, {
485
588
  sourceFile: id,
486
589
  layouts,
487
590
  imports
@@ -492,7 +595,7 @@ var layout_default = (options, config) => {
492
595
  export default { layout: [${exports.join(", ")}] }
493
596
  <\/script>
494
597
  <template>
495
- `;
598
+ `.replace(/^\s+/gm, "");
496
599
  });
497
600
  return {
498
601
  map: updatedCode.generateMap(),
@@ -510,91 +613,6 @@ function resolveLayoutImportPath(name, config) {
510
613
  return `~/${path}`;
511
614
  }
512
615
  //#endregion
513
- //#region src/integrations/run.ts
514
- async function getRunOptions(options) {
515
- if (options.run === false) return [];
516
- const php = await getPhpExecutable();
517
- return [
518
- {
519
- name: "Generate TypeScript types",
520
- run: [
521
- ...php,
522
- "artisan",
523
- "hybridly:types",
524
- options.allowTypeGenerationFailures !== false ? "--allow-failures" : ""
525
- ].filter(Boolean),
526
- pattern: [
527
- "+(app|src)/**/*Data.php",
528
- "+(app|src)/**/Enums/*.php",
529
- "+(app|src)/**/Middleware/HandleHybridRequests.php"
530
- ]
531
- },
532
- {
533
- name: "Generate i18n",
534
- run: [
535
- ...php,
536
- "artisan",
537
- "hybridly:i18n"
538
- ],
539
- pattern: "lang/**/*.php"
540
- },
541
- ...options.run ?? []
542
- ];
543
- }
544
- //#endregion
545
- //#region ../utils/src/utils.ts
546
- var import_cjs = /* @__PURE__ */ __toESM(require_cjs(), 1);
547
- require_lodash_clonedeep();
548
- function merge(x, y, options = {}) {
549
- return (0, import_cjs.default)(x, y, {
550
- arrayMerge: typeof options?.arrayMerge === "function" ? options.arrayMerge : options?.overwriteArray !== false ? (_, s) => s : void 0,
551
- isMergeableObject: options?.mergePlainObjects ? isPlainObject : void 0
552
- });
553
- }
554
- (0, import_src.default)("hybridly:core:router"), (0, import_src.default)("hybridly:core:history"), (0, import_src.default)("hybridly:core:url"), (0, import_src.default)("hybridly:core:context"), (0, import_src.default)("hybridly:core:external"), (0, import_src.default)("hybridly:core:scroll"), (0, import_src.default)("hybridly:core:hook");
555
- //#endregion
556
- //#region src/integrations/vue.ts
557
- function getVueOptions(options) {
558
- if (options.vue === false) return {};
559
- return merge({
560
- template: {
561
- transformAssetUrls: {
562
- base: null,
563
- includeAbsolute: false
564
- },
565
- ...options.vue?.template
566
- },
567
- script: {
568
- globalTypeFiles: [path.resolve(".hybridly/php-types.d.ts")],
569
- defineModel: true,
570
- ...options.vue?.script
571
- }
572
- }, options.vue ?? {}, { overwriteArray: false });
573
- }
574
- //#endregion
575
- //#region src/kill-switch.ts
576
- function killSwitch() {
577
- let _enabled = false;
578
- return {
579
- name: "hybridly:build:kill-switch",
580
- config: ({ mode }) => {
581
- if (mode === "build") _enabled = true;
582
- },
583
- buildEnd: (error) => {
584
- if (!_enabled) return;
585
- if (error) {
586
- console.error("Error when bundling");
587
- console.error(error);
588
- process.exit(1);
589
- }
590
- },
591
- closeBundle: () => {
592
- if (!_enabled) return;
593
- process.exit(0);
594
- }
595
- };
596
- }
597
- //#endregion
598
616
  //#region src/local-build/client.ts
599
617
  function getClientCode() {
600
618
  return `
@@ -683,37 +701,6 @@ function warnOnLocalBuilds() {
683
701
  };
684
702
  }
685
703
  //#endregion
686
- //#region src/integrations/unplugins.ts
687
- /**
688
- * Import map for auto-importing Hybridly utils.
689
- */
690
- const hybridlyImports = {
691
- "hybridly/vue": [
692
- "useProperty",
693
- "setProperty",
694
- "useRefinements",
695
- "useTable",
696
- "useBulkSelect",
697
- "useProperties",
698
- "useBackForward",
699
- "useContext",
700
- "useForm",
701
- "useDialog",
702
- "useHistoryState",
703
- "createPaginator",
704
- "registerHook",
705
- "useRoute",
706
- "useQueryParameter",
707
- "useQueryParameters"
708
- ],
709
- "hybridly": [
710
- "router",
711
- "route",
712
- "can",
713
- "getRouterContext"
714
- ]
715
- };
716
- //#endregion
717
704
  //#region src/index.ts
718
705
  async function plugin(options = {}) {
719
706
  const config = await loadConfiguration();