vite-plugin-caddy-multiple-tls 1.0.0 → 1.1.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/README.md CHANGED
@@ -1,28 +1,132 @@
1
1
  # vite-plugin-caddy-multiple-tls
2
2
 
3
- Vite plugin that runs Caddy to proxy local development traffic over HTTPS with
4
- derived domains like `<repo>.<branch>.localhost`.
3
+ ## Usage
5
4
 
6
- ## Install
5
+ ```js
6
+ // vite.config.js
7
+ import { defineConfig } from 'vite';
8
+ import caddyTls from 'vite-plugin-caddy-multiple-tls';
7
9
 
8
- ```sh
9
- npm install -D vite-plugin-caddy-multiple-tls
10
+ const config = defineConfig({
11
+ plugins: [
12
+ caddyTls(),
13
+ ]
14
+ });
15
+
16
+ export default config;
10
17
  ```
11
18
 
12
- ## Usage
19
+ Will give this in the terminal, allow you to connect to your app on HTTPS with a self-signed and trusted cert.
20
+ ```
21
+ > vite
22
+
23
+
24
+ 🔒 Caddy is proxying your traffic on https
25
+
26
+ 🔗 Access your local server
27
+ 🌍 https://my-repo.my-branch.localhost
28
+
29
+ ```
30
+
31
+ By default, the plugin derives `<repo>.<branch>.localhost` from git.
32
+ If repo or branch can't be detected, pass `repo`/`branch` or use `domain`.
33
+
34
+ If you want a fixed host without repo/branch in the URL, pass a single domain:
35
+
36
+ ```js
37
+ // vite.config.js
38
+ import { defineConfig } from 'vite';
39
+ import caddyTls from 'vite-plugin-caddy-multiple-tls';
40
+
41
+ const config = defineConfig({
42
+ plugins: [
43
+ caddyTls({
44
+ domain: 'app.localhost',
45
+ })
46
+ ]
47
+ });
48
+
49
+ export default config;
50
+ ```
51
+
52
+ To derive a domain like `<repo>.<branch>.<baseDomain>` automatically from git (repo name first, then branch):
13
53
 
14
54
  ```js
55
+ // vite.config.js
15
56
  import { defineConfig } from 'vite';
16
57
  import caddyTls from 'vite-plugin-caddy-multiple-tls';
17
58
 
