@hybridly/vite 0.5.6 → 0.6.0

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.cjs CHANGED
@@ -2,9 +2,12 @@
2
2
 
3
3
  Object.defineProperty(exports, '__esModule', { value: true });
4
4
 
5
- const laravel = require('laravel-vite-plugin');
6
- const path = require('node:path');
7
5
  const fs = require('node:fs');
6
+ const path = require('node:path');
7
+ const colors = require('picocolors');
8
+ const vite = require('vite');
9
+ require('node:url');
10
+ const os = require('node:os');
8
11
  const makeDebugger = require('debug');
9
12
  const localPkg = require('local-pkg');
10
13
  const node_child_process = require('node:child_process');
@@ -21,9 +24,10 @@ const vue = require('@vitejs/plugin-vue');
21
24
 
22
25
  function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e.default : e; }
23
26
 
24
- const laravel__default = /*#__PURE__*/_interopDefaultCompat(laravel);
25
- const path__default = /*#__PURE__*/_interopDefaultCompat(path);
26
27
  const fs__default = /*#__PURE__*/_interopDefaultCompat(fs);
28
+ const path__default = /*#__PURE__*/_interopDefaultCompat(path);
29
+ const colors__default = /*#__PURE__*/_interopDefaultCompat(colors);
30
+ const os__default = /*#__PURE__*/_interopDefaultCompat(os);
27
31
  const makeDebugger__default = /*#__PURE__*/_interopDefaultCompat(makeDebugger);
28
32
  const MagicString__default = /*#__PURE__*/_interopDefaultCompat(MagicString);
29
33
  const run__default = /*#__PURE__*/_interopDefaultCompat(run);
@@ -33,6 +37,215 @@ const iconsResolver__default = /*#__PURE__*/_interopDefaultCompat(iconsResolver)
33
37
  const icons__default = /*#__PURE__*/_interopDefaultCompat(icons);
34
38
  const vue__default = /*#__PURE__*/_interopDefaultCompat(vue);
35
39
 
40
+ function isIpv6(address) {
41
+ return address.family === "IPv6" || address.family === 6;
42
+ }
43
+
44
+ function determineDevelopmentEnvironmentConfigPath() {
45
+ const herdConfigPath = path__default.resolve(os__default.homedir(), "Library", "Application Support", "Herd", "config", "valet");
46
+ if (fs__default.existsSync(herdConfigPath)) {
47
+ return herdConfigPath;
48
+ }
49
+ return path__default.resolve(os__default.homedir(), ".config", "valet");
50
+ }
51
+ function resolveDevelopmentEnvironmentHost(configPath) {
52
+ const configFile = path__default.resolve(configPath, "config.json");
53
+ if (!fs__default.existsSync(configFile)) {
54
+ throw new Error(`Unable to find the configuration file [${configFile}]. You will need to manually specify the host in the \`detectTls\` configuration option.`);
55
+ }
56
+ const config = JSON.parse(fs__default.readFileSync(configFile, "utf-8"));
57
+ return `${path__default.basename(process.cwd())}.${config.tld}`;
58
+ }
59
+ function resolveDevelopmentEnvironmentServerConfig() {
60
+ const configPath = determineDevelopmentEnvironmentConfigPath();
61
+ const host = resolveDevelopmentEnvironmentHost(configPath);
62
+ const keyPath = path__default.resolve(configPath, "Certificates", `${host}.key`);
63
+ const certPath = path__default.resolve(configPath, "Certificates", `${host}.crt`);
64
+ if (!fs__default.existsSync(keyPath) || !fs__default.existsSync(certPath)) {
65
+ return;
66
+ }
67
+ return {
68
+ hmr: { host },
69
+ host,
70
+ https: {
71
+ key: fs__default.readFileSync(keyPath),
72
+ cert: fs__default.readFileSync(certPath)
73
+ }
74
+ };
75
+ }
76
+ function resolveEnvironmentServerConfig(env) {
77
+ if (!env.VITE_DEV_SERVER_KEY && !env.VITE_DEV_SERVER_CERT) {
78
+ return;
79
+ }
80
+ if (!fs__default.existsSync(env.VITE_DEV_SERVER_KEY) || !fs__default.existsSync(env.VITE_DEV_SERVER_CERT)) {
81
+ 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}].`);
82
+ }
83
+ const host = resolveHostFromEnv(env);
84
+ return {
85
+ hmr: { host },
86
+ host,
87
+ https: {
88
+ key: fs__default.readFileSync(env.VITE_DEV_SERVER_KEY),
89
+ cert: fs__default.readFileSync(env.VITE_DEV_SERVER_CERT)
90
+ }
91
+ };
92
+ }
93
+ function resolveHostFromEnv(env) {
94
+ if (env.VITE_DEV_SERVER_KEY) {
95
+ return env.VITE_DEV_SERVER_KEY;
96
+ }
97
+ try {
98
+ return new URL(env.APP_URL).host;
99
+ } catch {
100
+ throw new Error(`Unable to determine the host from the environment's APP_URL: [${env.APP_URL}].`);
101
+ }
102
+ }
103
+
104
+ let exitHandlersBound = false;
105
+ function laravel(options, hybridlyConfig) {
106
+ let viteDevServerUrl;
107
+ let resolvedConfig;
108
+ let userConfig;
109
+ const publicDirectory = "public";
110
+ const buildDirectory = "build";
111
+ const hotFile = path__default.join(publicDirectory, "hot");
112
+ return {
113
+ name: "hybridly:laravel",
114
+ enforce: "post",
115
+ config: (config, { command, mode }) => {
116
+ userConfig = config;
117
+ const ssr = !!userConfig.build?.ssr;
118
+ const env = vite.loadEnv(mode, userConfig.envDir || process.cwd(), "");
119
+ const assetUrl = env.ASSET_URL ?? "";
120
+ const base = `${assetUrl + (!assetUrl.endsWith("/") ? "/" : "") + buildDirectory}/`;
121
+ const serverConfig = command === "serve" ? resolveEnvironmentServerConfig(env) ?? resolveDevelopmentEnvironmentServerConfig() : void 0;
122
+ ensureCommandShouldRunInEnvironment(command, env);
123
+ return {
124
+ base: userConfig.base ?? (command === "build" ? base : ""),
125
+ publicDir: userConfig.publicDir ?? false,
126
+ build: {
127
+ manifest: ssr === true ? false : userConfig.build?.manifest ?? "manifest.json",
128
+ outDir: userConfig.build?.outDir ?? path__default.join(publicDirectory, buildDirectory),
129
+ rollupOptions: {
130
+ input: resolveInput(config, hybridlyConfig)
131
+ },
132
+ assetsInlineLimit: userConfig.build?.assetsInlineLimit ?? 0
133
+ },
134
+ server: {
135
+ origin: userConfig.server?.origin ?? "__laravel_vite_placeholder__",
136
+ ...process.env.LARAVEL_SAIL ? {
137
+ host: userConfig.server?.host ?? "0.0.0.0",
138
+ port: userConfig.server?.port ?? (env.VITE_PORT ? parseInt(env.VITE_PORT) : 5173),
139
+ strictPort: userConfig.server?.strictPort ?? true
140
+ } : void 0,
141
+ ...serverConfig ? {
142
+ host: userConfig.server?.host ?? serverConfig.host,
143
+ hmr: userConfig.server?.hmr === false ? false : {
144
+ ...serverConfig.hmr,
145
+ ...userConfig.server?.hmr === true ? {} : userConfig.server?.hmr
146
+ },
147
+ https: userConfig.server?.https ?? serverConfig.https
148
+ } : void 0
149
+ }
150
+ };
151
+ },
152
+ configResolved(config) {
153
+ resolvedConfig = config;
154
+ },
155
+ transform(code) {
156
+ if (resolvedConfig.command === "serve") {
157
+ return code.replace(/__laravel_vite_placeholder__/g, viteDevServerUrl);
158
+ }
159
+ },
160
+ configureServer(server) {
161
+ const envDir = resolvedConfig.envDir || process.cwd();
162
+ const appUrl = vite.loadEnv(resolvedConfig.mode, envDir, "APP_URL").APP_URL ?? "undefined";
163
+ server.httpServer?.once("listening", () => {
164
+ const address = server.httpServer?.address();
165
+ const isAddressInfo = (x) => typeof x === "object";
166
+ if (isAddressInfo(address)) {
167
+ viteDevServerUrl = resolveDevServerUrl(address, server.config, userConfig);
168
+ fs__default.writeFileSync(hotFile, viteDevServerUrl);
169
+ if (!hybridlyConfig.versions) {
170
+ return;
171
+ }
172
+ let registered = `${colors__default.bold(hybridlyConfig.components.views.length)} ${colors__default.dim("views")}, `;
173
+ registered += `${colors__default.bold(hybridlyConfig.components.components.length)} ${colors__default.dim("components")}, `;
174
+ registered += `${colors__default.bold(hybridlyConfig.components.layouts.length)} ${colors__default.dim("layouts")}, `;
175
+ registered += `${colors__default.bold(hybridlyConfig.components.directories.length)} ${colors__default.dim("directories")}`;
176
+ const latest = hybridlyConfig.versions.is_latest ? "" : colors__default.dim(`(${colors__default.yellow(`${hybridlyConfig.versions.latest} is available`)})`);
177
+ let version = `${colors__default.yellow(`v${hybridlyConfig.versions.composer}`)} ${colors__default.dim("(composer)")}, `;
178
+ version += `${colors__default.yellow(`v${hybridlyConfig.versions.npm}`)} ${colors__default.dim("(npm)")}`;
179
+ version += ` \u2014 ${colors__default.yellow("this may lead to undefined behavior")}`;
180
+ setTimeout(() => {
181
+ server.config.logger.info(`
182
+ ${colors__default.magenta(`${colors__default.bold("HYBRIDLY")} v${hybridlyConfig.versions.composer}`)} ${latest}`);
183
+ server.config.logger.info("");
184
+ server.config.logger.info(` ${colors__default.green("\u279C")} ${colors__default.bold("URL")}: ${colors__default.cyan(hybridlyConfig.routing.url)}`);
185
+ server.config.logger.info(` ${colors__default.green("\u279C")} ${colors__default.bold("Registered")}: ${registered}`);
186
+ if (hybridlyConfig.versions.composer !== hybridlyConfig.versions.npm) {
187
+ server.config.logger.info(` ${colors__default.yellow("\u279C")} ${colors__default.bold("Version mismatch")}: ${version}`);
188
+ }
189
+ }, 100);
190
+ }
191
+ });
192
+ if (!exitHandlersBound) {
193
+ let clean = function() {
194
+ if (fs__default.existsSync(hotFile)) {
195
+ fs__default.rmSync(hotFile);
196
+ }
197
+ };
198
+ process.on("exit", clean);
199
+ process.on("SIGINT", () => process.exit());
200
+ process.on("SIGTERM", () => process.exit());
201
+ process.on("SIGHUP", () => process.exit());
202
+ exitHandlersBound = true;
203
+ }
204
+ return () => server.middlewares.use((req, res, next) => {
205
+ if (req.url === "/index.html") {
206
+ res.writeHead(302, { Location: appUrl });
207
+ res.end();
208
+ }
209
+ next();
210
+ });
211
+ }
212
+ };
213
+ }
214
+ function ensureCommandShouldRunInEnvironment(command, env) {
215
+ if (command === "build" || env.LARAVEL_BYPASS_ENV_CHECK === "1") {
216
+ return;
217
+ }
218
+ if (typeof env.LARAVEL_VAPOR !== "undefined") {
219
+ 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");
220
+ }
221
+ if (typeof env.LARAVEL_FORGE !== "undefined") {
222
+ 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");
223
+ }
224
+ if (typeof env.LARAVEL_ENVOYER !== "undefined") {
225
+ 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");
226
+ }
227
+ if (typeof env.CI !== "undefined") {
228
+ 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");
229
+ }
230
+ }
231
+ function resolveInput(userConfig, hybridlyConfig, ssr) {
232
+ return userConfig.build?.rollupOptions?.input ?? hybridlyConfig.architecture.application_main_path;
233
+ }
234
+ function resolveDevServerUrl(address, config, userConfig) {
235
+ const configHmrProtocol = typeof config.server.hmr === "object" ? config.server.hmr.protocol : null;
236
+ const clientProtocol = configHmrProtocol ? configHmrProtocol === "wss" ? "https" : "http" : null;
237
+ const serverProtocol = config.server.https ? "https" : "http";
238
+ const protocol = clientProtocol ?? serverProtocol;
239
+ const configHmrHost = typeof config.server.hmr === "object" ? config.server.hmr.host : null;
240
+ const configHost = typeof config.server.host === "string" ? config.server.host : null;
241
+ const sailHost = process.env.LARAVEL_SAIL && !userConfig.server?.host ? "localhost" : null;
242
+ const serverAddress = isIpv6(address) ? `[${address.address}]` : address.address;
243
+ const host = configHmrHost ?? sailHost ?? configHost ?? serverAddress;
244
+ const configHmrClientPort = typeof config.server.hmr === "object" ? config.server.hmr.clientPort : null;
245
+ const port = configHmrClientPort ?? address.port;
246
+ return `${protocol}://${host}:${port}`;
247
+ }
248
+
36
249
  const LAYOUT_PLUGIN_NAME = "vite:hybridly:layout";
