Skip to content

Commit

Permalink
feat: Add live reload
Browse files Browse the repository at this point in the history
  • Loading branch information
sidharthv96 committed Aug 12, 2023
1 parent a39122b commit 8da895c
Show file tree
Hide file tree
Showing 4 changed files with 106 additions and 19 deletions.
92 changes: 74 additions & 18 deletions .esbuild/server.ts
Original file line number Diff line number Diff line change
@@ -1,29 +1,85 @@
import express from 'express';
import express, { NextFunction, Request, Response } from 'express';
import cors from 'cors';
import { getBuildConfig } from './util.js';
import { context } from 'esbuild';
import chokidar from 'chokidar';

const mermaidCtx = await context(
getBuildConfig({ minify: false, core: false, entryName: 'mermaid' })
);
const mermaidIIFECtx = await context(
getBuildConfig({ minify: false, core: false, entryName: 'mermaid', format: 'iife' })
);
const externalCtx = await context(
getBuildConfig({ minify: false, core: false, entryName: 'mermaid-example-diagram' })
);
const zenuml = await context(
getBuildConfig({ minify: false, core: false, entryName: 'mermaid-zenuml' })
);

const contexts = [mermaidCtx, mermaidIIFECtx, externalCtx, zenuml];
const rebuildAll = async () => {
const promises = contexts.map((ctx) => ctx.rebuild());
await Promise.all(promises);
};

let clients: { id: number; response: Response }[] = [];
function eventsHandler(request: Request, response: Response, next: NextFunction) {
const headers = {
'Content-Type': 'text/event-stream',
Connection: 'keep-alive',
'Cache-Control': 'no-cache',
};
response.writeHead(200, headers);
const clientId = Date.now();
const newClient = {
id: clientId,
response,
};
clients.push(newClient);
request.on('close', () => {
clients = clients.filter((client) => client.id !== clientId);
});
}

let timeoutId: NodeJS.Timeout | undefined = undefined;

/**
* Debounce file change events to avoid rebuilding multiple times.
*/
function handleFileChange() {
if (timeoutId !== undefined) {
clearTimeout(timeoutId);
}
timeoutId = setTimeout(async () => {
await rebuildAll();
sendEventsToAll();
timeoutId = undefined;
}, 200);
}

function sendEventsToAll() {
clients.forEach((client) => client.response.write(`data: ${Date.now()}\n\n`));
}

async function createServer() {
const app = express();
const mermaidCtx = await context(
getBuildConfig({ minify: false, core: false, entryName: 'mermaid' })
);
const mermaidIIFECtx = await context(
getBuildConfig({ minify: false, core: false, entryName: 'mermaid', format: 'iife' })
);
const externalCtx = await context(
getBuildConfig({ minify: false, core: false, entryName: 'mermaid-example-diagram' })
);
const zenuml = await context(
getBuildConfig({ minify: false, core: false, entryName: 'mermaid-zenuml' })
);

mermaidCtx.watch();
mermaidIIFECtx.watch();
externalCtx.watch();
zenuml.watch();
chokidar
.watch('**/src/**/*.{js,ts,yaml}', {
ignoreInitial: true,
ignored: ['**/node_modules/*', '**/dist/*', '**/docs/*'],
})
.on('all', async (event, path) => {
// Ignore other events.
if (!['add', 'change'].includes(event)) {
return;
}
console.log(`${path} changed. Rebuilding...`);
handleFileChange();
});

app.use(cors());
app.get('/events', eventsHandler);
app.use(express.static('./packages/mermaid/dist'));
app.use(express.static('./packages/mermaid-zenuml/dist'));
app.use(express.static('./packages/mermaid-example-diagram/dist'));
Expand Down
27 changes: 27 additions & 0 deletions demos/dev/example.html
Original file line number Diff line number Diff line change
Expand Up @@ -30,5 +30,32 @@
console.log(svg);
el.innerHTML = svg;
</script>

<script>
// Set to false to disable live reload
const liveReload = true;
// Connect to the server and reload the page if the server sends a reload message
const connectToEvents = () => {
const events = new EventSource('/events');
const loadTime = Date.now();
events.onmessage = (event) => {
const time = JSON.parse(event.data);
if (time && time > loadTime) {
location.reload();
}
};
events.onerror = () => {
events.close();
// Try to reconnect after 1 second in case of errors
setTimeout(connectToEvents, 1000);
};
events.onopen = () => {
console.log('Connected to live reload server');
};
};
if (liveReload) {
connectToEvents();
}
</script>
</body>
</html>
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,6 @@
"@types/eslint": "^8.37.0",
"@types/express": "^4.17.17",
"@types/js-yaml": "^4.0.5",
"@vitest/coverage-c8": "^0.28.4",
"@types/jsdom": "^21.1.1",
"@types/lodash": "^4.14.194",
"@types/mdast": "^3.0.11",
Expand All @@ -79,10 +78,12 @@
"@types/rollup-plugin-visualizer": "^4.2.1",
"@typescript-eslint/eslint-plugin": "^5.59.0",
"@typescript-eslint/parser": "^5.59.0",
"@vitest/coverage-c8": "^0.28.4",
"@vitest/coverage-v8": "^0.33.0",
"@vitest/spy": "^0.33.0",
"@vitest/ui": "^0.33.0",
"ajv": "^8.12.0",
"chokidar": "^3.5.3",
"concurrently": "^8.0.1",
"cors": "^2.8.5",
"cypress": "^12.10.0",
Expand Down
3 changes: 3 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit 8da895c

Please sign in to comment.