import liveServer from 'live-server'; import { qualifyURL } from './packages/docsify-server-renderer/src/utils'; const isSSR = !!process.env.SSR; const middleware = []; const port = 3000; main(); async function main() { if (isSSR) { // Using JSDom here because the server relies on a small subset of DOM APIs. // The URL used here serves no purpose other than to give JSDOM an HTTP // URL to operate under (it probably can be anything). initJSDOM('', { url: 'http://127.0.0.1:' + port }); const { Renderer, getServerHTMLTemplate } = await import( './packages/docsify-server-renderer/index' ); const renderer = new Renderer({ // The default template is simple, without any plugins or scripts, just docsify.js. // template: getServerHTMLTemplate(), template: /* html */ ` docsify `, config: { name: 'docsify', // repo: 'docsifyjs/docsify', alias: { '.*?/awesome': 'https://raw.githubusercontent.com/docsifyjs/awesome-docsify/master/README.md', '.*?/changelog': 'https://raw.githubusercontent.com/docsifyjs/docsify/master/CHANGELOG.md', '/.*/_navbar.md': '/_navbar.md', '/es/(.*)': 'https://raw.githubusercontent.com/docsifyjs/docs-es/master/$1', '/de-de/(.*)': 'https://raw.githubusercontent.com/docsifyjs/docs-de/master/$1', '/ru-ru/(.*)': 'https://raw.githubusercontent.com/docsifyjs/docs-ru/master/$1', '/zh-cn/(.*)': 'https://cdn.jsdelivr.net/gh/docsifyjs/docs-zh@master/$1', // In SSR mode, the _sidebar fallback mechanism is not implemented, // so without this, sub pages will show their specific sidebar // instead of the top-level sidebar. // // TODO SSR needs to have the fallback mechanism too, so it matches // with the dynamic-site behavior by default, without having to add // this line. '/.*/_sidebar.md': '/_sidebar.md', }, auto2top: true, // TODO better handling of these cases, perhaps a (sane?) default value. // basePath: undefined, // breaks: if base path is not set while in SSR mode, code tries to operate on an undefined value and errors. // basePath: '', // breaks: similar to undefined, server doesn't lookup file correctly. // If this is used, then after the initial payload is sent to the // client, the client will then make all following requests to // docsify.js.org for dynamic markdown rendering. // basePath: 'https://docsify.js.org/', basePath: '/docs', hasSSR: true, // coverpage: true, FIXME, not working in SSR. executeScript: true, loadSidebar: true, loadNavbar: true, mergeNavbar: true, maxLevel: 4, subMaxLevel: 2, search: { noData: { '/es/': '¡No hay resultados!', '/de-de/': 'Keine Ergebnisse!', '/ru-ru/': 'Никаких результатов!', '/zh-cn/': '没有结果!', '/': 'No results!', }, paths: 'auto', placeholder: { '/es/': 'Buscar', '/de-de/': 'Suche', '/ru-ru/': 'Поиск', '/zh-cn/': '搜索', '/': 'Search', }, pathNamespaces: ['/es', '/de-de', '/ru-ru', '/zh-cn'], }, }, }); middleware.push(function (req, res, next) { const url = new URL(qualifyURL(req.url)); // If the hasSSR flag is enabled, then dynamic fetches of markdown from a // "hydrated" cilent should not be compiled to HTML. if (url.searchParams.has('hasSSR')) { console.log('Skipping markdown handling for already-loaded client.'); return next(); } // Only handle markdown files or folders. if (/(\.md|\/[^.]*)$/.test(url.pathname)) { console.log('Render markdown to HTML on the server for file ', req.url); // This eventually feeds through the getFileName() function in // src/core/router/history/base.js. renderer.renderToString(req.url).then(html => res.end(html)); return; } // TODO There will surely be edge cases. Add an option to force certain files? console.log('Skipping markdown handling of file ' + req.url); return next(); }); } const params = { port, watch: ['lib', 'docs', 'themes'], middleware, }; liveServer.start(params); } async function initJSDOM(markup, options) { const { JSDOM } = (await import('jsdom')).default; const dom = new JSDOM(markup, options); global.window = dom.window; global.document = dom.window.document; global.navigator = dom.window.navigator; global.location = dom.window.location; global.XMLHttpRequest = dom.window.XMLHttpRequest; return dom; }