@witchcraft/nuxt-electron 0.2.1 → 0.2.3

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/module.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "electron",
3
3
  "configKey": "electron",
4
- "version": "0.2.1",
4
+ "version": "0.2.3",
5
5
  "builder": {
6
6
  "@nuxt/module-builder": "1.0.2",
7
7
  "unbuild": "3.6.1"
package/dist/module.mjs CHANGED
@@ -331,7 +331,7 @@ const module$1 = defineNuxtModule({
331
331
  nuxtRemoveUneededPages(nuxt, ["/", electronRoute, ...options.additionalRoutes]);
332
332
  nuxt.options.router.options ??= {};
333
333
  nuxt.options.router.options.hashMode = false;
334
- extendRouteRules(electronRoute + "/", {
334
+ extendRouteRules(electronRoute, {
335
335
  prerender: true
336
336
  }, { override: true });
337
337
  extendRouteRules(electronRoute + "/**", {
@@ -1,4 +1,6 @@
1
1
  import type { Protocol } from "electron";
2
+ export declare const cache: Map<string, string | undefined>;
3
+ export declare const proxyCache: Map<string, string | undefined>;
2
4
  export declare function createProxiedProtocolHandler(
3
5
  /** `protocol` or `session.protocol` depending on if you're using paritions with your windows or not, regular `protocol` only registers the handler for the default parition. */
4
6
  protocol: Protocol, protocolName: string | undefined, basePath: string,
@@ -7,14 +9,33 @@ protocol: Protocol, protocolName: string | undefined, basePath: string,
7
9
  *
8
10
  * At least `/api` should be added for a basic nuxt app to work correctly.
9
11
  *
12
+ * The longest key matched will be used.
10
13
  *
11
14
  * ```ts
12
15
  * routeProxies: {
13
- * "/api": "http://localhost:3000/api",
16
+ * "/api": "http://localhost:3000", // turns into http://localhost:3000/api
17
+ * // for more control, for example: to proxy /your/path to some other path while removing the /your/path part:
18
+ * "/your/path": {
19
+ * url: "http://some-site.com",
20
+ * convertPath: (proxyKey, url, requestPath) => url + requestPath.slice(proxyKey.length)
21
+ * }
22
+ * // to ignore a path
23
+ * "/ignore/some/path": {
24
+ * ignore: true
25
+ * }
14
26
  * }
15
27
  * ```
16
28
  */
17
- routeProxies: Record<string, string>, { logger, errorPage }?: {
29
+ routeProxies: Record<string, string | {
30
+ url: string;
31
+ /** Override how the path is merged with the url. The default literally just concatenates url + path. */
32
+ convertPath?: (proxyKey: string, url: string, requestPath: string) => string;
33
+ ignore?: false;
34
+ } | {
35
+ url: never;
36
+ convertPath: never;
37
+ ignore: true;
38
+ }>, { logger, errorPage }?: {
18
39
  /**
19
40
  * Optional logger. It's suggested you not pass this unless you're traceging in dev mode as a lot of requests can be made.
20
41
  */
@@ -4,33 +4,41 @@ import { net } from "electron";
4
4
  import fs from "node:fs/promises";
5
5
  import path from "node:path";
6
6
  import { pathToFileURL } from "node:url";
7
- const cache = /* @__PURE__ */ new Map();
8
- async function getPathToServe(originalPath, pathWithIndexHtml, key, logger) {
9
- if (cache.has(key)) {
10
- const result = cache.get(key);
11
- if (logger) {
12
- logger.trace({
13
- ns: "main:createProxiedProtocolHandler:cacheHit",
14
- requestUrl: key,
15
- result: cache.get(key)
16
- });
17
- }
18
- return result;
19
- }
7
+ export const cache = /* @__PURE__ */ new Map();
8
+ export const proxyCache = /* @__PURE__ */ new Map();
9
+ const proxiedProperties = ["headers", "destination", "referrer", "referrerPolicy", "mode", "credentials", "cache", "redirect", "integrity", "keepalive"];
10
+ async function getPathToServe(originalPath, pathWithIndexHtml, requestUrl, logger) {
20
11
  const stats = await fs.stat(originalPath).catch(() => void 0);
21
12
  if (logger) {
22
13
  logger.trace({
23
14
  ns: "main:createProxiedProtocolHandler:stats",
24
- key,
15
+ requestUrl,
25
16
  exists: !!stats,
26
17
  isFile: stats?.isFile(),
27
18
  isDirectory: stats?.isDirectory()
28
19
  });
29
20
  }
30
21
  const pathToServe = stats !== void 0 ? stats.isFile() ? originalPath : stats.isDirectory() ? (await fs.stat(pathWithIndexHtml).catch(() => void 0))?.isFile() ? pathWithIndexHtml : void 0 : void 0 : void 0;
31
- cache.set(key, pathToServe);
32
22
  return pathToServe;
33
23
  }
24
+ async function getFromCacheOr(cache2, key, fn, logger) {
25
+ let result = cache2.get(key);
26
+ if (result) {
27
+ if (logger) {
28
+ logger.trace({
29
+ ns: "main:createProxiedProtocolHandler:cacheHit",
30
+ requestUrl: key,
31
+ result
32
+ });
33
+ }
34
+ return result;
35
+ }
36
+ result = await fn(key);
37
+ if (result) {
38
+ cache2.set(key, result);
39
+ }
40
+ return result;
41
+ }
34
42
  export function createProxiedProtocolHandler(protocol, protocolName = "app", basePath, routeProxies, {
35
43
  logger,
36
44
  errorPage = "404.html"
@@ -46,28 +54,44 @@ export function createProxiedProtocolHandler(protocol, protocolName = "app", bas
46
54
  }
47
55
  let errorPage404;
48
56
  protocol.handle(protocolName, async (request) => {
49
- errorPage404 ??= await getPathToServe(path.join(basePath, errorPage), "404.html", "404.html", logger);
57
+ errorPage404 ??= await getFromCacheOr(cache, "404.html", (key) => getPathToServe(path.join(basePath, errorPage), "404.html", key, logger), logger);
50
58
  if (!errorPage404) {
51
59
  throw new Error(`Error page ${path.join(basePath, errorPage)} does not exist. Did you override the routeRules for it?`);
52
60
  }
53
61
  const parsedUrl = new URL(request.url);
54
62
  const requestPath = decodeURIComponent(parsedUrl.pathname);
55
- const proxyKey = routeProxyKeys.find((key) => requestPath.startsWith(key));
56
- if (proxyKey) {
57
- const proxyUrl = routeProxies[proxyKey];
58
- const finalPath2 = proxyUrl + requestPath;
63
+ const cachedProxyResult = await getFromCacheOr(proxyCache, requestPath, (_) => {
64
+ const matchedProxyKeys = routeProxyKeys.filter((key) => requestPath.startsWith(key));
65
+ const proxyKey = matchedProxyKeys.sort((a, b) => b.length - a.length)[0];
66
+ const proxyEntry = proxyKey && routeProxies[proxyKey];
67
+ if (proxyKey && proxyEntry && !(typeof proxyEntry === "object" && proxyEntry?.ignore)) {
68
+ const proxyUrl = typeof proxyEntry === "string" ? proxyEntry : proxyEntry?.url;
69
+ const finalPath2 = typeof proxyEntry === "object" && proxyEntry?.convertPath ? proxyEntry.convertPath(proxyKey, proxyUrl, requestPath) : proxyUrl + requestPath;
70
+ if (logger) {
71
+ logger.trace({
72
+ ns: "main:createProxiedProtocolHandler:fetchingViaProxy",
73
+ requestUrl: request.url,
74
+ proxyKey,
75
+ route: proxyUrl,
76
+ requestPath,
77
+ finalPath: finalPath2
78
+ });
79
+ }
80
+ return finalPath2;
81
+ }
82
+ return void 0;
83
+ });
84
+ if (cachedProxyResult) {
59
85
  if (logger) {
60
86
  logger.trace({
61
- ns: "main:createProxiedProtocolHandler:fetchingViaProxy",
87
+ ns: "main:createProxiedProtocolHandler:fetchingViaProxy(cached)",
62
88
  requestUrl: request.url,
63
- proxyKey,
64
- route: proxyUrl,
65
89
  requestPath,
66
- finalPath: finalPath2
90
+ finalPath: cachedProxyResult
67
91
  });
68
92
  }
69
- return net.fetch(finalPath2, {
70
- ...pick(request, ["headers", "destination", "referrer", "referrerPolicy", "mode", "credentials", "cache", "redirect", "integrity", "keepalive"])
93
+ return net.fetch(cachedProxyResult, {
94
+ ...pick(request, proxiedProperties)
71
95
  });
72
96
  }
73
97
  const originalPath = path.join(basePath, requestPath);
@@ -107,7 +131,7 @@ export function createProxiedProtocolHandler(protocol, protocolName = "app", bas
107
131
  status: 400
108
132
  });
109
133
  }
110
- const pathToServe = await getPathToServe(originalPath, pathWithIndexHtml, request.url, logger);
134
+ const pathToServe = await getFromCacheOr(cache, request.url, (key) => getPathToServe(originalPath, pathWithIndexHtml, key, logger), logger);
111
135
  if (!pathToServe) {
112
136
  if (logger) {
113
137
  logger.error({
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@witchcraft/nuxt-electron",
3
- "version": "0.2.1",
3
+ "version": "0.2.3",
4
4
  "description": "Nuxt module for working with electron.",
5
5
  "repository": "https://github.com/witchcraftjs/nuxt-electron",
6
6
  "license": "MIT",
package/src/module.ts CHANGED
@@ -522,7 +522,7 @@ export default defineNuxtModule<ModuleOptions>({
522
522
  nuxt.options.router.options.hashMode = false
523
523
 
524
524
  // its not a smart merge or anything, so we need to override both possibilities
525
- extendRouteRules(electronRoute + "/", {
525
+ extendRouteRules(electronRoute, {
526
526
  prerender: true
527
527
  }, { override: true })
528
528
 
@@ -7,35 +7,24 @@ import path from "node:path"
7
7
  import { pathToFileURL } from "node:url"
8
8
 
9
9
 
10
- const cache = new Map<string, string | undefined>()
10
+ export const cache = new Map<string, string | undefined>()
11
+ export const proxyCache = new Map<string, string | undefined>()
12
+ const proxiedProperties: (keyof Request)[] = ["headers", "destination", "referrer", "referrerPolicy", "mode", "credentials", "cache", "redirect", "integrity", "keepalive"]
11
13
 
12
14
  async function getPathToServe(
13
15
  originalPath: string,
14
16
  pathWithIndexHtml: string,
15
- /** Usually the request url */
16
- key: string,
17
+ requestUrl: string,
17
18
  logger?: {
18
19
  trace: (...args: any[]) => void
19
20
  }
20
21
  ) {
21
- if (cache.has(key)) {
22
- const result = cache.get(key)
23
- if (logger) {
24
- logger.trace({
25
- ns: "main:createProxiedProtocolHandler:cacheHit",
26
- requestUrl: key,
27
- result: cache.get(key)
28
- })
29
- }
30
- return result
31
- }
32
22
  const stats = await fs.stat(originalPath).catch(() => undefined)
33
23
 
34
-
35
24
  if (logger) {
36
25
  logger.trace({
37
26
  ns: "main:createProxiedProtocolHandler:stats",
38
- key,
27
+ requestUrl,
39
28
  exists: !!stats,
40
29
  isFile: stats?.isFile(),
41
30
  isDirectory: stats?.isDirectory()
@@ -51,9 +40,28 @@ async function getPathToServe(
51
40
  : undefined
52
41
  : undefined
53
42
  : undefined
54
- cache.set(key, pathToServe)
55
43
  return pathToServe
56
44
  }
45
+
46
+ async function getFromCacheOr(cache: Map<string, string | undefined>, key: string, fn: (key: string) => Promise<string | undefined> | string | undefined, logger?: { trace: (...args: any[]) => void }): Promise<string | undefined> {
47
+ let result = cache.get(key)
48
+ if (result) {
49
+ if (logger) {
50
+ logger.trace({
51
+ ns: "main:createProxiedProtocolHandler:cacheHit",
52
+ requestUrl: key,
53
+ result
54
+ })
55
+ }
56
+ return result
57
+ }
58
+ result = await fn(key)
59
+ if (result) {
60
+ cache.set(key, result)
61
+ }
62
+ return result
63
+ }
64
+
57
65
  export function createProxiedProtocolHandler(
58
66
  /** `protocol` or `session.protocol` depending on if you're using paritions with your windows or not, regular `protocol` only registers the handler for the default parition. */
59
67
  protocol: Protocol,
@@ -64,14 +72,38 @@ export function createProxiedProtocolHandler(
64
72
  *
65
73
  * At least `/api` should be added for a basic nuxt app to work correctly.
66
74
  *
75
+ * The longest key matched will be used.
67
76
  *
68
77
  * ```ts
69
78
  * routeProxies: {
70
- * "/api": "http://localhost:3000/api",
79
+ * "/api": "http://localhost:3000", // turns into http://localhost:3000/api
80
+ * // for more control, for example: to proxy /your/path to some other path while removing the /your/path part:
81
+ * "/your/path": {
82
+ * url: "http://some-site.com",
83
+ * convertPath: (proxyKey, url, requestPath) => url + requestPath.slice(proxyKey.length)
84
+ * }
85
+ * // to ignore a path
86
+ * "/ignore/some/path": {
87
+ * ignore: true
88
+ * }
71
89
  * }
72
90
  * ```
73
91
  */
74
- routeProxies: Record<string, string>,
92
+ routeProxies: Record<
93
+ string,
94
+ | string
95
+ | {
96
+ url: string
97
+ /** Override how the path is merged with the url. The default literally just concatenates url + path. */
98
+ convertPath?: (proxyKey: string, url: string, requestPath: string) => string
99
+ ignore?: false
100
+ }
101
+ | {
102
+ url: never
103
+ convertPath: never
104
+ ignore: true
105
+ }
106
+ >,
75
107
  {
76
108
  logger,
77
109
  errorPage = "404.html"
@@ -108,7 +140,7 @@ export function createProxiedProtocolHandler(
108
140
  // to check the user correctly registered it
109
141
  // it's deprecated for some reason and also it doesn't work (so maybe because of that)!
110
142
  protocol.handle(protocolName, async request => {
111
- errorPage404 ??= await getPathToServe(path.join(basePath, errorPage), "404.html", "404.html", logger)
143
+ errorPage404 ??= await getFromCacheOr(cache, "404.html", key => getPathToServe(path.join(basePath, errorPage), "404.html", key, logger), logger)
112
144
 
113
145
  if (!errorPage404) {
114
146
  throw new Error(`Error page ${path.join(basePath, errorPage)} does not exist. Did you override the routeRules for it?`)
@@ -118,23 +150,45 @@ export function createProxiedProtocolHandler(
118
150
  // we can ignore the host, as getPaths sets it to bundle (e.g. protocol://bundle/path/to/file)
119
151
  const requestPath = decodeURIComponent(parsedUrl.pathname)
120
152
 
121
- const proxyKey = routeProxyKeys.find(key => requestPath.startsWith(key))
122
153
 
123
- if (proxyKey) {
124
- const proxyUrl = routeProxies[proxyKey]
125
- const finalPath = proxyUrl + requestPath
154
+ // this must be on a seperate cache because the result and key are different since fetching is different
155
+ const cachedProxyResult = await getFromCacheOr(proxyCache, requestPath, _ /* requestPath */ => {
156
+ const matchedProxyKeys = routeProxyKeys.filter(key => requestPath.startsWith(key))
157
+ const proxyKey = matchedProxyKeys.sort((a, b) => b.length - a.length)[0]
158
+
159
+ const proxyEntry = proxyKey && routeProxies[proxyKey]
160
+ if (proxyKey && proxyEntry && !(typeof proxyEntry === "object" && proxyEntry?.ignore)) {
161
+ const proxyUrl = typeof proxyEntry === "string" ? proxyEntry : proxyEntry?.url
162
+
163
+ const finalPath = typeof proxyEntry === "object" && proxyEntry?.convertPath
164
+ ? proxyEntry.convertPath(proxyKey, proxyUrl, requestPath)
165
+ : proxyUrl + requestPath
166
+
167
+ if (logger) {
168
+ logger.trace({
169
+ ns: "main:createProxiedProtocolHandler:fetchingViaProxy",
170
+ requestUrl: request.url,
171
+ proxyKey,
172
+ route: proxyUrl,
173
+ requestPath,
174
+ finalPath
175
+ })
176
+ }
177
+ return finalPath
178
+ }
179
+ return undefined
180
+ })
181
+ if (cachedProxyResult) {
126
182
  if (logger) {
127
183
  logger.trace({
128
- ns: "main:createProxiedProtocolHandler:fetchingViaProxy",
184
+ ns: "main:createProxiedProtocolHandler:fetchingViaProxy(cached)",
129
185
  requestUrl: request.url,
130
- proxyKey,
131
- route: proxyUrl,
132
186
  requestPath,
133
- finalPath
187
+ finalPath: cachedProxyResult
134
188
  })
135
189
  }
136
- return net.fetch(finalPath, {
137
- ...pick(request, ["headers", "destination", "referrer", "referrerPolicy", "mode", "credentials", "cache", "redirect", "integrity", "keepalive"])
190
+ return net.fetch(cachedProxyResult, {
191
+ ...pick(request, proxiedProperties)
138
192
  })
139
193
  }
140
194
 
@@ -173,7 +227,7 @@ export function createProxiedProtocolHandler(
173
227
  }
174
228
 
175
229
 
176
- const pathToServe = await getPathToServe(originalPath, pathWithIndexHtml, request.url, logger)
230
+ const pathToServe = await getFromCacheOr(cache, request.url, key => getPathToServe(originalPath, pathWithIndexHtml, key, logger), logger)
177
231
 
178
232
  if (!pathToServe) {
179
233
  if (logger) {