37
250
  const CONFIG_PLUGIN_NAME = "vite:hybridly:config";
38
251
  const CONFIG_VIRTUAL_MODULE_ID = "virtual:hybridly/config";
@@ -45,6 +258,14 @@ const debug = {
45
258
  function isPackageInstalled(name, paths = [process.cwd()]) {
46
259
  return localPkg.isPackageExists(name, { paths });
47
260
  }
261
+ function importPackage(name, paths = [process.cwd()]) {
262
+ const mod = localPkg.resolveModule(name, { paths });
263
+ if (!mod) {
264
+ console.warn(`Could not resolve package [${name}]`);
265
+ return;
266
+ }
267
+ return localPkg.importModule(mod);
268
+ }
48
269
  function toKebabCase(key) {
49
270
  const result = key.replace(/([A-Z])/g, " $1").trim();
50
271
  return result.split(" ").join("-").toLowerCase();
@@ -55,7 +276,7 @@ function generateTsConfig(options, config) {
55
276
  compilerOptions: {
56
277
  target: "esnext",
57
278
  module: "esnext",
58
- moduleResolution: "node",
279
+ moduleResolution: "bundler",
59
280
  strict: true,
60
281
  jsx: "preserve",
61
282
  sourceMap: true,
@@ -81,7 +302,7 @@ function generateTsConfig(options, config) {
81
302
  "./*"
82
303
  ],
83
304
  "@/*": [
84
- `./${config.architecture.root}/*`
305
+ `./${config.architecture.root_directory}/*`
85
306
  ]
86
307
  }
87
308
  },
@@ -89,7 +310,7 @@ function generateTsConfig(options, config) {
89
310
  ...config.components.views.map(({ path: path2 }) => `../${path2}`),
90
311
  ...config.components.layouts.map(({ path: path2 }) => `../${path2}`),
91
312
  ...config.components.components.map(({ path: path2 }) => `../${path2}`),
92
- `../${config.architecture.root}/**/*`,
313
+ `../${config.architecture.root_directory}/**/*`,
93
314
  "../app/**/*",
94
315
  "../src/**/*",
95
316
  "./php-types.d.ts",
@@ -101,8 +322,6 @@ function generateTsConfig(options, config) {
101
322
  ],
102
323
  exclude: [
103
324
  "../public/**/*",
104
- "../node_modules",
105
- "../vendor",
106
325
  ...options.tsconfig?.exclude ?? []
107
326
  ]
108
327
  };
@@ -181,7 +400,7 @@ async function loadConfiguration(options) {
181
400
  }
182
401
  }
183
402
 
184
- function getClientCode(config) {
403
+ function getClientCode$1(config) {
185
404
  const paths = config.components.views.map(({ path }) => `"~/${path}"`).join(",");
186
405
  return `
187
406
  import { initializeHybridly as init } from 'hybridly/vue'
@@ -207,7 +426,7 @@ const initialize = (options, config) => {
207
426
  return {
208
427
  resolve: {
209
428
  alias: {
210
- "@": path__default.join(process.cwd(), config.architecture.root),
429
+ "@": path__default.join(process.cwd(), config.architecture.root_directory),
211
430
  "#": path__default.join(process.cwd(), ".hybridly"),
212
431
  "~": path__default.join(process.cwd())
213
432
  }
@@ -253,7 +472,7 @@ const initialize = (options, config) => {
253
472
  },
254
473
  async load(id) {
255
474
  if (id === RESOLVED_CONFIG_VIRTUAL_MODULE_ID) {
256
- return getClientCode(config);
475
+ return getClientCode$1(config);
257
476
  }
258
477
  },
259
478
  // Denies HMR for `.hybridly` content, it causes unwanted reloads
@@ -347,13 +566,6 @@ function getRunOptions(options) {
347
566
  ];
348
567
  }
349
568
 
350
- function getLaravelOptions(options, config) {
351
- return {
352
- input: `${config.architecture.root}/application/main.ts`,
353
- ...options.laravel ?? {}
354
- };
355
- }
356
-
357
569
  const HybridlyImports = {
358
570
  "hybridly/vue": [
359
571
  "useProperty",
@@ -402,8 +614,8 @@ function getAutoImportsOptions(options, config) {
402
614
  vueTemplate: true,
403
615
  dts: ".hybridly/auto-imports.d.ts",
404
616
  dirs: [
405
- `${config.architecture.root}/utils`,
406
- `${config.architecture.root}/composables`,
617
+ `${config.architecture.root_directory}/utils`,
618
+ `${config.architecture.root_directory}/composables`,
407
619
  ...config.components.directories.map((directory) => `${directory}/**/*.ts`)
408
620
  ],
409
621
  imports: [
@@ -419,21 +631,7 @@ function getAutoImportsOptions(options, config) {
419
631
  );
420
632
  }
421
633
 
422
- function HybridlyResolver(linkName = "RouterLink") {
423
- return {
424
- type: "component",
425
- resolve: (name) => {
426
- if (name === linkName) {
427
- return {
428
- from: "hybridly/vue",
429
- name: "RouterLink",
430
- as: linkName
431
- };
432
- }
433
- }
434
- };
435
- }
436
- function getVueComponentsOptions(options, config) {
634
+ async function getVueComponentsOptions(options, config) {
437
635
  if (options.vueComponents === false) {
438
636
  return {};
439
637
  }
@@ -441,16 +639,18 @@ function getVueComponentsOptions(options, config) {
441
639
  const customCollections = Array.isArray(options.customIcons) ? options.customIcons : options.customIcons?.collections ?? [];
442
640
  const overrideResolvers = options.overrideResolvers ? Array.isArray(options.overrideResolvers) ? options.overrideResolvers : [options.overrideResolvers] : false;
443
641
  const hasHeadlessUI = isPackageInstalled("@headlessui/vue");
642
+ const hasRadix = isPackageInstalled("radix-vue");
444
643
  return utils.merge(
445
644
  {
446
645
  dirs: [
447
- `./${config.architecture.root}/components`
646
+ `./${config.architecture.root_directory}/${config.architecture.components_directory}`
448
647
  ],
449
648
  directoryAsNamespace: true,
450
649
  dts: ".hybridly/components.d.ts",
451
650
  resolvers: overrideResolvers || [
452
651
  ...hasIcons ? [iconsResolver__default({ customCollections })] : [],
453
652
  ...hasHeadlessUI ? [resolvers.HeadlessUiResolver({ prefix: options?.vueComponents?.headlessUiPrefix ?? "Headless" })] : [],
653
+ ...hasRadix ? [await RadixResolver(options?.vueComponents?.radixPrefix)] : [],
454
654
  ProvidedComponentListResolver(config),
455
655
  HybridlyResolver(options.vueComponents?.linkName)
456
656
  ]
@@ -459,6 +659,24 @@ function getVueComponentsOptions(options, config) {
459
659
  { overwriteArray: false }
460
660
  );
461
661
  }
662
+ async function RadixResolver(prefix = "Radix") {
663
+ const radix = await importPackage("radix-vue/resolver");
664
+ return radix.default({ prefix });
665
+ }
666
+ function HybridlyResolver(linkName = "RouterLink") {
667
+ return {
668
+ type: "component",
669
+ resolve: (name) => {
670
+ if (name === linkName) {
671
+ return {
672
+ from: "hybridly/vue",
673
+ name: "RouterLink",
674
+ as: linkName
675
+ };
676
+ }
677
+ }
678
+ };
679
+ }
462
680
  function ProvidedComponentListResolver(config) {
463
681
  function resolveComponentPath(name) {
464
682
  const kebabName = toKebabCase(name);
@@ -485,7 +703,7 @@ function getIconsOptions(options, config) {
485
703
  const customIconDirectoryName = resolved?.icons ?? "icons";
486
704
  const customCollections = Object.fromEntries(resolved?.collections?.map((collection) => [
487
705
  collection,
488
- loaders.FileSystemIconLoader(`./${config.architecture.root}/${customIconDirectoryName}/${collection}`)
706
+ loaders.FileSystemIconLoader(`./${config.architecture.root_directory}/${customIconDirectoryName}/${collection}`)
489
707
  ]) ?? []);
490
708
  return {
491
709
  autoInstall: true,
@@ -548,18 +766,121 @@ function killSwitch() {
548
766
  };
549
767
  }
550
768
 
769
+ function getClientCode() {
770
+ const style = `
771
+ .local-build {
772
+ position: fixed;
773
+ bottom: 1rem;
774
+ left: 1rem;
775
+ z-index: 50;
776
+ display: inline-flex;
777
+ max-width: 26rem;
778
+ align-items: center;
779
+ background-color: rgba(0, 0, 0, 0.9);
780
+ padding: 0.75rem;
781
+ font-size: 0.75rem;
782
+ color: #8C8C8C;
783
+ transition: opacity 0.3s;
784
+ }
785
+
786
+ .local-build:hover {
787
+ opacity: 0.1;
788
+ }
789
+
790
+ .local-build .icon {
791
+ margin-right: 0.5rem;
792
+ height: 1.25rem;
793
+ width: 1.25rem;
794
+ fill: currentColor;
795
+ }
796
+
797
+ .local-build .content {
798
+ display: inline-flex;
799
+ flex-direction: column;
800
+ gap: 0.5rem;
801
+ }
802
+
803
+ .local-build .title {
804
+ font-weight: 500;
805
+ }
806
+ `;
807
+ const html = `
808
+ <div class="local-build">
809
+ <svg viewBox="0 0 24 24" width="1.2em" height="1.2em" class="icon"><path fill="currentColor" d="M11 15h2v2h-2zm0-8h2v6h-2zm1-5C6.47 2 2 6.5 2 12a10 10 0 0 0 10 10a10 10 0 0 0 10-10A10 10 0 0 0 12 2m0 18a8 8 0 0 1-8-8a8 8 0 0 1 8-8a8 8 0 0 1 8 8a8 8 0 0 1-8 8"></path></svg>
810
+ <span class="content">
811
+ <span class="title">This is a local production build. Changes will not be reflected.</span>
812
+ </span>
813
+ </div>
814
+ `;
815
+ return `
816
+ ;(function() {
817
+ const style = document.createElement('style')
818
+ style.innerHTML = \`${style}\`
819
+ document.head.appendChild(style)
820
+
821
+ const html = document.createElement('div')
822
+ html.innerHTML = \`${html}\`
823
+ document.body.appendChild(html)
824
+ html.addEventListener('click', () => html.remove())
825
+ })()
826
+ `;
827
+ }
828
+
829
+ const LOCAL_BUILD_VIRTUAL_ID = "virtual:hybridly/local-build";
830
+ const RESOLVED_LOCAL_BUILD_VIRTUAL_ID = `\0${LOCAL_BUILD_VIRTUAL_ID}`;
831
+ function warnOnLocalBuilds() {
832
+ let shouldDisplayWarning = false;
833
+ return {
834
+ name: "vite:hybridly:local-build",
835
+ enforce: "pre",
836
+ apply: "build",
837
+ config(config, { mode }) {
838
+ const env = vite.loadEnv(mode, config.envDir ?? process.cwd(), "");
839
+ shouldDisplayWarning = env.APP_ENV === "local";
840
+ },
841
+ async resolveId(id) {
842
+ if (!shouldDisplayWarning) {
843
+ return;
844
+ }
845
+ if (id === LOCAL_BUILD_VIRTUAL_ID) {
846
+ return RESOLVED_LOCAL_BUILD_VIRTUAL_ID;
847
+ }
848
+ },
849
+ async load(id) {
850
+ if (!shouldDisplayWarning) {
851
+ return;
852
+ }
853
+ if (id === RESOLVED_LOCAL_BUILD_VIRTUAL_ID) {
854
+ return getClientCode();
855
+ }
856
+ },
857
+ transform(code, id) {
858
+ if (!shouldDisplayWarning) {
859
+ return;
860
+ }
861
+ if (!id.endsWith(CONFIG_VIRTUAL_MODULE_ID)) {
862
+ return;
863
+ }
864
+ code = `${code}
865
+ import '${LOCAL_BUILD_VIRTUAL_ID}'`;
866
+ return code;
867
+ }
868
+ };
869
+ }
870
+
551
871
  async function plugin(options = {}) {
552
872
  const config = await loadConfiguration(options);
553
873
  return [
554
874
  initialize(options, config),
555
875
  layout(options, config),
556
- options.laravel !== false && laravel__default(getLaravelOptions(options, config)),
876
+ options.laravel !== false && laravel(options, config),
557
877
  options.run !== false && run__default(getRunOptions(options)),
558
- options.vueComponents !== false && vueComponents__default(getVueComponentsOptions(options, config)),
878
+ options.vueComponents !== false && vueComponents__default(await getVueComponentsOptions(options, config)),
559
879
  options.autoImports !== false && autoimport__default(getAutoImportsOptions(options, config)),
560
880
  options.icons !== false && icons__default(getIconsOptions(options, config)),
561
881
  options.vue !== false && vue__default(getVueOptions(options)),
562
- options.killSwitch !== false && killSwitch()
882
+ options.killSwitch !== false && killSwitch(),
883
+ options.warnOnLocalBuilds !== false && warnOnLocalBuilds()
563
884
  ];
564
885
  }
565
886
 
package/dist/index.d.cts CHANGED
@@ -2,7 +2,6 @@ import { Plugin } from 'vite';
2
2
  import { DynamicConfiguration } from '@hybridly/core';
3
3
  import autoimport from 'unplugin-auto-import/vite';
4
4
  import icons from 'unplugin-icons/vite';
5
- import laravel from 'laravel-vite-plugin';
6
5
  import { Runner } from 'vite-plugin-run';
7
6
  import vue from '@vitejs/plugin-vue';
8
7
  import vueComponents from 'unplugin-vue-components/vite';
@@ -22,8 +21,6 @@ type CustomIconOptions = string[] | {
22
21
  collections?: string[];
23
22
  };
24
23
 
25
- type LaravelOptions = Exclude<Parameters<typeof laravel>[0], string | string[]>;
26
-
27
24
  type VueOptions = Parameters<typeof vue>[0];
28
25
 
29
26
  type VueComponentsOptions = Parameters<typeof vueComponents>[0] & {
@@ -31,6 +28,8 @@ type VueComponentsOptions = Parameters<typeof vueComponents>[0] & {
31
28
  linkName?: string;
32
29
  /** Custom prefix for Headless UI components. */
33
30
  headlessUiPrefix?: string;
31
+ /** Custom prefix for Radix components. */
32
+ radixPrefix?: string;
34
33
  };
35
34
  type CustomResolvers = ComponentResolver | ComponentResolver[];
36
35
  type CustomComponentsOptions = VueComponentsOptions;
@@ -46,12 +45,12 @@ declare function HybridlyResolver(linkName?: string): {
46
45
  interface ViteOptions {
47
46
  /** Path to the PHP executable. */
48
47
  php?: string;
48
+ /** Disables the Laravel integration. Useful if you prefer to use the official one. */
49
+ laravel?: false;
49
50
  /** Options for the layout plugin. */
50
51
  layout?: LayoutOptions;
51
52
  /** Options for `@vitejs/plugin-vue`. */
52
53
  vue?: false | VueOptions;
53
- /** Options for `laravel-vite-plugin`. Set to `false` to disable. */
54
- laravel?: false | Partial<LaravelOptions>;
55
54
  /** Options for `vite-plugin-run`. Set to `false` to disable. */
56
55
  run?: false | Runner[];
57
56
  /** Options for `unplugin-auto-import`. Set to `false` to disable. */
@@ -70,6 +69,8 @@ interface ViteOptions {
70
69
  killSwitch?: boolean;
71
70
  /** Extra `tsconfig.json` options. */
72
71
  tsconfig?: TsConfigOptions;
72
+ /** Warns when displaying local builds. */
73
+ warnOnLocalBuilds?: boolean;
73
74
  }
74
75
  interface LayoutOptions {
75
76
  /** Custom RegExp for parsing the template string. */
package/dist/index.d.mts CHANGED
@@ -2,7 +2,6 @@ import { Plugin } from 'vite';
2
2
  import { DynamicConfiguration } from '@hybridly/core';
3
3
  import autoimport from 'unplugin-auto-import/vite';
4
4
  import icons from 'unplugin-icons/vite';
5
- import laravel from 'laravel-vite-plugin';
6
5
  import { Runner } from 'vite-plugin-run';
7
6
  import vue from '@vitejs/plugin-vue';
8
7
  import vueComponents from 'unplugin-vue-components/vite';
@@ -22,8 +21,6 @@ type CustomIconOptions = string[] | {
22
21
  collections?: string[];
23
22
  };
24
23
 
25
- type LaravelOptions = Exclude<Parameters<typeof laravel>[0], string | string[]>;
26
-
27
24
  type VueOptions = Parameters<typeof vue>[0];
28
25
 
29
26
  type VueComponentsOptions = Parameters<typeof vueComponents>[0] & {
@@ -31,6 +28,8 @@ type VueComponentsOptions = Parameters<typeof vueComponents>[0] & {
31
28
  linkName?: string;
32
29
  /** Custom prefix for Headless UI components. */
33
30
  headlessUiPrefix?: string;
31
+ /** Custom prefix for Radix components. */
32
+ radixPrefix?: string;
34
33
  };
35
34
  type CustomResolvers = ComponentResolver | ComponentResolver[];
36
35
  type CustomComponentsOptions = VueComponentsOptions;
@@ -46,12 +45,12 @@ declare function HybridlyResolver(linkName?: string): {
46
45
  interface ViteOptions {
47
46
  /** Path to the PHP executable. */
48
47
  php?: string;
48
+ /** Disables the Laravel integration. Useful if you prefer to use the official one. */
49
+ laravel?: false;
49
50
  /** Options for the layout plugin. */
50
51
  layout?: LayoutOptions;
51
52
  /** Options for `@vitejs/plugin-vue`. */
52
53
  vue?: false | VueOptions;
53
- /** Options for `laravel-vite-plugin`. Set to `false` to disable. */
54
- laravel?: false | Partial<LaravelOptions>;
55
54
  /** Options for `vite-plugin-run`. Set to `false` to disable. */
56
55
  run?: false | Runner[];
57
56
  /** Options for `unplugin-auto-import`. Set to `false` to disable. */
@@ -70,6 +69,8 @@ interface ViteOptions {
70
69
  killSwitch?: boolean;
71
70
  /** Extra `tsconfig.json` options. */
72
71
  tsconfig?: TsConfigOptions;
72
+ /** Warns when displaying local builds. */
73
+ warnOnLocalBuilds?: boolean;
73
74
  }
74
75
  interface LayoutOptions {
75
76
  /** Custom RegExp for parsing the template string. */
package/dist/index.d.ts CHANGED
@@ -2,7 +2,6 @@ import { Plugin } from 'vite';
2
2
  import { DynamicConfiguration } from '@hybridly/core';
3
3
  import autoimport from 'unplugin-auto-import/vite';
4
4
  import icons from 'unplugin-icons/vite';
5
- import laravel from 'laravel-vite-plugin';
6
5
  import { Runner } from 'vite-plugin-run';
7
6
  import vue from '@vitejs/plugin-vue';
8
7
  import vueComponents from 'unplugin-vue-components/vite';
@@ -22,8 +21,6 @@ type CustomIconOptions = string[] | {
22
21
  collections?: string[];
23
22
  };
24
23
 
25
- type LaravelOptions = Exclude<Parameters<typeof laravel>[0], string | string[]>;
26
-
27
24
  type VueOptions = Parameters<typeof vue>[0];
28
25
 
29
26
  type VueComponentsOptions = Parameters<typeof vueComponents>[0] & {
@@ -31,6 +28,8 @@ type VueComponentsOptions = Parameters<typeof vueComponents>[0] & {
31
28
  linkName?: string;
32
29
  /** Custom prefix for Headless UI components. */
33
30
  headlessUiPrefix?: string;
31
+ /** Custom prefix for Radix components. */
32
+ radixPrefix?: string;
34
33
  };
35
34
  type CustomResolvers = ComponentResolver | ComponentResolver[];
36
35
  type CustomComponentsOptions = VueComponentsOptions;
@@ -46,12 +45,12 @@ declare function HybridlyResolver(linkName?: string): {
46
45
  interface ViteOptions {
47
46
  /** Path to the PHP executable. */
48
47
  php?: string;
48
+ /** Disables the Laravel integration. Useful if you prefer to use the official one. */
49
+ laravel?: false;
49
50
  /** Options for the layout plugin. */
50
51
  layout?: LayoutOptions;
51
52
  /** Options for `@vitejs/plugin-vue`. */
52
53
  vue?: false | VueOptions;
53
- /** Options for `laravel-vite-plugin`. Set to `false` to disable. */
54
- laravel?: false | Partial<LaravelOptions>;
55
54
  /** Options for `vite-plugin-run`. Set to `false` to disable. */
56
55
  run?: false | Runner[];
57
56
  /** Options for `unplugin-auto-import`. Set to `false` to disable. */
@@ -70,6 +69,8 @@ interface ViteOptions {
70
69
  killSwitch?: boolean;
71
70
  /** Extra `tsconfig.json` options. */
72
71
  tsconfig?: TsConfigOptions;
72
+ /** Warns when displaying local builds. */
73
+ warnOnLocalBuilds?: boolean;
73
74
  }
74
75
  interface LayoutOptions {
75
76
  /** Custom RegExp for parsing the template string. */
package/dist/index.mjs CHANGED
@@ -1,8 +1,11 @@
1
- import laravel from 'laravel-vite-plugin';
2
- import path from 'node:path';
3
1
  import fs from 'node:fs';
2
+ import path from 'node:path';
3
+ import colors from 'picocolors';
4
+ import { loadEnv } from 'vite';
5
+ import 'node:url';
6
+ import os from 'node:os';
4
7
  import makeDebugger from 'debug';
5
- import { isPackageExists } from 'local-pkg';
8
+ import { isPackageExists, resolveModule, importModule } from 'local-pkg';
6
9
  import { execSync } from 'node:child_process';
7
10
  import MagicString from 'magic-string';
8
11
  import run from 'vite-plugin-run';
@@ -15,6 +18,215 @@ import icons from 'unplugin-icons/vite';
15
18
  import { FileSystemIconLoader } from 'unplugin-icons/loaders';
16
19
  import vue from '@vitejs/plugin-vue';
17
20
 
21
+ function isIpv6(address) {
22
+ return address.family === "IPv6" || address.family === 6;
23
+ }
24
+
25
+ function determineDevelopmentEnvironmentConfigPath() {
26
+ const herdConfigPath = path.resolve(os.homedir(), "Library", "Application Support", "Herd", "config", "valet");
27
+ if (fs.existsSync(herdConfigPath)) {
28
+ return herdConfigPath;
29
+ }
30
+ return path.resolve(os.homedir(), ".config", "valet");
31
+ }
32
+ function resolveDevelopmentEnvironmentHost(configPath) {
33
+ const configFile = path.resolve(configPath, "config.json");
34
+ if (!fs.existsSync(configFile)) {
35
+ throw new Error(`Unable to find the configuration file [${configFile}]. You will need to manually specify the host in the \`detectTls\` configuration option.`);
36
+ }
37
+ const config = JSON.parse(fs.readFileSync(configFile, "utf-8"));
38
+ return `${path.basename(process.cwd())}.${config.tld}`;
39
+ }
40
+ function resolveDevelopmentEnvironmentServerConfig() {
41
+ const configPath = determineDevelopmentEnvironmentConfigPath();
42
+ const host = resolveDevelopmentEnvironmentHost(configPath);
43
+ const keyPath = path.resolve(configPath, "Certificates", `${host}.key`);
44
+ const certPath = path.resolve(configPath, "Certificates", `${host}.crt`);
45
+ if (!fs.existsSync(keyPath) || !fs.existsSync(certPath)) {
46
+ return;
47
+ }
48
+ return {
49
+ hmr: { host },
50
+ host,
51
+ https: {
52
+ key: fs.readFileSync(keyPath),
53
+ cert: fs.readFileSync(certPath)
54
+ }
55
+ };
56
+ }
57
+ function resolveEnvironmentServerConfig(env) {
58
+ if (!env.VITE_DEV_SERVER_KEY && !env.VITE_DEV_SERVER_CERT) {
59
+ return;
60
+ }
61
+ if (!fs.existsSync(env.VITE_DEV_SERVER_KEY) || !fs.existsSync(env.VITE_DEV_SERVER_CERT)) {
62
+ 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}].`);
63
+ }
64
+ const host = resolveHostFromEnv(env);
65
+ return {
66
+ hmr: { host },
67
+ host,
68
+ https: {
69
+ key: fs.readFileSync(env.VITE_DEV_SERVER_KEY),
70
+ cert: fs.readFileSync(env.VITE_DEV_SERVER_CERT)
71
+ }
72
+ };
73
+ }
74
+ function resolveHostFromEnv(env) {
75
+ if (env.VITE_DEV_SERVER_KEY) {
76
+ return env.VITE_DEV_SERVER_KEY;
77
+ }
78
+ try {
79
+ return new URL(env.APP_URL).host;
80
+ } catch {
81
+ throw new Error(`Unable to determine the host from the environment's APP_URL: [${env.APP_URL}].`);
82
+ }
83
+ }
84
+
85
+ let exitHandlersBound = false;
86
+ function laravel(options, hybridlyConfig) {
87
+ let viteDevServerUrl;
88
+ let resolvedConfig;
89
+ let userConfig;
90
+ const publicDirectory = "public";
91
+ const buildDirectory = "build";
92
+ const hotFile = path.join(publicDirectory, "hot");
93
+ return {
94
+ name: "hybridly:laravel",
95
+ enforce: "post",
96
+ config: (config, { command, mode }) => {
97
+ userConfig = config;
98
+ const ssr = !!userConfig.build?.ssr;
99
+ const env = loadEnv(mode, userConfig.envDir || process.cwd(), "");
100
+ const assetUrl = env.ASSET_URL ?? "";
101
+ const base = `${assetUrl + (!assetUrl.endsWith("/") ? "/" : "") + buildDirectory}/`;
102
+ const serverConfig = command === "serve" ? resolveEnvironmentServerConfig(env) ?? resolveDevelopmentEnvironmentServerConfig() : void 0;
103
+ ensureCommandShouldRunInEnvironment(command, env);
104
+ return {
105
+ base: userConfig.base ?? (command === "build" ? base : ""),
106
+ publicDir: userConfig.publicDir ?? false,
107
+ build: {
108
+ manifest: ssr === true ? false : userConfig.build?.manifest ?? "manifest.json",
109
+ outDir: userConfig.build?.outDir ?? path.join(publicDirectory, buildDirectory),
110
+ rollupOptions: {
111
+ input: resolveInput(config, hybridlyConfig)
112
+ },
113
+ assetsInlineLimit: userConfig.build?.assetsInlineLimit ?? 0
114
+ },
115
+ server: {
116
+ origin: userConfig.server?.origin ?? "__laravel_vite_placeholder__",
117
+ ...process.env.LARAVEL_SAIL ? {
118
+ host: userConfig.server?.host ?? "0.0.0.0",
119
+ port: userConfig.server?.port ?? (env.VITE_PORT ? parseInt(env.VITE_PORT) : 5173),
120
+ strictPort: userConfig.server?.strictPort ?? true
121
+ } : void 0,
122
+ ...serverConfig ? {
123
+ host: userConfig.server?.host ?? serverConfig.host,
124
+ hmr: userConfig.server?.hmr === false ? false : {
125
+ ...serverConfig.hmr,
126
+ ...userConfig.server?.hmr === true ? {} : userConfig.server?.hmr
127
+ },
128
+ https: userConfig.server?.https ?? serverConfig.https
129
+ } : void 0
130
+ }
131
+ };
132
+ },
133
+ configResolved(config) {
134
+ resolvedConfig = config;
135
+ },
136
+ transform(code) {
137
+ if (resolvedConfig.command === "serve") {
138
+ return code.replace(/__laravel_vite_placeholder__/g, viteDevServerUrl);
139
+ }
140
+ },
141
+ configureServer(server) {
142
+ const envDir = resolvedConfig.envDir || process.cwd();
143
+ const appUrl = loadEnv(resolvedConfig.mode, envDir, "APP_URL").APP_URL ?? "undefined";
144
+ server.httpServer?.once("listening", () => {
145
+ const address = server.httpServer?.address();
146
+ const isAddressInfo = (x) => typeof x === "object";
147
+ if (isAddressInfo(address)) {
148
+ viteDevServerUrl = resolveDevServerUrl(address, server.config, userConfig);
149
+ fs.writeFileSync(hotFile, viteDevServerUrl);
150
+ if (!hybridlyConfig.versions) {
151
+ return;
152
+ }
153
+ let registered = `${colors.bold(hybridlyConfig.components.views.length)} ${colors.dim("views")}, `;
154
+ registered += `${colors.bold(hybridlyConfig.components.components.length)} ${colors.dim("components")}, `;
155
+ registered += `${colors.bold(hybridlyConfig.components.layouts.length)} ${colors.dim("layouts")}, `;
156
+ registered += `${colors.bold(hybridlyConfig.components.directories.length)} ${colors.dim("directories")}`;
157
+ const latest = hybridlyConfig.versions.is_latest ? "" : colors.dim(`(${colors.yellow(`${hybridlyConfig.versions.latest} is available`)})`);
158
+ let version = `${colors.yellow(`v${hybridlyConfig.versions.composer}`)} ${colors.dim("(composer)")}, `;
159
+ version += `${colors.yellow(`v${hybridlyConfig.versions.npm}`)} ${colors.dim("(npm)")}`;
160
+ version += ` \u2014 ${colors.yellow("this may lead to undefined behavior")}`;
161
+ setTimeout(() => {
162
+ server.config.logger.info(`
163
+ ${colors.magenta(`${colors.bold("HYBRIDLY")} v${hybridlyConfig.versions.composer}`)} ${latest}`);
164
+ server.config.logger.info("");
165
+ server.config.logger.info(` ${colors.green("\u279C")} ${colors.bold("URL")}: ${colors.cyan(hybridlyConfig.routing.url)}`);
166
+ server.config.logger.info(` ${colors.green("\u279C")} ${colors.bold("Registered")}: ${registered}`);
167
+ if (hybridlyConfig.versions.composer !== hybridlyConfig.versions.npm) {
168
+ server.config.logger.info(` ${colors.yellow("\u279C")} ${colors.bold("Version mismatch")}: ${version}`);
169
+ }
170
+ }, 100);
171
+ }
172
+ });
173
+ if (!exitHandlersBound) {
174
+ let clean = function() {
175
+ if (fs.existsSync(hotFile)) {
176
+ fs.rmSync(hotFile);
177
+ }
178
+ };
179
+ process.on("exit", clean);
180
+ process.on("SIGINT", () => process.exit());
181
+ process.on("SIGTERM", () => process.exit());
182
+ process.on("SIGHUP", () => process.exit());
183
+ exitHandlersBound = true;
184
+ }
185
+ return () => server.middlewares.use((req, res, next) => {
186
+ if (req.url === "/index.html") {
187
+ res.writeHead(302, { Location: appUrl });
188
+ res.end();
189
+ }
190
+ next();
191
+ });
192
+ }
193
+ };
194
+ }
195
+ function ensureCommandShouldRunInEnvironment(command, env) {
196
+ if (command === "build" || env.LARAVEL_BYPASS_ENV_CHECK === "1") {
197
+ return;
198
+ }
199
+ if (typeof env.LARAVEL_VAPOR !== "undefined") {
200
+ 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");
201
+ }
202
+ if (typeof env.LARAVEL_FORGE !== "undefined") {
203
+ 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");
204
+ }
205
+ if (typeof env.LARAVEL_ENVOYER !== "undefined") {
206
+ 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");
207
+ }
208
+ if (typeof env.CI !== "undefined") {
209
+ 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");
210
+ }
211
+ }
212
+ function resolveInput(userConfig, hybridlyConfig, ssr) {
213
+ return userConfig.build?.rollupOptions?.input ?? hybridlyConfig.architecture.application_main_path;
214
+ }
215
+ function resolveDevServerUrl(address, config, userConfig) {
216
+ const configHmrProtocol = typeof config.server.hmr === "object" ? config.server.hmr.protocol : null;
217
+ const clientProtocol = configHmrProtocol ? configHmrProtocol === "wss" ? "https" : "http" : null;
218
+ const serverProtocol = config.server.https ? "https" : "http";
219
+ const protocol = clientProtocol ?? serverProtocol;
220
+ const configHmrHost = typeof config.server.hmr === "object" ? config.server.hmr.host : null;
221
+ const configHost = typeof config.server.host === "string" ? config.server.host : null;
222
+ const sailHost = process.env.LARAVEL_SAIL && !userConfig.server?.host ? "localhost" : null;
223
+ const serverAddress = isIpv6(address) ? `[${address.address}]` : address.address;
224
+ const host = configHmrHost ?? sailHost ?? configHost ?? serverAddress;
225
+ const configHmrClientPort = typeof config.server.hmr === "object" ? config.server.hmr.clientPort : null;
226
+ const port = configHmrClientPort ?? address.port;
227
+ return `${protocol}://${host}:${port}`;
228
+ }
229
+
18
230
  const LAYOUT_PLUGIN_NAME = "vite:hybridly:layout";
19
231
  const CONFIG_PLUGIN_NAME = "vite:hybridly:config";
20
232
  const CONFIG_VIRTUAL_MODULE_ID = "virtual:hybridly/config";
@@ -27,6 +239,14 @@ const debug = {
27
239
  function isPackageInstalled(name, paths = [process.cwd()]) {
28
240
  return isPackageExists(name, { paths });
29
241
  }
242
+ function importPackage(name, paths = [process.cwd()]) {
243
+ const mod = resolveModule(name, { paths });
244
+ if (!mod) {
245
+ console.warn(`Could not resolve package [${name}]`);
246
+ return;
247
+ }
248
+ return importModule(mod);
249
+ }
30
250
  function toKebabCase(key) {
31
251
  const result = key.replace(/([A-Z])/g, " $1").trim();
32
252
  return result.split(" ").join("-").toLowerCase();
@@ -37,7 +257,7 @@ function generateTsConfig(options, config) {
37
257
  compilerOptions: {
38
258
  target: "esnext",
39
259
  module: "esnext",
40
- moduleResolution: "node",
260
+ moduleResolution: "bundler",
41
261
  strict: true,
42
262
  jsx: "preserve",
43
263
  sourceMap: true,
@@ -63,7 +283,7 @@ function generateTsConfig(options, config) {
63
283
  "./*"
64
284
  ],
65
285
  "@/*": [
66
- `./${config.architecture.root}/*`
286
+ `./${config.architecture.root_directory}/*`
67
287
  ]
68
288
  }
69
289
  },
@@ -71,7 +291,7 @@ function generateTsConfig(options, config) {
71
291
  ...config.components.views.map(({ path: path2 }) => `../${path2}`),
72
292
  ...config.components.layouts.map(({ path: path2 }) => `../${path2}`),
73
293
  ...config.components.components.map(({ path: path2 }) => `../${path2}`),
74
- `../${config.architecture.root}/**/*`,
294
+ `../${config.architecture.root_directory}/**/*`,
75
295
  "../app/**/*",
76
296
  "../src/**/*",
77
297
  "./php-types.d.ts",
@@ -83,8 +303,6 @@ function generateTsConfig(options, config) {
83
303
  ],
84
304
  exclude: [
85
305
  "../public/**/*",
86
- "../node_modules",
87
- "../vendor",
88
306
  ...options.tsconfig?.exclude ?? []
89
307
  ]
90
308
  };
@@ -163,7 +381,7 @@ async function loadConfiguration(options) {
163
381
  }
164
382
  }
165
383
 
166
- function getClientCode(config) {
384
+ function getClientCode$1(config) {
167
385
  const paths = config.components.views.map(({ path }) => `"~/${path}"`).join(",");
168
386
  return `
169
387
  import { initializeHybridly as init } from 'hybridly/vue'
@@ -189,7 +407,7 @@ const initialize = (options, config) => {
189
407
  return {
190
408
  resolve: {
191
409
  alias: {
192
- "@": path.join(process.cwd(), config.architecture.root),
410
+ "@": path.join(process.cwd(), config.architecture.root_directory),
193
411
  "#": path.join(process.cwd(), ".hybridly"),
194
412
  "~": path.join(process.cwd())
195
413
  }
@@ -235,7 +453,7 @@ const initialize = (options, config) => {
235
453
  },
236
454
  async load(id) {
237
455
  if (id === RESOLVED_CONFIG_VIRTUAL_MODULE_ID) {
238
- return getClientCode(config);
456
+ return getClientCode$1(config);
239
457
  }
240
458
  },
241
459
  // Denies HMR for `.hybridly` content, it causes unwanted reloads
@@ -329,13 +547,6 @@ function getRunOptions(options) {
329
547
  ];
330
548
  }
331
549
 
332
- function getLaravelOptions(options, config) {
333
- return {
334
- input: `${config.architecture.root}/application/main.ts`,
335
- ...options.laravel ?? {}
336
- };
337
- }
338
-
339
550
  const HybridlyImports = {
340
551
  "hybridly/vue": [
341
552
  "useProperty",
@@ -384,8 +595,8 @@ function getAutoImportsOptions(options, config) {
384
595
  vueTemplate: true,
385
596
  dts: ".hybridly/auto-imports.d.ts",
386
597
  dirs: [
387
- `${config.architecture.root}/utils`,
388
- `${config.architecture.root}/composables`,
598
+ `${config.architecture.root_directory}/utils`,
599
+ `${config.architecture.root_directory}/composables`,
389
600
  ...config.components.directories.map((directory) => `${directory}/**/*.ts`)
390
601
  ],
391
602
  imports: [
@@ -401,21 +612,7 @@ function getAutoImportsOptions(options, config) {
401
612
  );
402
613
  }
403
614
 
404
- function HybridlyResolver(linkName = "RouterLink") {
405
- return {
406
- type: "component",
407
- resolve: (name) => {
408
- if (name === linkName) {
409
- return {
410
- from: "hybridly/vue",
411
- name: "RouterLink",
412
- as: linkName
413
- };
414
- }
415
- }
416
- };
417
- }
418
- function getVueComponentsOptions(options, config) {
615
+ async function getVueComponentsOptions(options, config) {
419
616
  if (options.vueComponents === false) {
420
617
  return {};
421
618
  }
@@ -423,16 +620,18 @@ function getVueComponentsOptions(options, config) {
423
620
  const customCollections = Array.isArray(options.customIcons) ? options.customIcons : options.customIcons?.collections ?? [];
424
621
  const overrideResolvers = options.overrideResolvers ? Array.isArray(options.overrideResolvers) ? options.overrideResolvers : [options.overrideResolvers] : false;
425
622
  const hasHeadlessUI = isPackageInstalled("@headlessui/vue");
623
+ const hasRadix = isPackageInstalled("radix-vue");
426
624
  return merge(
427
625
  {
428
626
  dirs: [
429
- `./${config.architecture.root}/components`
627
+ `./${config.architecture.root_directory}/${config.architecture.components_directory}`
430
628
  ],
431
629
  directoryAsNamespace: true,
432
630
  dts: ".hybridly/components.d.ts",
433
631
  resolvers: overrideResolvers || [
434
632
  ...hasIcons ? [iconsResolver({ customCollections })] : [],
435
633
  ...hasHeadlessUI ? [HeadlessUiResolver({ prefix: options?.vueComponents?.headlessUiPrefix ?? "Headless" })] : [],
634
+ ...hasRadix ? [await RadixResolver(options?.vueComponents?.radixPrefix)] : [],
436
635
  ProvidedComponentListResolver(config),
437
636
  HybridlyResolver(options.vueComponents?.linkName)
438
637
  ]
@@ -441,6 +640,24 @@ function getVueComponentsOptions(options, config) {
441
640
  { overwriteArray: false }
442
641
  );
443
642
  }
643
+ async function RadixResolver(prefix = "Radix") {
644
+ const radix = await importPackage("radix-vue/resolver");
645
+ return radix.default({ prefix });
646
+ }
647
+ function HybridlyResolver(linkName = "RouterLink") {
648
+ return {
649
+ type: "component",
650
+ resolve: (name) => {
651
+ if (name === linkName) {
652
+ return {
653
+ from: "hybridly/vue",
654
+ name: "RouterLink",
655
+ as: linkName
656
+ };
657
+ }
658
+ }
659
+ };
660
+ }
444
661
  function ProvidedComponentListResolver(config) {
445
662
  function resolveComponentPath(name) {
446
663
  const kebabName = toKebabCase(name);
@@ -467,7 +684,7 @@ function getIconsOptions(options, config) {
467
684
  const customIconDirectoryName = resolved?.icons ?? "icons";
468
685
  const customCollections = Object.fromEntries(resolved?.collections?.map((collection) => [
469
686
  collection,
470
- FileSystemIconLoader(`./${config.architecture.root}/${customIconDirectoryName}/${collection}`)
687
+ FileSystemIconLoader(`./${config.architecture.root_directory}/${customIconDirectoryName}/${collection}`)
471
688
  ]) ?? []);
472
689
  return {
473
690
  autoInstall: true,
@@ -530,18 +747,121 @@ function killSwitch() {
530
747
  };
531
748
  }
532
749
 
750
+ function getClientCode() {
751
+ const style = `
752
+ .local-build {
753
+ position: fixed;
754
+ bottom: 1rem;
755
+ left: 1rem;
756
+ z-index: 50;
757
+ display: inline-flex;
758
+ max-width: 26rem;
759
+ align-items: center;
760
+ background-color: rgba(0, 0, 0, 0.9);
761
+ padding: 0.75rem;
762
+ font-size: 0.75rem;
763
+ color: #8C8C8C;
764
+ transition: opacity 0.3s;
765
+ }
766
+
767
+ .local-build:hover {
768
+ opacity: 0.1;
769
+ }
770
+
771
+ .local-build .icon {
772
+ margin-right: 0.5rem;
773
+ height: 1.25rem;
774
+ width: 1.25rem;
775
+ fill: currentColor;
776
+ }
777
+
778
+ .local-build .content {
779
+ display: inline-flex;
780
+ flex-direction: column;
781
+ gap: 0.5rem;
782
+ }
783
+
784
+ .local-build .title {
785
+ font-weight: 500;
786
+ }
787
+ `;
788
+ const html = `
789
+ <div class="local-build">
790
+ <svg viewBox="0 0 24 24" width="1.2em" height="1.2em" class="icon"><path fill="currentColor" d="M11 15h2v2h-2zm0-8h2v6h-2zm1-5C6.47 2 2 6.5 2 12a10 10 0 0 0 10 10a10 10 0 0 0 10-10A10 10 0 0 0 12 2m0 18a8 8 0 0 1-8-8a8 8 0 0 1 8-8a8 8 0 0 1 8 8a8 8 0 0 1-8 8"></path></svg>
791
+ <span class="content">
792
+ <span class="title">This is a local production build. Changes will not be reflected.</span>
793
+ </span>
794
+ </div>
795
+ `;
796
+ return `
797
+ ;(function() {
798
+ const style = document.createElement('style')
799
+ style.innerHTML = \`${style}\`
800
+ document.head.appendChild(style)
801
+
802
+ const html = document.createElement('div')
803
+ html.innerHTML = \`${html}\`
804
+ document.body.appendChild(html)
805
+ html.addEventListener('click', () => html.remove())
806
+ })()
807
+ `;
808
+ }
809
+
810
+ const LOCAL_BUILD_VIRTUAL_ID = "virtual:hybridly/local-build";
811
+ const RESOLVED_LOCAL_BUILD_VIRTUAL_ID = `\0${LOCAL_BUILD_VIRTUAL_ID}`;
812
+ function warnOnLocalBuilds() {
813
+ let shouldDisplayWarning = false;
814
+ return {
815
+ name: "vite:hybridly:local-build",
816
+ enforce: "pre",
817
+ apply: "build",
818
+ config(config, { mode }) {
819
+ const env = loadEnv(mode, config.envDir ?? process.cwd(), "");
820
+ shouldDisplayWarning = env.APP_ENV === "local";
821
+ },
822
+ async resolveId(id) {
823
+ if (!shouldDisplayWarning) {
824
+ return;
825
+ }
826
+ if (id === LOCAL_BUILD_VIRTUAL_ID) {
827
+ return RESOLVED_LOCAL_BUILD_VIRTUAL_ID;
828
+ }
829
+ },
830
+ async load(id) {
831
+ if (!shouldDisplayWarning) {
832
+ return;
833
+ }
834
+ if (id === RESOLVED_LOCAL_BUILD_VIRTUAL_ID) {
835
+ return getClientCode();
836
+ }
837
+ },
838
+ transform(code, id) {
839
+ if (!shouldDisplayWarning) {
840
+ return;
841
+ }
842
+ if (!id.endsWith(CONFIG_VIRTUAL_MODULE_ID)) {
843
+ return;
844
+ }
845
+ code = `${code}
846
+ import '${LOCAL_BUILD_VIRTUAL_ID}'`;
847
+ return code;
848
+ }
849
+ };
850
+ }
851
+
533
852
  async function plugin(options = {}) {
534
853
  const config = await loadConfiguration(options);
535
854
  return [
536
855
  initialize(options, config),
537
856
  layout(options, config),
538
- options.laravel !== false && laravel(getLaravelOptions(options, config)),
857
+ options.laravel !== false && laravel(options, config),
539
858
  options.run !== false && run(getRunOptions(options)),
540
- options.vueComponents !== false && vueComponents(getVueComponentsOptions(options, config)),
859
+ options.vueComponents !== false && vueComponents(await getVueComponentsOptions(options, config)),
541
860
  options.autoImports !== false && autoimport(getAutoImportsOptions(options, config)),
542
861
  options.icons !== false && icons(getIconsOptions(options, config)),
543
862
  options.vue !== false && vue(getVueOptions(options)),
544
- options.killSwitch !== false && killSwitch()
863
+ options.killSwitch !== false && killSwitch(),
864
+ options.warnOnLocalBuilds !== false && warnOnLocalBuilds()
545
865
  ];
546
866
  }
547
867
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hybridly/vite",
3
- "version": "0.5.6",
3
+ "version": "0.6.0",
4
4
  "description": "Vite plugin for Hybridly",
5
5
  "keywords": [
6
6
  "hybridly",
@@ -8,10 +8,6 @@
8
8
  "vite",
9
9
  "vite-plugin"
10
10
  ],
11
- "homepage": "https://github.com/hybridly/hybridly/tree/main/packages/vite#readme",
12
- "bugs": {
13
- "url": "https://github.com/hybridly/hybridly/issues"
14
- },
15
11
  "license": "MIT",
16
12
  "repository": {
17
13
  "type": "git",
@@ -20,6 +16,11 @@
20
16
  },
21
17
  "funding": "https://github.com/sponsors/innocenzi",
22
18
  "author": "Enzo Innocenzi <enzo@innocenzi.dev>",
19
+ "type": "module",
20
+ "homepage": "https://github.com/hybridly/hybridly/tree/main/packages/vite#readme",
21
+ "bugs": {
22
+ "url": "https://github.com/hybridly/hybridly/issues"
23
+ },
23
24
  "sideEffects": false,
24
25
  "files": [
25
26
  "dist",
@@ -36,27 +37,27 @@
36
37
  "module": "dist/index.mjs",
37
38
  "types": "dist/index.d.ts",
38
39
  "peerDependencies": {
39
- "vite": "^4.4.9",
40
+ "vite": "^5.0.8",
40
41
  "vue": "^3.2.45"
41
42
  },
42
43
  "dependencies": {
43
- "@vitejs/plugin-vue": "^4.4.0",
44
- "fast-glob": "^3.3.1",
45
- "laravel-vite-plugin": "^0.8.1",
46
- "local-pkg": "^0.4.3",
44
+ "@vitejs/plugin-vue": "^4.6.2",
45
+ "fast-glob": "^3.3.2",
46
+ "local-pkg": "^0.5.0",
47
47
  "magic-string": "^0.30.5",
48
+ "picocolors": "^1.0.0",
48
49
  "throttle-debounce": "^5.0.0",
49
- "unplugin-auto-import": "^0.16.6",
50
- "unplugin-icons": "^0.17.1",
51
- "unplugin-vue-components": "^0.25.2",
50
+ "unplugin-auto-import": "^0.17.3",
51
+ "unplugin-icons": "^0.18.1",
52
+ "unplugin-vue-components": "^0.26.0",
52
53
  "vite-plugin-run": "^0.5.1",
53
- "@hybridly/core": "0.5.6"
54
+ "@hybridly/core": "0.6.0"
54
55
  },
55
56
  "devDependencies": {
56
- "@iconify/json": "^2.2.133",
57
- "rollup": "^3.29.4",
58
- "vite": "^4.5.0",
59
- "vue": "^3.3.7"
57
+ "@iconify/json": "^2.2.163",
58
+ "rollup": "^4.9.2",
59
+ "vite": "^5.0.10",
60
+ "vue": "^3.4.3"
60
61
  },
61
62
  "scripts": {
62
63
  "build": "unbuild",