unplugin-https-reverse-proxy 2.0.3-beta.2 → 4.0.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.
@@ -3,11 +3,11 @@ import { Liquid } from 'liquidjs'
3
3
 
4
4
  export const ProxyType = type({
5
5
  target: 'string',
6
- port_suffix: 'string',
6
+ portSuffix: 'string',
7
7
  tls: 'string',
8
8
  source: 'string',
9
9
  base: 'string',
10
- health_check: 'boolean',
10
+ healthCheck: 'boolean',
11
11
  })
12
12
 
13
13
  const CaddyContext = type({
@@ -46,27 +46,36 @@ export const caddyTemplate = `{
46
46
  }
47
47
  }
48
48
 
49
- {% for p in proxies %}
50
- {{ p.target }}{{ p.port_suffix }} {
51
- {{ p.tls }}
52
- reverse_proxy http://{{ p.source }} {% if p.health_check %} {
53
- health_uri {{ p.base }}
54
- health_interval 2s
55
- health_timeout 5s
56
- fail_duration 2s
57
- unhealthy_status 502 503 504 404
58
- lb_try_duration 3s
59
- lb_try_interval 300ms
60
-
61
- @error status 502 503 504 404
62
- handle_response @error {
63
- respond * 503 {
64
- body "Service Unavailable"
65
- close
49
+ {% for host in hosts %}
50
+ {{ host.host }}{{ host.portSuffix }} {
51
+ {{ host.tls }}
52
+
53
+ {% for route in host.routes %}
54
+ handle {{ route.base }}* {
55
+ reverse_proxy http://{{ route.source }} {% if route.healthCheck %} {
56
+ health_uri {{ route.base }}
57
+ health_interval 2s
58
+ health_timeout 5s
59
+ health_headers {
60
+ User-Agent {http.request.header.User-Agent}
61
+ Accept text/html,application/json,*/*
62
+ }
63
+ fail_duration 2s
64
+ unhealthy_status 502 503 504 404
65
+ lb_try_duration 3s
66
+ lb_try_interval 300ms
67
+
68
+ @error status 502 503 504 404
69
+ handle_response @error {
70
+ respond * 503 {
71
+ body "Service Unavailable"
72
+ close
73
+ }
66
74
  }
67
75
  }
76
+ {% endif %}
68
77
  }
69
- {% endif %}
78
+ {% endfor %}
70
79
  }
71
80
  {% endfor %}
72
81
  `
@@ -74,5 +83,35 @@ export const caddyTemplate = `{
74
83
  const liquid = new Liquid()
75
84
 
76
85
  export async function genCaddyfile(ctx: typeof CaddyContext.infer): Promise<string> {
77
- return await liquid.parseAndRender(caddyTemplate, ctx)
86
+ const hostsMap = new Map<string, {
87
+ host: string
88
+ portSuffix: string
89
+ tls: string
90
+ routes: typeof ProxyType.infer[]
91
+ }>()
92
+
93
+ for (const proxy of ctx.proxies) {
94
+ const key = `${proxy.target}${proxy.portSuffix}`
95
+ if (!hostsMap.has(key)) {
96
+ hostsMap.set(key, {
97
+ host: proxy.target,
98
+ portSuffix: proxy.portSuffix,
99
+ tls: proxy.tls,
100
+ routes: [],
101
+ })
102
+ }
103
+ let base = proxy.base || '/'
104
+ if (!base.startsWith('/'))
105
+ base = `/${base}`
106
+ if (base !== '/' && !base.endsWith('/'))
107
+ base = `${base}/`
108
+ hostsMap.get(key)!.routes.push({ ...proxy, base })
109
+ }
110
+
111
+ for (const host of hostsMap.values())
112
+ host.routes.sort((a, b) => b.base.length - a.base.length)
113
+
114
+ const hosts = Array.from(hostsMap.values())
115
+
116
+ return await liquid.parseAndRender(caddyTemplate, { ...ctx, hosts })
78
117
  }
@@ -44,8 +44,13 @@ export function useCaddyConfig(): {
44
44
  const proxies = configJsonRef() || {}
45
45
 
46
46
  _proxies.forEach((p) => {
47
- const index = `${p.target}${p.port_suffix}`
48
- proxies[index] = p
47
+ let base = p.base || '/'
48
+ if (!base.startsWith('/'))
49
+ base = `/${base}`
50
+ if (base !== '/' && !base.endsWith('/'))
51
+ base = `${base}/`
52
+ const index = `${p.target}${p.portSuffix}${base}`
53
+ proxies[index] = { ...p, base }
49
54
  })
50
55
 
51
56
  const content = JSON.stringify(proxies, null, 2)
@@ -102,10 +102,17 @@ interface RunOptions {
102
102
  base: string
103
103
  showCaddyLog: boolean
104
104
  https: boolean
105
- health_check?: boolean
105
+ healthCheck?: boolean
106
106
  }
107
107
 
108
- const { cleanUp, configJsonRef, writeCaddyConfig } = useCaddyConfig()
108
+ let caddyConfig: ReturnType<typeof useCaddyConfig> | undefined
109
+
110
+ function getCaddyConfig(): ReturnType<typeof useCaddyConfig> {
111
+ if (!caddyConfig) {
112
+ caddyConfig = useCaddyConfig()
113
+ }
114
+ return caddyConfig
115
+ }
109
116
 
110
117
  export class CaddyInstant {
111
118
  private inited = false
@@ -178,7 +185,7 @@ export class CaddyInstant {
178
185
  base = '/',
179
186
  showCaddyLog = false,
180
187
  https = false,
181
- health_check = true,
188
+ healthCheck = true,
182
189
  } = options || {}
183
190
 
184
191
  this._source = source
@@ -192,32 +199,41 @@ export class CaddyInstant {
192
199
  consola.success('update host success\n')
193
200
 
194
201
  const targetHost = target.split(':')[0]
202
+ const normalizeBase = (b: string): string => {
203
+ let out = b || '/'
204
+ if (!out.startsWith('/'))
205
+ out = `/${out}`
206
+ if (out !== '/' && !out.endsWith('/'))
207
+ out = `${out}/`
208
+ return out
209
+ }
210
+ const baseNormalized = normalizeBase(base)
195
211
 
196
212
  const proxies = [
197
213
  {
198
214
  target: targetHost,
199
- port_suffix: https ? '' : ':80',
215
+ portSuffix: https ? '' : ':80',
200
216
  tls: https ? 'tls internal' : '',
201
217
  source,
202
- base,
203
- health_check,
218
+ base: baseNormalized,
219
+ healthCheck,
204
220
  },
205
221
  ]
206
222
 
223
+ const { writeCaddyConfig } = getCaddyConfig()
207
224
  writeCaddyConfig(proxies)
208
225
 
209
226
  this._stopEffects.push(
210
227
  effect(async () => {
228
+ const { configJsonRef } = getCaddyConfig()
211
229
  const proxies = Object.values(configJsonRef() || {})
212
- if (!(this.caddyfile || '').includes(`${target.split(':')[0]}${https ? '' : ':80'}`)) {
213
- const ctx = validateTemplateContext({
214
- caddy_root: this.caddyRoot,
215
- proxies,
216
- })
217
-
218
- this.caddyfile = await genCaddyfile(ctx)
219
- await this.writeCaddyfile()
220
- }
230
+ const ctx = validateTemplateContext({
231
+ caddy_root: this.caddyRoot,
232
+ proxies,
233
+ })
234
+
235
+ this.caddyfile = await genCaddyfile(ctx)
236
+ await this.writeCaddyfile()
221
237
  }),
222
238
  )
223
239
 
@@ -368,7 +384,9 @@ export class CaddyInstant {
368
384
  await lockfile.unlock(caddyLockFilePath).catch(() => { })
369
385
  await unlink(caddyFilePath).catch(() => { })
370
386
  await unlink(caddyLockFilePath).catch(() => { })
371
- await cleanUp()
387
+ if (caddyConfig) {
388
+ await caddyConfig.cleanUp()
389
+ }
372
390
  }
373
391
  catch (e) {
374
392
  consola.error(e)
package/src/index.ts CHANGED
@@ -160,6 +160,16 @@ export const unpluginFactory: UnpluginFactory<Options> = options => ({
160
160
  if (caddy)
161
161
  return
162
162
 
163
+ let base = '/'
164
+ const publicPath = compiler.options.output?.publicPath as unknown
165
+ if (typeof publicPath === 'string' && publicPath) {
166
+ base = publicPath
167
+ }
168
+ if (!base.startsWith('/'))
169
+ base = `/${base}`
170
+ if (base !== '/' && !base.endsWith('/'))
171
+ base = `${base}/`
172
+
163
173
  // https://github.com/webpack/webpack-dev-server/blob/master/lib/Server.js#L1913
164
174
  const _close = compiler.close?.bind(compiler)
165
175
  if (_close) {
@@ -177,12 +187,13 @@ export const unpluginFactory: UnpluginFactory<Options> = options => ({
177
187
  caddy = new CaddyInstant()
178
188
 
179
189
  caddy.run(source, target, {
190
+ base,
180
191
  ...options,
181
192
  }).then(() => {
182
193
  compiler.hooks.done.tap('unplugin-https-reverse-proxy', async () => {
183
194
  await printForwardProxy()
184
195
 
185
- consola.success(` ${c.green('➜')} ${c.bold('run caddy reverse proxy success')}: ${colorUrl(`${options.https ? 'https' : 'http'}://${target}`)}`)
196
+ consola.success(` ${c.green('➜')} ${c.bold('run caddy reverse proxy success')}: ${colorUrl(`${options.https ? 'https' : 'http'}://${target}${base}`)}`)
186
197
  })
187
198
  }).catch((e) => {
188
199
  throw e
@@ -231,12 +242,23 @@ export const unpluginFactory: UnpluginFactory<Options> = options => ({
231
242
 
232
243
  caddy = new CaddyInstant()
233
244
 
245
+ let base = '/'
246
+ const publicPath = compiler.options.output?.publicPath as unknown
247
+ if (typeof publicPath === 'string' && publicPath) {
248
+ base = publicPath
249
+ }
250
+ if (!base.startsWith('/'))
251
+ base = `/${base}`
252
+ if (base !== '/' && !base.endsWith('/'))
253
+ base = `${base}/`
254
+
234
255
  caddy.run(source, target, {
256
+ base,
235
257
  ...options,
236
258
  }).then(async () => {
237
259
  await printForwardProxy()
238
260
 
239
- consola.success(` ${c.green('➜')} ${c.bold('run caddy reverse proxy success')}: ${colorUrl(`${options.https ? 'https' : 'http'}://${target}`)}`)
261
+ consola.success(` ${c.green('➜')} ${c.bold('run caddy reverse proxy success')}: ${colorUrl(`${options.https ? 'https' : 'http'}://${target}${base}`)}`)
240
262
  }).catch((e) => {
241
263
  throw e
242
264
  })
package/src/types.ts CHANGED
@@ -5,5 +5,5 @@ export interface Options {
5
5
  showCaddyLog?: boolean
6
6
  /** default `false` */
7
7
  https?: boolean
8
- health_check?: boolean
8
+ healthCheck?: boolean
9
9
  }