18
- export default defineConfig({
19
- plugins: [caddyTls()],
59
+ const config = defineConfig({
60
+ plugins: [
61
+ caddyTls({
62
+ baseDomain: 'local.conekto.eu',
63
+ })
64
+ ]
20
65
  });
66
+
67
+ export default config;
68
+ ```
69
+
70
+ You can override auto-detection with `repo` or `branch` if needed.
71
+
72
+ For a zero-config experience, use `baseDomain: 'localhost'` (the default) so the derived domain works without editing `/etc/hosts`.
73
+
74
+ `internalTls` defaults to `true` when you pass `baseDomain` or `domain`. You can override it if needed.
75
+
76
+ For non-`.localhost` domains (like `local.example.test`), keep `internalTls: true` to force Caddy to use its internal CA for certificates.
77
+
78
+ > [!IMPORTANT]
79
+ > **Hosts file limitation:** If you use a custom domain, you must **manually** add each generated subdomain to your `/etc/hosts` file (e.g., `127.0.0.1 repo.branch.local.example.test`). System hosts files **do not support wildcards** (e.g., `*.local.example.test`), so you lose the benefit of automatic domain resolution that `localhost` provides.
80
+
81
+ ## Recommended base domain: `.localhost`
82
+ Why `localhost` is the best option for local development:
83
+ - Reserved by RFC 6761 (never on the public internet).
84
+ - Automatic resolution on macOS: `*.localhost` maps to `127.0.0.1` and `::1` without DNS or `/etc/hosts`.
85
+ - Subdomain support: `api.localhost`, `foo.bar.localhost`, etc.
86
+ - Secure context in browsers for HTTPS, service workers, and cookies.
87
+ - Works well with Caddy and other local reverse proxies.
88
+
89
+ Example usage:
90
+ ```
91
+ app.localhost
92
+ api.app.localhost
21
93
  ```
22
94
 
23
- ## Options
95
+ > [!NOTE]
96
+ > **Linux users:** Unlike macOS, most Linux distributions don't automatically resolve `*.localhost` subdomains. The plugin will detect Linux and show you the exact command to run:
97
+ > ```
98
+ > 🐧 Linux users: if the domain doesn't resolve, run:
99
+ > echo "127.0.0.1 my-repo.my-branch.localhost" | sudo tee -a /etc/hosts
100
+ > ```
101
+ >
102
+ > If you want to avoid `/etc/hosts` edits on Linux, set `loopbackDomain` to a public loopback domain:
103
+ > ```ts
104
+ > caddyTls({
105
+ > loopbackDomain: 'localtest.me',
106
+ > })
107
+ > ```
108
+ > Supported values: `localtest.me`, `lvh.me`, `nip.io` (maps to `127.0.0.1.nip.io`). These rely on public DNS, so they can fail offline or on restricted networks.
109
+ >
110
+ > Why these work: they use wildcard DNS so any subdomain resolves to `127.0.0.1`, meaning the request loops back to your machine after DNS.
111
+ > - `localtest.me` and `lvh.me`: static wildcard -> always `127.0.0.1` (great for subdomain testing).
112
+ > - `nip.io`: dynamic parsing of the IP in the hostname (e.g. `app.192.168.1.50.nip.io`) so you can target LAN devices.
113
+ > Why use them: subdomains behave like real domains, no `/etc/hosts` edits, and closer parity for cookies/CORS rules.
114
+ >
115
+ > When using loopback domains, ensure your Vite config allows the Host header, e.g. `server: { allowedHosts: true }`.
116
+ >
117
+ > For a permanent fix that handles all `*.localhost` domains automatically, install dnsmasq:
118
+ > ```bash
119
+ > sudo apt install dnsmasq
120
+ > echo "address=/.localhost/127.0.0.1" | sudo tee /etc/dnsmasq.d/localhost.conf
121
+ > sudo systemctl restart dnsmasq
122
+ > ```
123
+
124
+ ## Development
125
+ This repo uses npm workspaces. Install from the root with `npm install`, then run workspace scripts like `npm run build --workspace packages/plugin` or `npm run dev --workspace playground`.
126
+
127
+ ## Contributing
128
+ See [CONTRIBUTING.md](./CONTRIBUTING.md) to see how to get started.
129
+
130
+ ## License
24
131
 
25
- - `domain`: explicit domain to proxy without repo/branch derivation
26
- - `baseDomain`: base domain to build `<repo>.<branch>.<baseDomain>` (defaults to `localhost`)
27
- - `repo`, `branch`: override repo/branch names used for derived domains
28
- - `internalTls`: use Caddy internal CA for provided domains
132
+ MIT
package/dist/index.d.ts CHANGED
@@ -5,6 +5,8 @@ interface ViteCaddyTlsPluginOptions {
5
5
  domain?: string;
6
6
  /** Base domain to build <repo>.<branch>.<baseDomain> (defaults to localhost) */
7
7
  baseDomain?: string;
8
+ /** Optional loopback domain to avoid /etc/hosts edits */
9
+ loopbackDomain?: LoopbackDomain;
8
10
  /** Override repo name used in derived domains */
9
11
  repo?: string;
10
12
  /** Override branch name used in derived domains */
@@ -15,6 +17,7 @@ interface ViteCaddyTlsPluginOptions {
15
17
  /** Use Caddy's internal CA for the provided domains (defaults to true when baseDomain or domain is set) */
16
18
  internalTls?: boolean;
17
19
  }
20
+ type LoopbackDomain = 'localtest.me' | 'lvh.me' | 'nip.io';
18
21
  /**
19
22
  * Vite plugin to run Caddy server to proxy traffic on https for local development
20
23
  *
@@ -27,6 +30,6 @@ interface ViteCaddyTlsPluginOptions {
27
30
  * ```
28
31
  * @returns {Plugin} - a Vite plugin
29
32
  */
30
- declare function viteCaddyTlsPlugin({ domain, baseDomain, repo, branch, cors, serverName, internalTls, }?: ViteCaddyTlsPluginOptions): PluginOption;
33
+ declare function viteCaddyTlsPlugin({ domain, baseDomain, loopbackDomain, repo, branch, cors, serverName, internalTls, }?: ViteCaddyTlsPluginOptions): PluginOption;
31
34
 
32
35
  export { type ViteCaddyTlsPluginOptions, viteCaddyTlsPlugin as default };
package/dist/index.js CHANGED
@@ -1,5 +1,4 @@
1
1
  // src/index.ts
2
- import chalk from "chalk";
3
2
  import { execSync as execSync2 } from "child_process";
4
3
  import path from "path";
5
4
 
@@ -271,6 +270,11 @@ async function removeTlsPolicy(id) {
271
270
  }
272
271
 
273
272
  // src/index.ts
273
+ var LOOPBACK_DOMAINS = {
274
+ "localtest.me": "localtest.me",
275
+ "lvh.me": "lvh.me",
276
+ "nip.io": "127.0.0.1.nip.io"
277
+ };
274
278
  function execGit(command) {
275
279
  return execSync2(command, { stdio: ["ignore", "pipe", "ignore"] }).toString().trim();
276
280
  }
@@ -298,11 +302,20 @@ function getGitRepoInfo() {
298
302
  function normalizeBaseDomain(baseDomain) {
299
303
  return baseDomain.trim().replace(/^\.+|\.+$/g, "").toLowerCase();
300
304
  }
305
+ function resolveBaseDomain(options) {
306
+ if (options.baseDomain !== void 0) {
307
+ return normalizeBaseDomain(options.baseDomain);
308
+ }
309
+ if (options.loopbackDomain) {
310
+ return normalizeBaseDomain(LOOPBACK_DOMAINS[options.loopbackDomain]);
311
+ }
312
+ return "localhost";
313
+ }
301
314
  function sanitizeDomainLabel(value) {
302
315
  return value.toLowerCase().replace(/[^a-z0-9-]/g, "-").replace(/-+/g, "-").replace(/^-+|-+$/g, "");
303
316
  }
304
317
  function buildDerivedDomain(options) {
305
- const baseDomain = normalizeBaseDomain(options.baseDomain ?? "localhost");
318
+ const baseDomain = resolveBaseDomain(options);
306
319
  if (!baseDomain) return null;
307
320
  let repo = options.repo;
308
321
  let branch = options.branch;
@@ -331,6 +344,7 @@ function resolveDomain(options) {
331
344
  function viteCaddyTlsPlugin({
332
345
  domain,
333
346
  baseDomain,
347
+ loopbackDomain,
334
348
  repo,
335
349
  branch,
336
350
  cors,
@@ -341,17 +355,21 @@ function viteCaddyTlsPlugin({
341
355
  name: "vite:caddy-tls",
342
356
  configureServer({ httpServer, config }) {
343
357
  const fallbackPort = config.server.port || 5173;
344
- const resolvedDomain = resolveDomain({ domain, baseDomain, repo, branch });
358
+ const resolvedDomain = resolveDomain({
359
+ domain,
360
+ baseDomain,
361
+ loopbackDomain,
362
+ repo,
363
+ branch
364
+ });
345
365
  const domainArray = resolvedDomain ? [resolvedDomain] : [];
346
366
  const routeId = `vite-proxy-${Date.now()}-${Math.floor(Math.random() * 1e3)}`;
347
- const shouldUseInternalTls = internalTls ?? (baseDomain !== void 0 || domain !== void 0);
367
+ const shouldUseInternalTls = internalTls ?? (baseDomain !== void 0 || loopbackDomain !== void 0 || domain !== void 0);
348
368
  const tlsPolicyId = shouldUseInternalTls ? `${routeId}-tls` : null;
349
369
  let cleanupStarted = false;
350
370
  if (domainArray.length === 0) {
351
371
  console.error(
352
- chalk.red(
353
- "No domain resolved. Provide domain, or run inside a git repo, or pass repo/branch."
354
- )
372
+ "No domain resolved. Provide domain, or run inside a git repo, or pass repo/branch."
355
373
  );
356
374
  return;
357
375
  }
@@ -400,14 +418,14 @@ function viteCaddyTlsPlugin({
400
418
  if (!running) {
401
419
  running = await startCaddy();
402
420
  if (!running) {
403
- console.error(chalk.red("Failed to start Caddy server."));
421
+ console.error("Failed to start Caddy server.");
404
422
  return;
405
423
  }
406
424
  }
407
425
  try {
408
426
  await ensureBaseConfig(serverName);
409
427
  } catch (e) {
410
- console.error(chalk.red("Failed to configure Caddy base settings."), e);
428
+ console.error("Failed to configure Caddy base settings.", e);
411
429
  return;
412
430
  }
413
431
  const port = getServerPort();
@@ -416,7 +434,7 @@ function viteCaddyTlsPlugin({
416
434
  await addTlsPolicy(tlsPolicyId, domainArray);
417
435
  tlsPolicyAdded = true;
418
436
  } catch (e) {
419
- console.error(chalk.red("Failed to add TLS policy to Caddy."), e);
437
+ console.error("Failed to add TLS policy to Caddy.", e);
420
438
  return;
421
439
  }
422
440
  }
@@ -426,23 +444,23 @@ function viteCaddyTlsPlugin({
426
444
  if (tlsPolicyAdded && tlsPolicyId) {
427
445
  await removeTlsPolicy(tlsPolicyId);
428
446
  }
429
- console.error(chalk.red("Failed to add route to Caddy."), e);
447
+ console.error("Failed to add route to Caddy.", e);
430
448
  return;
431
449
  }
432
450
  console.log();
433
- console.log(chalk.green("\u{1F512} Caddy is proxying your traffic on https"));
451
+ console.log("\u{1F512} Caddy is proxying your traffic on https");
434
452
  console.log();
435
453
  console.log(
436
454
  `\u{1F517} Access your local ${domainArray.length > 1 ? "servers" : "server"} `
437
455
  );
438
456
  domainArray.forEach((domain2) => {
439
- console.log(chalk.blue(`\u{1F30D} https://${domain2}`));
457
+ console.log(`\u{1F30D} https://${domain2}`);
440
458
  });
441
- if (process.platform === "linux") {
459
+ if (process.platform === "linux" && !loopbackDomain) {
442
460
  console.log();
443
- console.log(chalk.yellow("\u{1F427} Linux users: if the domain doesn't resolve, run:"));
461
+ console.log("\u{1F427} Linux users: if the domain doesn't resolve, run:");
444
462
  domainArray.forEach((domain2) => {
445
- console.log(chalk.dim(` echo "127.0.0.1 ${domain2}" | sudo tee -a /etc/hosts`));
463
+ console.log(` echo "127.0.0.1 ${domain2}" | sudo tee -a /etc/hosts`);
446
464
  });
447
465
  }
448
466
  console.log();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vite-plugin-caddy-multiple-tls",
3
- "version": "1.0.0",
3
+ "version": "1.1.0",
4
4
  "description": "Vite plugin that uses Caddy to provide local HTTPS with derived domains.",
5
5
  "keywords": [
6
6
  "vite",
@@ -29,7 +29,8 @@
29
29
  },
30
30
  "scripts": {
31
31
  "dev": "tsup --watch src/**/* src/index.ts --format esm --dts-resolve",
32
- "build": "tsup src/index.ts --format esm --dts",
32
+ "sync-readme": "bash scripts/sync-readme.sh",
33
+ "build": "npm run sync-readme && tsup src/index.ts --format esm --dts",
33
34
  "prepublishOnly": "npm run build",
34
35
  "test": "vitest run",
35
36
  "test:watch": "vitest"
@@ -55,8 +56,5 @@
55
56
  "tsup": "^8.5.1",
56
57
  "vite": "^7.3.0",
57
58
  "vitest": "^4.0.16"
58
- },
59
- "dependencies": {
60
- "chalk": "^5.6.2"
61
59
  }
62
60
  }