evolit 0.1.0-alpha.5 → 0.1.0-alpha.7
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/package.json +3 -2
- package/src/build.js +6 -2
- package/src/client-assets.js +22 -0
- package/src/deployment-runtime.js +6 -2
- package/src/server.js +42 -24
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "evolit",
|
|
3
|
-
"version": "0.1.0-alpha.
|
|
3
|
+
"version": "0.1.0-alpha.7",
|
|
4
4
|
"description": "A convention-driven application framework for LitSX and web components.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"packageManager": "yarn@4.10.3",
|
|
@@ -55,7 +55,8 @@
|
|
|
55
55
|
"lit": "^3.3.3",
|
|
56
56
|
"magic-string": "^1.1.0",
|
|
57
57
|
"rollup": "^4.46.1",
|
|
58
|
-
"typescript": "^6.0.0"
|
|
58
|
+
"typescript": "^6.0.0",
|
|
59
|
+
"ws": "^8.18.3"
|
|
59
60
|
},
|
|
60
61
|
"devDependencies": {
|
|
61
62
|
"vite": "^8.1.5"
|
package/src/build.js
CHANGED
|
@@ -15,6 +15,7 @@ import {
|
|
|
15
15
|
emitBundledClientAssets,
|
|
16
16
|
emitHashedClientAssets,
|
|
17
17
|
normalizeHydrationDataForClient,
|
|
18
|
+
resolveRouteClientImports,
|
|
18
19
|
resolveSharedVendorModuleUrl,
|
|
19
20
|
rewriteHydrationDataScript,
|
|
20
21
|
rewriteServerAssetPlaceholders,
|
|
@@ -241,8 +242,11 @@ export async function buildProject(projectRoot) {
|
|
|
241
242
|
);
|
|
242
243
|
const ssrAdapter = createSsrAdapter({
|
|
243
244
|
assetResolver,
|
|
244
|
-
async resolveAdditionalHead({ result }) {
|
|
245
|
-
const clientImports =
|
|
245
|
+
async resolveAdditionalHead({ routeResult, result }) {
|
|
246
|
+
const clientImports = [
|
|
247
|
+
...(Array.isArray(result.clientImports) ? result.clientImports : []),
|
|
248
|
+
...resolveRouteClientImports(routeResult, projectRoot, clientAssets),
|
|
249
|
+
];
|
|
246
250
|
const urls = collectTransitiveAssetPreloads(clientImports, clientAssets);
|
|
247
251
|
const styleUrls = collectTransitiveStyleUrls(clientImports, clientAssets);
|
|
248
252
|
|
package/src/client-assets.js
CHANGED
|
@@ -1776,6 +1776,28 @@ export function collectTransitiveAssetPreloads(publicUrls, assetManifest) {
|
|
|
1776
1776
|
return discovered;
|
|
1777
1777
|
}
|
|
1778
1778
|
|
|
1779
|
+
export function resolveRouteClientImports(routeResult, projectRoot, assetManifest) {
|
|
1780
|
+
const normalizedManifest = normalizeClientAssetManifest(assetManifest);
|
|
1781
|
+
if (!normalizedManifest) {
|
|
1782
|
+
return [];
|
|
1783
|
+
}
|
|
1784
|
+
|
|
1785
|
+
const routeModules = [
|
|
1786
|
+
routeResult?.route?.page,
|
|
1787
|
+
...(routeResult?.route?.layouts ?? []),
|
|
1788
|
+
routeResult?.boundaryModule,
|
|
1789
|
+
].filter((modulePath) => typeof modulePath === "string");
|
|
1790
|
+
|
|
1791
|
+
return [...new Set(routeModules.map((modulePath) => {
|
|
1792
|
+
const relativePath = path.relative(projectRoot, modulePath).split(path.sep).join("/");
|
|
1793
|
+
const extension = path.extname(relativePath);
|
|
1794
|
+
const clientModule = extension
|
|
1795
|
+
? `${relativePath.slice(0, -extension.length)}.mjs`
|
|
1796
|
+
: `${relativePath}.mjs`;
|
|
1797
|
+
return normalizedManifest.byClientModule[clientModule] ?? null;
|
|
1798
|
+
}).filter((publicUrl) => typeof publicUrl === "string"))];
|
|
1799
|
+
}
|
|
1800
|
+
|
|
1779
1801
|
export function collectTransitiveStyleUrls(publicUrls, assetManifest) {
|
|
1780
1802
|
const normalizedManifest = normalizeClientAssetManifest(assetManifest);
|
|
1781
1803
|
if (!normalizedManifest) {
|
|
@@ -12,6 +12,7 @@ import {
|
|
|
12
12
|
getSharedOutputRoot,
|
|
13
13
|
normalizeHydrationDataForClient,
|
|
14
14
|
normalizeClientAssetManifest,
|
|
15
|
+
resolveRouteClientImports,
|
|
15
16
|
resolveSharedVendorModuleUrl,
|
|
16
17
|
resolveBrowserPackageAssetFilePath,
|
|
17
18
|
rewriteHydrationDataScript,
|
|
@@ -233,8 +234,11 @@ export async function createRequestRenderer({ projectRoot, mode, assetManifest,
|
|
|
233
234
|
assetResolver(moduleId) {
|
|
234
235
|
return currentAssetResolver(moduleId);
|
|
235
236
|
},
|
|
236
|
-
async resolveAdditionalHead({ result }) {
|
|
237
|
-
const clientImports =
|
|
237
|
+
async resolveAdditionalHead({ routeResult, result }) {
|
|
238
|
+
const clientImports = [
|
|
239
|
+
...(Array.isArray(result.clientImports) ? result.clientImports : []),
|
|
240
|
+
...resolveRouteClientImports(routeResult, projectRoot, currentAssetManifest),
|
|
241
|
+
];
|
|
238
242
|
const urls = currentAssetManifest
|
|
239
243
|
? collectTransitiveAssetPreloads(clientImports, currentAssetManifest)
|
|
240
244
|
: [];
|
package/src/server.js
CHANGED
|
@@ -2,6 +2,7 @@ import http from "node:http";
|
|
|
2
2
|
import { watch } from "node:fs";
|
|
3
3
|
import fs from "node:fs/promises";
|
|
4
4
|
import path from "node:path";
|
|
5
|
+
import { WebSocketServer, WebSocket } from "ws";
|
|
5
6
|
import { loadEvolitConfig } from "./config.js";
|
|
6
7
|
import { createDeploymentRuntime } from "./deployment-runtime.js";
|
|
7
8
|
import { APP_DIRECTORY, BUILD_DIRECTORY, INTERNAL_DIRECTORY, MANIFEST_FILENAME } from "./constants.js";
|
|
@@ -36,7 +37,6 @@ async function writeResponseBody(response, body) {
|
|
|
36
37
|
}
|
|
37
38
|
|
|
38
39
|
const LIVE_RELOAD_PATHNAME = "/_evolit/live-reload";
|
|
39
|
-
const LIVE_RELOAD_SNIPPET = `<script data-evolit-live-reload>if (typeof EventSource !== "undefined") { const source = new EventSource(${JSON.stringify(LIVE_RELOAD_PATHNAME)}); source.addEventListener("reload", () => window.location.reload()); }</script>`;
|
|
40
40
|
|
|
41
41
|
function getResponseHeader(headers, name) {
|
|
42
42
|
if (headers?.get) {
|
|
@@ -57,11 +57,15 @@ function injectLiveReloadSnippet(response) {
|
|
|
57
57
|
return {
|
|
58
58
|
...response,
|
|
59
59
|
body: response.body.includes("</body>")
|
|
60
|
-
? response.body.replace("</body>", `${
|
|
61
|
-
: `${response.body}${
|
|
60
|
+
? response.body.replace("</body>", `${createLiveReloadSnippet()}</body>`)
|
|
61
|
+
: `${response.body}${createLiveReloadSnippet()}`,
|
|
62
62
|
};
|
|
63
63
|
}
|
|
64
64
|
|
|
65
|
+
function createLiveReloadSnippet() {
|
|
66
|
+
return `<script data-evolit-live-reload>const evolitProtocol=window.location.protocol==="https:"?"wss:":"ws:";const evolitSocket=new WebSocket(evolitProtocol+"//"+window.location.host+${JSON.stringify(LIVE_RELOAD_PATHNAME)});evolitSocket.addEventListener("message",({data})=>{if(data==="reload")window.location.reload()});</script>`;
|
|
67
|
+
}
|
|
68
|
+
|
|
65
69
|
async function createRecursiveDirectoryWatcher(rootDirectory, onChange) {
|
|
66
70
|
const watchers = new Map();
|
|
67
71
|
let closed = false;
|
|
@@ -149,7 +153,14 @@ async function createServer(projectRoot, mode, explicitPort, options = {}) {
|
|
|
149
153
|
responseCacheRuntime,
|
|
150
154
|
});
|
|
151
155
|
const port = getPort(explicitPort);
|
|
152
|
-
const
|
|
156
|
+
const liveReloadServer = mode === "development" ? new WebSocketServer({ noServer: true }) : null;
|
|
157
|
+
const liveReloadSockets = new Set();
|
|
158
|
+
liveReloadServer?.on("connection", (socket) => {
|
|
159
|
+
liveReloadSockets.add(socket);
|
|
160
|
+
socket.on("close", () => {
|
|
161
|
+
liveReloadSockets.delete(socket);
|
|
162
|
+
});
|
|
163
|
+
});
|
|
153
164
|
let invalidationTimer = null;
|
|
154
165
|
let pendingInvalidation = null;
|
|
155
166
|
let resolvePendingInvalidation = null;
|
|
@@ -176,8 +187,10 @@ async function createServer(projectRoot, mode, explicitPort, options = {}) {
|
|
|
176
187
|
.then(() => deploymentRuntime.invalidateDevelopmentState());
|
|
177
188
|
invalidationPromise.then(
|
|
178
189
|
() => {
|
|
179
|
-
for (const
|
|
180
|
-
|
|
190
|
+
for (const socket of liveReloadSockets) {
|
|
191
|
+
if (socket.readyState === WebSocket.OPEN) {
|
|
192
|
+
socket.send("reload");
|
|
193
|
+
}
|
|
181
194
|
}
|
|
182
195
|
resolve();
|
|
183
196
|
},
|
|
@@ -197,20 +210,6 @@ async function createServer(projectRoot, mode, explicitPort, options = {}) {
|
|
|
197
210
|
try {
|
|
198
211
|
const origin = `http://${req.headers.host ?? `localhost:${port}`}`;
|
|
199
212
|
const pathname = new URL(req.url ?? "/", origin).pathname;
|
|
200
|
-
if (mode === "development" && pathname === LIVE_RELOAD_PATHNAME) {
|
|
201
|
-
res.writeHead(200, {
|
|
202
|
-
"cache-control": "no-cache, no-transform",
|
|
203
|
-
connection: "keep-alive",
|
|
204
|
-
"content-type": "text/event-stream",
|
|
205
|
-
});
|
|
206
|
-
res.write("retry: 1000\\n\\n");
|
|
207
|
-
liveReloadConnections.add(res);
|
|
208
|
-
res.on("close", () => {
|
|
209
|
-
liveReloadConnections.delete(res);
|
|
210
|
-
});
|
|
211
|
-
return;
|
|
212
|
-
}
|
|
213
|
-
|
|
214
213
|
await pendingInvalidation;
|
|
215
214
|
await invalidationPromise;
|
|
216
215
|
const method = req.method ?? "GET";
|
|
@@ -220,7 +219,9 @@ async function createServer(projectRoot, mode, explicitPort, options = {}) {
|
|
|
220
219
|
...(method === "GET" || method === "HEAD" ? {} : { body: req, duplex: "half" }),
|
|
221
220
|
});
|
|
222
221
|
const response = await deploymentRuntime.handle(request);
|
|
223
|
-
const servedResponse = mode === "development"
|
|
222
|
+
const servedResponse = mode === "development"
|
|
223
|
+
? injectLiveReloadSnippet(response)
|
|
224
|
+
: response;
|
|
224
225
|
|
|
225
226
|
res.writeHead(servedResponse.status, servedResponse.headers);
|
|
226
227
|
await writeResponseBody(res, servedResponse.body);
|
|
@@ -230,6 +231,19 @@ async function createServer(projectRoot, mode, explicitPort, options = {}) {
|
|
|
230
231
|
}
|
|
231
232
|
});
|
|
232
233
|
|
|
234
|
+
server.on("upgrade", (request, socket, head) => {
|
|
235
|
+
const origin = `http://${request.headers.host ?? `localhost:${port}`}`;
|
|
236
|
+
const pathname = new URL(request.url ?? "/", origin).pathname;
|
|
237
|
+
if (!liveReloadServer || pathname !== LIVE_RELOAD_PATHNAME) {
|
|
238
|
+
socket.destroy();
|
|
239
|
+
return;
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
liveReloadServer.handleUpgrade(request, socket, head, (webSocket) => {
|
|
243
|
+
liveReloadServer.emit("connection", webSocket, request);
|
|
244
|
+
});
|
|
245
|
+
});
|
|
246
|
+
|
|
233
247
|
return {
|
|
234
248
|
port,
|
|
235
249
|
deploymentRuntime,
|
|
@@ -244,10 +258,14 @@ async function createServer(projectRoot, mode, explicitPort, options = {}) {
|
|
|
244
258
|
clearTimeout(invalidationTimer);
|
|
245
259
|
}
|
|
246
260
|
watcher?.close();
|
|
247
|
-
for (const
|
|
248
|
-
|
|
261
|
+
for (const socket of liveReloadSockets) {
|
|
262
|
+
socket.close();
|
|
263
|
+
}
|
|
264
|
+
if (liveReloadServer) {
|
|
265
|
+
await new Promise((resolve) => {
|
|
266
|
+
liveReloadServer.close(resolve);
|
|
267
|
+
});
|
|
249
268
|
}
|
|
250
|
-
liveReloadConnections.clear();
|
|
251
269
|
await new Promise((resolve, reject) => {
|
|
252
270
|
server.close((error) => {
|
|
253
271
|
if (error) {
|