dev server changes
This commit is contained in:
parent
2be03480fa
commit
10a3c01a56
4 changed files with 158 additions and 35 deletions
|
|
@ -11,6 +11,11 @@ fmt: node_modules
|
|||
build: fmt
|
||||
prefix "$@" ./ci/build.sh
|
||||
|
||||
.PHONY: dev
|
||||
dev: build
|
||||
prefix "$@" git checkout -- src/platform.js src/worker.js
|
||||
prefix "$@" bun run dev
|
||||
|
||||
.PHONY: test
|
||||
test: build
|
||||
prefix "$@" bun test:all
|
||||
|
|
|
|||
|
|
@ -77,12 +77,12 @@ If you change the main D2 source code, you should regenerate the WASM file:
|
|||
./make.sh build
|
||||
```
|
||||
|
||||
### Running the Development Server
|
||||
### Running the dev server
|
||||
|
||||
Make sure you've built already, then run:
|
||||
You can browse the examples by running the dev server:
|
||||
|
||||
```bash
|
||||
bun run dev
|
||||
./make.sh dev
|
||||
```
|
||||
|
||||
Visit `http://localhost:3000` to see the example page.
|
||||
|
|
|
|||
|
|
@ -1,3 +1,6 @@
|
|||
const fs = require("fs/promises");
|
||||
const path = require("path");
|
||||
|
||||
const MIME_TYPES = {
|
||||
".html": "text/html",
|
||||
".js": "text/javascript",
|
||||
|
|
@ -11,45 +14,57 @@ const server = Bun.serve({
|
|||
port: 3000,
|
||||
async fetch(request) {
|
||||
const url = new URL(request.url);
|
||||
let path = url.pathname;
|
||||
let filePath = url.pathname.slice(1); // Remove leading "/"
|
||||
|
||||
// Serve index page by default
|
||||
if (path === "/") {
|
||||
path = "/examples/basic.html";
|
||||
}
|
||||
|
||||
// Handle attempts to access files in src
|
||||
if (path.startsWith("/src/")) {
|
||||
const wasmFile = path.includes("wasm_exec.js") || path.includes("d2.wasm");
|
||||
if (wasmFile) {
|
||||
path = path.replace("/src/", "/wasm/");
|
||||
}
|
||||
if (filePath === "") {
|
||||
filePath = "examples/";
|
||||
}
|
||||
|
||||
try {
|
||||
const filePath = path.slice(1);
|
||||
const file = Bun.file(filePath);
|
||||
const exists = await file.exists();
|
||||
const fullPath = path.join(process.cwd(), filePath);
|
||||
const stats = await fs.stat(fullPath);
|
||||
|
||||
if (!exists) {
|
||||
return new Response(`File not found: ${path}`, { status: 404 });
|
||||
if (stats.isDirectory()) {
|
||||
const entries = await fs.readdir(fullPath);
|
||||
const links = await Promise.all(
|
||||
entries.map(async (entry) => {
|
||||
const entryPath = path.join(fullPath, entry);
|
||||
const isDir = (await fs.stat(entryPath)).isDirectory();
|
||||
const slash = isDir ? "/" : "";
|
||||
return `<li><a href="${filePath}${entry}${slash}">${entry}${slash}</a></li>`;
|
||||
})
|
||||
);
|
||||
|
||||
const html = `
|
||||
<html>
|
||||
<body>
|
||||
<h1>Examples</h1>
|
||||
<ul>
|
||||
${links.join("")}
|
||||
</ul>
|
||||
</body>
|
||||
</html>
|
||||
`;
|
||||
return new Response(html, {
|
||||
headers: { "Content-Type": "text/html" },
|
||||
});
|
||||
} else {
|
||||
const ext = path.extname(filePath);
|
||||
const mimeType = MIME_TYPES[ext] || "application/octet-stream";
|
||||
|
||||
const file = Bun.file(filePath);
|
||||
return new Response(file, {
|
||||
headers: {
|
||||
"Content-Type": mimeType,
|
||||
"Access-Control-Allow-Origin": "*",
|
||||
"Cross-Origin-Opener-Policy": "same-origin",
|
||||
"Cross-Origin-Embedder-Policy": "require-corp",
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
// Get file extension and corresponding MIME type
|
||||
const ext = "." + filePath.split(".").pop();
|
||||
const mimeType = MIME_TYPES[ext] || "application/octet-stream";
|
||||
|
||||
return new Response(file, {
|
||||
headers: {
|
||||
"Content-Type": mimeType,
|
||||
"Access-Control-Allow-Origin": "*",
|
||||
"Cross-Origin-Opener-Policy": "same-origin",
|
||||
"Cross-Origin-Embedder-Policy": "require-corp",
|
||||
},
|
||||
});
|
||||
} catch (err) {
|
||||
console.error(`Error serving ${path}:`, err);
|
||||
return new Response(`Server error: ${err.message}`, { status: 500 });
|
||||
console.error(`Error serving ${filePath}:`, err);
|
||||
return new Response(`File not found: ${filePath}`, { status: 404 });
|
||||
}
|
||||
},
|
||||
});
|
||||
|
|
|
|||
103
d2js/js/examples/customizable.html
Normal file
103
d2js/js/examples/customizable.html
Normal file
|
|
@ -0,0 +1,103 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<style>
|
||||
body {
|
||||
display: flex;
|
||||
gap: 20px;
|
||||
padding: 20px;
|
||||
height: 100vh;
|
||||
margin: 0;
|
||||
font-family: system-ui, -apple-system, sans-serif;
|
||||
}
|
||||
.controls {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 12px;
|
||||
width: 400px;
|
||||
}
|
||||
textarea {
|
||||
width: 100%;
|
||||
height: 300px;
|
||||
padding: 8px;
|
||||
border: 1px solid #ccc;
|
||||
border-radius: 4px;
|
||||
font-family: monospace;
|
||||
}
|
||||
.layout-toggle {
|
||||
display: flex;
|
||||
gap: 16px;
|
||||
align-items: center;
|
||||
}
|
||||
.radio-group {
|
||||
display: flex;
|
||||
gap: 12px;
|
||||
}
|
||||
.radio-label {
|
||||
display: flex;
|
||||
gap: 4px;
|
||||
align-items: center;
|
||||
cursor: pointer;
|
||||
}
|
||||
button {
|
||||
padding: 8px 16px;
|
||||
background: #0066cc;
|
||||
color: white;
|
||||
border: none;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
}
|
||||
button:hover {
|
||||
background: #0052a3;
|
||||
}
|
||||
#output {
|
||||
flex: 1;
|
||||
overflow: auto;
|
||||
border: 1px solid #eee;
|
||||
border-radius: 4px;
|
||||
padding: 16px;
|
||||
}
|
||||
#output svg {
|
||||
max-width: 100%;
|
||||
max-height: 90vh;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="controls">
|
||||
<textarea id="input">x -> y</textarea>
|
||||
<div class="layout-toggle">
|
||||
<span>Layout:</span>
|
||||
<div class="radio-group">
|
||||
<label class="radio-label">
|
||||
<input type="radio" name="layout" value="dagre" checked />
|
||||
Dagre
|
||||
</label>
|
||||
<label class="radio-label">
|
||||
<input type="radio" name="layout" value="elk" />
|
||||
ELK
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<button onclick="compile()">Compile</button>
|
||||
</div>
|
||||
<div id="output"></div>
|
||||
<script type="module">
|
||||
import { D2 } from "../dist/browser/index.js";
|
||||
const d2 = new D2();
|
||||
window.compile = async () => {
|
||||
const input = document.getElementById("input").value;
|
||||
const layout = document.querySelector('input[name="layout"]:checked').value;
|
||||
try {
|
||||
const result = await d2.compile(input, { layout });
|
||||
const svg = await d2.render(result.diagram);
|
||||
document.getElementById("output").innerHTML = svg;
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
document.getElementById("output").textContent = err.message;
|
||||
}
|
||||
};
|
||||
compile();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
Loading…
Reference in a new issue