@olenbetong/appframe-vite 4.1.4 → 4.1.5
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/lib/devServer.js +77 -64
- package/package.json +2 -6
package/lib/devServer.js
CHANGED
|
@@ -54,6 +54,63 @@ export function getProxyRoutes() {
|
|
|
54
54
|
* - Add the hostname to links with absolute paths (they are not part of the application, and will fail without host)
|
|
55
55
|
* @returns
|
|
56
56
|
*/
|
|
57
|
+
async function transformArticleHtml(html) {
|
|
58
|
+
let entry;
|
|
59
|
+
if (await exists(resolve(process.cwd(), "./src/index.tsx"))) {
|
|
60
|
+
entry = "/src/index.tsx";
|
|
61
|
+
}
|
|
62
|
+
else if (await exists(resolve(process.cwd(), "./src/index.ts"))) {
|
|
63
|
+
entry = "/src/index.ts";
|
|
64
|
+
}
|
|
65
|
+
else if (await exists(resolve(process.cwd(), "./src/index.js"))) {
|
|
66
|
+
entry = "/src/index.js";
|
|
67
|
+
}
|
|
68
|
+
let article = appframe.article?.id;
|
|
69
|
+
let { hostname } = await getLoginInfo();
|
|
70
|
+
let dom = new JSDOM(html);
|
|
71
|
+
let nodesToRemove = [];
|
|
72
|
+
dom.window.document.querySelectorAll("script").forEach((script) => {
|
|
73
|
+
if (script.src?.startsWith(`/file/article/script/${article}/main`)) {
|
|
74
|
+
let mainScript = dom.window.document.createElement("script");
|
|
75
|
+
mainScript.type = "module";
|
|
76
|
+
mainScript.src = entry;
|
|
77
|
+
script.insertAdjacentElement("beforebegin", mainScript);
|
|
78
|
+
nodesToRemove.push(script);
|
|
79
|
+
}
|
|
80
|
+
else if (script.src?.includes("bugsnag")) {
|
|
81
|
+
nodesToRemove.push(script);
|
|
82
|
+
}
|
|
83
|
+
else if (script.textContent?.includes("bugsnagOptions") ||
|
|
84
|
+
script.textContent?.includes("web-vitals") ||
|
|
85
|
+
script.textContent?.includes("serviceWorker.register")) {
|
|
86
|
+
nodesToRemove.push(script);
|
|
87
|
+
}
|
|
88
|
+
else if (script.textContent?.includes("af.article.i18n")) {
|
|
89
|
+
// There will be lots of strings that will be translated in dev, but not in production (e.g. grid localization for apps without grid),
|
|
90
|
+
// which means the strings will not be in the base strings. Since the dev server runs on HTTP 1, this causes lots
|
|
91
|
+
// of slow HTTP requests. To fix this, we cache them locally, and inject them here.
|
|
92
|
+
let cachedStrings = getStringCache();
|
|
93
|
+
let localizeScript = dom.window.document.createElement("script");
|
|
94
|
+
localizeScript.textContent = `Object.assign(af.article.i18n, ${JSON.stringify(cachedStrings)})`;
|
|
95
|
+
script.insertAdjacentElement("afterend", localizeScript);
|
|
96
|
+
}
|
|
97
|
+
});
|
|
98
|
+
dom.window.document.querySelectorAll("link").forEach((link) => {
|
|
99
|
+
if (link.rel === "stylesheet" && link.href?.startsWith(`/file/article/style/${article}`)) {
|
|
100
|
+
nodesToRemove.push(link);
|
|
101
|
+
}
|
|
102
|
+
else if (link.rel === "prefetch" && link.href?.startsWith(`/file/article`)) {
|
|
103
|
+
nodesToRemove.push(link);
|
|
104
|
+
}
|
|
105
|
+
});
|
|
106
|
+
nodesToRemove.forEach((node) => node.remove());
|
|
107
|
+
dom.window.document.querySelectorAll("a").forEach((anchor) => {
|
|
108
|
+
if (anchor.href?.startsWith("/") && !anchor.href?.startsWith(`/${article}`)) {
|
|
109
|
+
anchor.href = `https://${hostname}${anchor.href}`;
|
|
110
|
+
}
|
|
111
|
+
});
|
|
112
|
+
return dom.serialize();
|
|
113
|
+
}
|
|
57
114
|
async function getArticleHtml() {
|
|
58
115
|
let { hostname, username, password } = await getLoginInfo();
|
|
59
116
|
let article = appframe.article?.id;
|
|
@@ -63,57 +120,7 @@ async function getArticleHtml() {
|
|
|
63
120
|
timeout: 30000,
|
|
64
121
|
});
|
|
65
122
|
if (response.ok) {
|
|
66
|
-
|
|
67
|
-
let entry;
|
|
68
|
-
if (await exists(resolve(process.cwd(), "./src/index.tsx"))) {
|
|
69
|
-
entry = "/src/index.tsx";
|
|
70
|
-
}
|
|
71
|
-
else if (await exists(resolve(process.cwd(), "./src/index.ts"))) {
|
|
72
|
-
entry = "/src/index.ts";
|
|
73
|
-
}
|
|
74
|
-
else if (await exists(resolve(process.cwd(), "./src/index.js"))) {
|
|
75
|
-
entry = "/src/index.js";
|
|
76
|
-
}
|
|
77
|
-
let dom = new JSDOM(html);
|
|
78
|
-
let nodesToRemove = [];
|
|
79
|
-
dom.window.document.querySelectorAll("script").forEach((script) => {
|
|
80
|
-
if (script.src?.startsWith(`/file/article/script/${article}/main`)) {
|
|
81
|
-
let mainScript = dom.window.document.createElement("script");
|
|
82
|
-
mainScript.type = "module";
|
|
83
|
-
mainScript.src = entry;
|
|
84
|
-
script.insertAdjacentElement("beforebegin", mainScript);
|
|
85
|
-
nodesToRemove.push(script);
|
|
86
|
-
}
|
|
87
|
-
else if (script.src?.includes("bugsnag")) {
|
|
88
|
-
nodesToRemove.push(script);
|
|
89
|
-
}
|
|
90
|
-
else if (script.textContent?.includes("bugsnagOptions") ||
|
|
91
|
-
script.textContent?.includes("web-vitals") ||
|
|
92
|
-
script.textContent?.includes("serviceWorker.register")) {
|
|
93
|
-
nodesToRemove.push(script);
|
|
94
|
-
}
|
|
95
|
-
else if (script.textContent?.includes("af.article.i18n")) {
|
|
96
|
-
let cachedStrings = getStringCache();
|
|
97
|
-
let localizeScript = dom.window.document.createElement("script");
|
|
98
|
-
localizeScript.textContent = `Object.assign(af.article.i18n, ${JSON.stringify(cachedStrings)})`;
|
|
99
|
-
script.insertAdjacentElement("afterend", localizeScript);
|
|
100
|
-
}
|
|
101
|
-
});
|
|
102
|
-
dom.window.document.querySelectorAll("link").forEach((link) => {
|
|
103
|
-
if (link.rel === "stylesheet" && link.href?.startsWith(`/file/article/style/${article}`)) {
|
|
104
|
-
nodesToRemove.push(link);
|
|
105
|
-
}
|
|
106
|
-
else if (link.rel === "prefetch" && link.href?.startsWith(`/file/article`)) {
|
|
107
|
-
nodesToRemove.push(link);
|
|
108
|
-
}
|
|
109
|
-
});
|
|
110
|
-
nodesToRemove.forEach((node) => node.remove());
|
|
111
|
-
dom.window.document.querySelectorAll("a").forEach((anchor) => {
|
|
112
|
-
if (anchor.href?.startsWith("/") && !anchor.href?.startsWith(`/${article}`)) {
|
|
113
|
-
anchor.href = `https://${hostname}${anchor.href}`;
|
|
114
|
-
}
|
|
115
|
-
});
|
|
116
|
-
return dom.serialize();
|
|
123
|
+
return await response.text();
|
|
117
124
|
}
|
|
118
125
|
throw Error(`Failed to get article '${article}' from '${hostname}': ${response.status} ${response.statusText}`);
|
|
119
126
|
}
|
|
@@ -134,6 +141,22 @@ async function getCachedHtml(age) {
|
|
|
134
141
|
}
|
|
135
142
|
return "";
|
|
136
143
|
}
|
|
144
|
+
async function getCachedOrArticleHtml(skipCache = false) {
|
|
145
|
+
let html = "";
|
|
146
|
+
let age = Math.round(await getCacheAge());
|
|
147
|
+
if (!skipCache && age > 0) {
|
|
148
|
+
html = await getCachedHtml(age);
|
|
149
|
+
}
|
|
150
|
+
if (!html) {
|
|
151
|
+
html = await getArticleHtml();
|
|
152
|
+
if (!(await exists(cacheFile))) {
|
|
153
|
+
await mkdir(cachePath, { recursive: true });
|
|
154
|
+
}
|
|
155
|
+
await writeFile(cacheFile, html, { encoding: "utf-8" });
|
|
156
|
+
age = 0;
|
|
157
|
+
}
|
|
158
|
+
return { age, html };
|
|
159
|
+
}
|
|
137
160
|
export function createDevMiddleware(vite) {
|
|
138
161
|
return async (req, res, next) => {
|
|
139
162
|
const url = req.originalUrl;
|
|
@@ -147,19 +170,9 @@ export function createDevMiddleware(vite) {
|
|
|
147
170
|
// Unless the browser is explicitly disabling cache by setting the Cache-Control header
|
|
148
171
|
// to "no-cache", we cache the generated HTML for up to 3 hours
|
|
149
172
|
let cacheControl = req.headers["cache-control"];
|
|
150
|
-
let html = "";
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
html = await getCachedHtml(age);
|
|
154
|
-
}
|
|
155
|
-
if (!html) {
|
|
156
|
-
html = await getArticleHtml();
|
|
157
|
-
html = await vite.transformIndexHtml(url ?? "", html);
|
|
158
|
-
if (!(await exists(cacheFile))) {
|
|
159
|
-
await mkdir(cachePath, { recursive: true });
|
|
160
|
-
}
|
|
161
|
-
await writeFile(cacheFile, html, { encoding: "utf-8" });
|
|
162
|
-
}
|
|
173
|
+
let { age, html } = await getCachedOrArticleHtml(cacheControl === "no-cache");
|
|
174
|
+
html = await transformArticleHtml(html);
|
|
175
|
+
html = await vite.transformIndexHtml(url ?? "", html);
|
|
163
176
|
res.statusCode = 200;
|
|
164
177
|
res.setHeader("Content-Type", "text/html");
|
|
165
178
|
res.setHeader("Cache-Control", "max-age=10800000");
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@olenbetong/appframe-vite",
|
|
3
|
-
"version": "4.1.
|
|
3
|
+
"version": "4.1.5",
|
|
4
4
|
"description": "Tools to use and deploy Vite applications to Appframe",
|
|
5
5
|
"main": "./lib/index.js",
|
|
6
6
|
"type": "module",
|
|
@@ -33,16 +33,12 @@
|
|
|
33
33
|
"typescript": "^5.1.6"
|
|
34
34
|
},
|
|
35
35
|
"peerDependencies": {
|
|
36
|
-
"express": "^4.18.2",
|
|
37
36
|
"vite": "^4.4.9"
|
|
38
37
|
},
|
|
39
38
|
"optionalDependencies": {
|
|
40
|
-
"@types/express": "^4.17.17",
|
|
41
|
-
"@types/express-http-proxy": "^1.6.3",
|
|
42
39
|
"@types/tcp-port-used": "^1.0.1",
|
|
43
|
-
"express-http-proxy": "^1.6.3",
|
|
44
40
|
"open": "^9.1.0",
|
|
45
41
|
"tcp-port-used": "^1.0.2"
|
|
46
42
|
},
|
|
47
|
-
"gitHead": "
|
|
43
|
+
"gitHead": "c0fd9902c79c03be9d7234195845896012616789"
|
|
48
44
|
}
|