-
Notifications
You must be signed in to change notification settings - Fork 9
feat: add --live-reload flag for auto-refresh on file changes #111
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
bcbf980
1420069
7ea1bf4
c49b824
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -17,6 +17,23 @@ import { emitChange } from '../notifications/events.js'; | |
| import { checkIfMatch, checkIfNoneMatchForGet, checkIfNoneMatchForWrite } from '../utils/conditional.js'; | ||
| import { generateDatabrowserHtml, generateSolidosUiHtml, shouldServeMashlib } from '../mashlib/index.js'; | ||
|
|
||
| /** | ||
| * Live reload script - injected into HTML when --live-reload is enabled | ||
| */ | ||
| const LIVE_RELOAD_SCRIPT = `<script>(function(){var ws=new WebSocket((location.protocol==='https:'?'wss:':'ws:')+'//' +location.host+'/.notifications');ws.onopen=function(){ws.send('sub '+location.href)};ws.onmessage=function(e){if(e.data.startsWith('pub '))location.reload()};ws.onclose=function(){setTimeout(function(){location.reload()},1000)}})();</script>`; | ||
|
|
||
| /** | ||
| * Inject live reload script into HTML content | ||
| */ | ||
| function injectLiveReload(content) { | ||
| const html = content.toString(); | ||
| // Inject before </body> or at end | ||
| if (html.includes('</body>')) { | ||
| return Buffer.from(html.replace('</body>', LIVE_RELOAD_SCRIPT + '</body>')); | ||
| } | ||
| return Buffer.from(html + LIVE_RELOAD_SCRIPT); | ||
| } | ||
|
|
||
| /** | ||
| * Get the storage path and resource URL for a request | ||
| * In subdomain mode, storage path includes pod name, URL uses subdomain | ||
|
|
@@ -198,6 +215,12 @@ export async function handleGet(request, reply) { | |
| }); | ||
|
|
||
| Object.entries(headers).forEach(([k, v]) => reply.header(k, v)); | ||
| // Inject live reload script for index.html | ||
| if (request.liveReloadEnabled) { | ||
| reply.header('Cache-Control', 'no-store'); | ||
| reply.removeHeader('ETag'); | ||
| return reply.send(injectLiveReload(content)); | ||
| } | ||
| return reply.send(content); | ||
| } | ||
|
|
||
|
|
@@ -439,6 +462,13 @@ export async function handleGet(request, reply) { | |
| headers['Vary'] = getVaryHeader(connegEnabled, request.mashlibEnabled); | ||
|
|
||
| Object.entries(headers).forEach(([k, v]) => reply.header(k, v)); | ||
|
|
||
| // Inject live reload script into HTML (disable caching since content is modified) | ||
| if (actualContentType === 'text/html' && request.liveReloadEnabled) { | ||
| reply.header('Cache-Control', 'no-store'); | ||
| reply.removeHeader('ETag'); | ||
| return reply.send(injectLiveReload(content)); | ||
|
Comment on lines
+466
to
+470
|
||
| } | ||
|
Comment on lines
+466
to
+471
|
||
| return reply.send(content); | ||
| } | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -79,6 +79,8 @@ export function createServer(options = {}) { | |
| const defaultQuota = options.defaultQuota ?? 50 * 1024 * 1024; | ||
| // WebID-TLS client certificate authentication is OFF by default | ||
| const webidTlsEnabled = options.webidTls ?? false; | ||
| // Live reload - injects script to auto-refresh browser on file changes | ||
| const liveReloadEnabled = options.liveReload ?? false; | ||
|
|
||
| // Set data root via environment variable if provided | ||
| if (options.root) { | ||
|
|
@@ -136,9 +138,10 @@ export function createServer(options = {}) { | |
| fastify.decorateRequest('solidosUiEnabled', null); | ||
| fastify.decorateRequest('defaultQuota', null); | ||
| fastify.decorateRequest('config', null); | ||
| fastify.decorateRequest('liveReloadEnabled', null); | ||
| fastify.addHook('onRequest', async (request) => { | ||
| request.connegEnabled = connegEnabled; | ||
| request.notificationsEnabled = notificationsEnabled; | ||
| request.notificationsEnabled = notificationsEnabled || liveReloadEnabled; | ||
| request.idpEnabled = idpEnabled; | ||
| request.subdomainsEnabled = subdomainsEnabled; | ||
| request.baseDomain = baseDomain; | ||
|
|
@@ -148,6 +151,7 @@ export function createServer(options = {}) { | |
| request.solidosUiEnabled = solidosUiEnabled; | ||
| request.defaultQuota = defaultQuota; | ||
| request.config = { public: options.public, readOnly: options.readOnly }; | ||
| request.liveReloadEnabled = liveReloadEnabled; | ||
|
|
||
| // Extract pod name from subdomain if enabled | ||
| if (subdomainsEnabled && baseDomain) { | ||
|
|
@@ -164,8 +168,8 @@ export function createServer(options = {}) { | |
| } | ||
| }); | ||
|
|
||
| // Register WebSocket notifications plugin if enabled | ||
| if (notificationsEnabled) { | ||
| // Register WebSocket notifications plugin if enabled (or live reload needs it) | ||
| if (notificationsEnabled || liveReloadEnabled) { | ||
| fastify.register(notificationsPlugin); | ||
|
Comment on lines
+171
to
173
|
||
| } | ||
|
|
||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The PR description/issue text references a
/notifications/WebSocket endpoint, but the server’s notifications plugin exposes/.notifications(and the injected script also connects to/.notifications). Please align the docs/description (and any external consumers) with the actual endpoint used by this codebase to avoid confusion.