Alternate Formats (SVG, XML, JSON)
Besides HTML, modules can include alternate format renderings. The server automatically routes requests for the module’s endpoint to an entry point file (checked in order: index.html, index.xml, index.svg, index.json, index.js).
This enables serving other formats in browser rendering. For example, JavaScript can run inside an index.svg file to dynamically fetch data via the /graphql endpoint and construct a visualization directly in the browser:
<!-- app/index.svg -->
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 800 600">
<script type="text/javascript"><![CDATA[
async function renderGraph() {
const response = await fetch('/graphql', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ query: '{ countNodes }' })
});
const result = await response.json();
// Generate XML/SVG dynamically
const text = document.createElementNS("http://www.w3.org/2000/svg", "text");
text.setAttribute("x", "20"); text.setAttribute("y", "40");
text.textContent = "Total Graph Nodes: " + result.data.countNodes;
document.documentElement.appendChild(text);
}
renderGraph();
]]></script>
</svg>
Generating XML Downloads
Browsers do not execute JavaScript inside generic XML files. If your module needs to dynamically generate and download a generic XML file (such as GraphML) without a visible HTML interface, you can serve an index.xml file containing an <svg> root element.
The browser recognizes the SVG namespace and executes the embedded <script>, turning the file into an “invisible launcher”. The script can fetch data, construct the desired XML payload, and immediately trigger a download or redirect. Because the file is parsed as strict XML, wrap the script contents in <![CDATA[ ... ]]> to prevent parsing errors from characters like < and &.
<!-- app/index.xml -->
<svg xmlns="http://www.w3.org/2000/svg">
<script type="text/javascript"><![CDATA[
async function generateXml() {
// 1. Fetch data from GraphQL
const response = await fetch('/graphql', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ query: '{ countNodes }' })
});
const result = await response.json();
// 2. Construct the target XML payload
const xml = `<?xml version="1.0" encoding="UTF-8"?>\n` +
`<report>\n` +
` <totalNodes>${result.data.countNodes}</totalNodes>\n` +
`</report>`;
// 3. Create a Blob and trigger a download
const blob = new Blob([xml], { type: 'application/xml' });
const url = URL.createObjectURL(blob);
const a = document.createElementNS('http://www.w3.org/1999/xhtml', 'a');
a.href = url;
a.download = 'report.xml';
a.click();
setTimeout(() => URL.revokeObjectURL(url), 100);
}
generateXml();
]]></script>
</svg>