@olenbetong/appframe-vite 4.1.4 → 4.1.6

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.
Files changed (2) hide show
  1. package/lib/devServer.js +90 -65
  2. package/package.json +3 -7
package/lib/devServer.js CHANGED
@@ -54,66 +54,85 @@ 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 {
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
+ let mainScriptAdded = false;
73
+ dom.window.document.querySelectorAll("script").forEach((script) => {
74
+ if (script.src?.startsWith(`/file/article/script/${article}/main`)) {
75
+ let mainScript = dom.window.document.createElement("script");
76
+ mainScript.type = "module";
77
+ mainScript.src = entry;
78
+ script.insertAdjacentElement("beforebegin", mainScript);
79
+ nodesToRemove.push(script);
80
+ mainScriptAdded = true;
81
+ }
82
+ else if (script.src?.includes("bugsnag")) {
83
+ nodesToRemove.push(script);
84
+ }
85
+ else if (script.textContent?.includes("bugsnagOptions") ||
86
+ script.textContent?.includes("web-vitals") ||
87
+ script.textContent?.includes("serviceWorker.register")) {
88
+ nodesToRemove.push(script);
89
+ }
90
+ else if (script.textContent?.includes("af.article.i18n")) {
91
+ // There will be lots of strings that will be translated in dev, but not in production (e.g. grid localization for apps without grid),
92
+ // which means the strings will not be in the base strings. Since the dev server runs on HTTP 1, this causes lots
93
+ // of slow HTTP requests. To fix this, we cache them locally, and inject them here.
94
+ let cachedStrings = getStringCache();
95
+ let localizeScript = dom.window.document.createElement("script");
96
+ localizeScript.textContent = `Object.assign(af.article.i18n, ${JSON.stringify(cachedStrings)})`;
97
+ script.insertAdjacentElement("afterend", localizeScript);
98
+ }
99
+ });
100
+ if (!mainScriptAdded) {
101
+ let mainScript = dom.window.document.createElement("script");
102
+ mainScript.type = "module";
103
+ mainScript.src = entry;
104
+ dom.window.document.body.appendChild(mainScript);
105
+ }
106
+ dom.window.document.querySelectorAll("link").forEach((link) => {
107
+ if (link.rel === "stylesheet" && link.href?.startsWith(`/file/article/style/${article}`)) {
108
+ nodesToRemove.push(link);
109
+ }
110
+ else if (link.rel === "prefetch" && link.href?.startsWith(`/file/article`)) {
111
+ nodesToRemove.push(link);
112
+ }
113
+ });
114
+ nodesToRemove.forEach((node) => node.remove());
115
+ dom.window.document.querySelectorAll("a").forEach((anchor) => {
116
+ if (anchor.href?.startsWith("/") && !anchor.href?.startsWith(`/${article}`)) {
117
+ anchor.href = `https://${hostname}${anchor.href}`;
118
+ }
119
+ });
120
+ return dom.serialize();
121
+ }
57
122
  async function getArticleHtml() {
58
123
  let { hostname, username, password } = await getLoginInfo();
59
124
  let article = appframe.article?.id;
125
+ console.log(hostname);
60
126
  let client = new Client(hostname);
61
- await client.login(username, password);
127
+ console.log(article);
128
+ let re = await client.login(username, password);
129
+ console.log("login", username, password, re);
62
130
  let response = await client.afFetch(`/${article}`, {
63
131
  timeout: 30000,
64
132
  });
133
+ console.log("afFetch", response.status);
65
134
  if (response.ok) {
66
- let html = await response.text();
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();
135
+ return await response.text();
117
136
  }
118
137
  throw Error(`Failed to get article '${article}' from '${hostname}': ${response.status} ${response.statusText}`);
119
138
  }
@@ -134,6 +153,22 @@ async function getCachedHtml(age) {
134
153
  }
135
154
  return "";
136
155
  }
156
+ async function getCachedOrArticleHtml(skipCache = false) {
157
+ let html = "";
158
+ let age = Math.round(await getCacheAge());
159
+ if (!skipCache && age > 0) {
160
+ html = await getCachedHtml(age);
161
+ }
162
+ if (!html) {
163
+ html = await getArticleHtml();
164
+ if (!(await exists(cacheFile))) {
165
+ await mkdir(cachePath, { recursive: true });
166
+ }
167
+ await writeFile(cacheFile, html, { encoding: "utf-8" });
168
+ age = 0;
169
+ }
170
+ return { age, html };
171
+ }
137
172
  export function createDevMiddleware(vite) {
138
173
  return async (req, res, next) => {
139
174
  const url = req.originalUrl;
@@ -147,19 +182,9 @@ export function createDevMiddleware(vite) {
147
182
  // Unless the browser is explicitly disabling cache by setting the Cache-Control header
148
183
  // to "no-cache", we cache the generated HTML for up to 3 hours
149
184
  let cacheControl = req.headers["cache-control"];
150
- let html = "";
151
- let age = await getCacheAge();
152
- if (cacheControl !== "no-cache" && age > 0) {
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
- }
185
+ let { age, html } = await getCachedOrArticleHtml(cacheControl === "no-cache");
186
+ html = await transformArticleHtml(html);
187
+ html = await vite.transformIndexHtml(url ?? "", html);
163
188
  res.statusCode = 200;
164
189
  res.setHeader("Content-Type", "text/html");
165
190
  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.4",
3
+ "version": "4.1.6",
4
4
  "description": "Tools to use and deploy Vite applications to Appframe",
5
5
  "main": "./lib/index.js",
6
6
  "type": "module",
@@ -19,7 +19,7 @@
19
19
  "author": "Bjørnar Vister Hansen <bvh@olenbetong.no>",
20
20
  "license": "MIT",
21
21
  "dependencies": {
22
- "@olenbetong/appframe-data": "0.9.2",
22
+ "@olenbetong/appframe-data": "0.9.3",
23
23
  "body-parser": "^1.20.2",
24
24
  "chalk": "^5.3.0",
25
25
  "chokidar": "^3.5.3",
@@ -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": "fc463924fd3a7f311117211430dbf7d40c9c3149"
43
+ "gitHead": "54e7bf8d61f5f3ada6a635175d6c6fa564b2e62b"
48
44
  }