docsify/packages/docsify-server-renderer/index.js

142 lines
3.6 KiB
JavaScript
Raw Normal View History

2017-05-30 03:28:43 +08:00
import * as tpl from '../../src/core/render/tpl'
import fetch from 'node-fetch'
2017-05-29 22:24:38 +08:00
import { AbstractHistory } from '../../src/core/router/history/abstract'
2017-05-30 03:28:43 +08:00
import { Compiler } from '../../src/core/render/compiler'
import { isAbsolutePath } from '../../src/core/router/util'
2017-05-30 00:23:43 +08:00
import { readFileSync } from 'fs'
2017-05-30 03:28:43 +08:00
import { resolve, basename } from 'path'
2017-05-30 15:27:04 +08:00
import resolvePathname from 'resolve-pathname'
2017-05-30 16:16:36 +08:00
import debug from 'debug'
2017-05-30 00:23:43 +08:00
function cwd (...args) {
return resolve(process.cwd(), ...args)
}
function mainTpl (config) {
2017-05-30 06:32:41 +08:00
let html = `<nav class="app-nav${config.repo ? '' : ' no-badge'}"><!--navbar--></nav>`
2017-05-30 00:23:43 +08:00
if (config.repo) {
html += tpl.corner(config.repo)
}
if (config.coverpage) {
html += tpl.cover()
}
html += tpl.main(config)
return html
}
2017-05-29 22:24:38 +08:00
export default class Renderer {
constructor ({
template,
config,
cache
}) {
2017-05-30 01:25:52 +08:00
this.html = template
2017-05-30 03:28:43 +08:00
this.config = config = Object.assign({}, config, {
2017-05-30 00:23:43 +08:00
routerMode: 'history'
})
2017-05-29 22:24:38 +08:00
this.cache = cache
2017-05-30 00:23:43 +08:00
this.router = new AbstractHistory(config)
2017-05-29 22:24:38 +08:00
this.compiler = new Compiler(config, this.router)
2017-05-30 00:23:43 +08:00
this.router.getCurrentPath = () => this.url
this._renderHtml('inject-config', `<script>window.$docsify = ${JSON.stringify(config)}</script>`)
this._renderHtml('inject-app', mainTpl(config))
2017-05-30 01:25:52 +08:00
this.template = this.html
2017-05-30 00:23:43 +08:00
}
2017-05-30 03:48:29 +08:00
_getPath (url) {
2017-05-30 03:28:43 +08:00
const file = this.router.getFile(url)
return isAbsolutePath(file)
? file
2017-05-30 06:32:41 +08:00
: cwd(`./${file}`)
2017-05-30 03:28:43 +08:00
}
async renderToString (url) {
2017-05-30 01:25:52 +08:00
this.url = url = this.router.parse(url).path
2017-05-30 00:23:43 +08:00
const { loadSidebar, loadNavbar } = this.config
2017-05-30 03:28:43 +08:00
const mainFile = this._getPath(url)
this._renderHtml('main', await this._render(mainFile))
2017-05-30 00:23:43 +08:00
if (loadSidebar) {
const name = loadSidebar === true ? '_sidebar.md' : loadSidebar
2017-05-30 11:54:37 +08:00
const sidebarFile = this._getPath(resolve(url, `./${name}`))
2017-05-30 03:28:43 +08:00
this._renderHtml('sidebar', await this._render(sidebarFile, 'sidebar'))
2017-05-30 00:23:43 +08:00
}
if (loadNavbar) {
const name = loadNavbar === true ? '_navbar.md' : loadNavbar
2017-05-30 11:54:37 +08:00
const navbarFile = this._getPath(resolve(url, `./${name}`))
2017-05-30 03:28:43 +08:00
this._renderHtml('navbar', await this._render(navbarFile, 'navbar'))
2017-05-30 00:23:43 +08:00
}
2017-05-30 01:25:52 +08:00
const html = this.html
this.html = this.template
return html
2017-05-30 00:23:43 +08:00
}
_renderHtml (match, content) {
2017-05-30 01:32:04 +08:00
this.html = this.html.replace(new RegExp(`<!--${match}-->`, 'g'), content)
return this.html
2017-05-29 22:24:38 +08:00
}
2017-05-30 03:28:43 +08:00
async _render (path, type) {
let html = await this._loadFile(path)
2017-05-30 01:25:52 +08:00
const { subMaxLevel, maxLevel } = this.config
2017-05-30 00:23:43 +08:00
switch (type) {
case 'sidebar':
2017-05-30 01:32:04 +08:00
html = this.compiler.sidebar(html, maxLevel) +
`<script>window.__SUB_SIDEBAR__ = ${JSON.stringify(
2017-05-30 01:25:52 +08:00
this.compiler.subSidebar(html, subMaxLevel)
)}</script>`
2017-05-30 00:23:43 +08:00
break
case 'cover':
html = this.compiler.cover(html)
break
case 'navbar':
case 'article':
default:
html = this.compiler.compile(html)
break
}
return html
}
2017-05-30 03:28:43 +08:00
async _loadFile (filePath) {
2017-05-30 16:16:36 +08:00
debug('docsify')(`load > ${filePath}`)
2017-05-30 06:32:41 +08:00
let content
2017-05-30 00:23:43 +08:00
try {
2017-05-30 06:32:41 +08:00
if (isAbsolutePath(filePath)) {
const res = await fetch(filePath)
2017-05-30 16:16:36 +08:00
if (!res.ok) throw Error()
2017-05-30 06:32:41 +08:00
content = await res.text()
this.lock = 0
} else {
content = await readFileSync(filePath, 'utf8')
this.lock = 0
}
return content
} catch (e) {
2017-05-30 04:27:49 +08:00
this.lock = this.lock || 0
if (++this.lock > 10) {
this.lock = 0
return
}
2017-05-30 00:23:43 +08:00
const fileName = basename(filePath)
2017-05-30 15:27:04 +08:00
return await this._loadFile(resolvePathname(`../${fileName}`, filePath))
2017-05-30 00:23:43 +08:00
}
2017-05-29 22:24:38 +08:00
}
}