Skip to content

Commit

Permalink
feat: support xml and json pages
Browse files Browse the repository at this point in the history
  • Loading branch information
egoist committed Jul 31, 2020
1 parent 8a6f2f5 commit b8a0467
Show file tree
Hide file tree
Showing 8 changed files with 107 additions and 18 deletions.
17 changes: 17 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,23 @@ Then the generated website can be found at `.presite` folder.

Run `presite --help` for all CLI flags.

## Non-HTML pages

Presite also supports rendering non-HTML pages like XML or JSON pages, simply create files ending with `.xml.js` or `.json.js`, let's say you have a `feed.json.js`:

```js
import { createJSONFeed } from './somewhere/create-json-feed'

export default async () => {
const posts = await fetch('/api/my-posts').then((res) => res.json())
return createJSONFeed(posts)
}
```

You can export a function that resolves to a string or JSON object, then Presite will output this page as `feed.json`.

These pages are evaluated in browser in a `<script type="module">` tag, so you can use the `import` keyword.

## Configure in presite.config.js

Many CLI flags can be stored in a configuration file, that's totaly optional but if you need one, read on.
Expand Down
3 changes: 3 additions & 0 deletions example/feed.xml.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export default () => {
return `<feed></feed>`
}
2 changes: 1 addition & 1 deletion example/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
</head>
<body>
<div id="app"></div>

<a href="/feed.xml">feed</a>
<script src="/script.js"></script>
</body>
</html>
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,13 +30,14 @@
"polka": "^0.5.2",
"read-pkg-up": "^2.0.0",
"serve-static": "^1.14.1",
"taki": "2.0.0",
"taki": "2.2.2",
"update-notifier": "^4.1.0"
},
"devDependencies": {
"@types/connect-history-api-fallback": "^1.3.3",
"@types/fs-extra": "^9.0.1",
"@types/polka": "^0.5.1",
"@types/puppeteer-core": "^2.0.0",
"@types/update-notifier": "^4.1.0",
"shipjs": "0.20.1",
"tsup": "^3.4.2",
Expand Down
23 changes: 20 additions & 3 deletions src/Crawler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,12 @@ import { PromiseQueue } from '@egoist/promise-queue'
import { Writer } from './Writer'
import { Logger } from './Logger'

export const SPECIAL_EXTENSIONS_RE = /\.(xml|json)$/

const routeToFile = (route: string) => {
if (/\.html$/.test(route) || SPECIAL_EXTENSIONS_RE.test(route)) {
return route
}
return route.replace(/\/?$/, '/index.html')
}

Expand Down Expand Up @@ -43,12 +48,24 @@ export class Crawler {
const queue = new PromiseQueue(
async (route: string) => {
const file = routeToFile(route)

const html = await request({
url: `http://${hostname}:${port}${route}`,
onAfterRequest: (url) => {
onBeforeRequest(url) {
logger.log(`Crawling contents from ${chalk.cyan(url)}`)
},
manually: SPECIAL_EXTENSIONS_RE.test(route) ? true : undefined,
onCreatedPage(page) {
page.on('console', (e) => {
const type = e.type()
// @ts-ignore
const log = console[type] || console.log
const location = e.location()
log(
`Message from ${location.url}:${location.lineNumber}:${location.columnNumber}`,
e.text()
)
})
},
})

// find all `<a>` tags in exported html files and export links that are not yet exported
Expand All @@ -64,8 +81,8 @@ export class Crawler {
}
}

await writer.write({ html, file })
logger.log(`Writing ${chalk.cyan(file)} for ${chalk.cyan(route)}`)
await writer.write({ html, file })
},
{ maxConcurrent: 50 }
)
Expand Down
37 changes: 36 additions & 1 deletion src/Server.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
import { Server as HttpServer } from 'http'
import { join } from 'path'
import fs from 'fs-extra'
import polka from 'polka'
import getPort from 'get-port'
import historyAPIFallback from 'connect-history-api-fallback'
import serveStatic from 'serve-static'
import { SPECIAL_EXTENSIONS_RE } from './Crawler'

type ServerOptions = {
baseDir: string
outDir: string
}

export class Server {
Expand All @@ -21,7 +25,38 @@ export class Server {
this.opts = opts

this.app.use(historyAPIFallback())
this.app.use('/', serveStatic(this.opts.baseDir))
this.app.use(serveStatic(this.opts.baseDir))
this.app.use(async (req, res, next) => {
if (!SPECIAL_EXTENSIONS_RE.test(req.path)) {
return next()
}
const file = join(this.opts.baseDir, req.path + '.js')
if (await fs.pathExists(file)) {
// Remove copied original file in output directory
// e.g. /feed.xml should remove original feed.xml.js in output directory
await fs.remove(join(this.opts.outDir, req.path + '.js'))
res.setHeader('content-type', 'text/html')
res.end(`
<html>
<body>
<script id="__presite_script__" type="module">
import getContent from "${req.path + '.js'}"
document.addEventListener('DOMContentLoaded', () => {
Promise.resolve(getContent()).then(content => {
window.snapshot({
content: typeof content === 'string' ? content : JSON.stringify(content)
});
})
})
</script>
</body>
</html>
`)
return
}
next()
})
}

async start(): Promise<void> {
Expand Down
18 changes: 10 additions & 8 deletions src/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ async function main() {

const joycon = new JoyCon({
packageKey: 'presite',
files: ['package.json', 'presite.config.json', 'presite.config.js']
files: ['package.json', 'presite.config.json', 'presite.config.js'],
})

const { data: configData, path: configPath } = await joycon.load()
Expand All @@ -57,35 +57,37 @@ async function main() {
config = Object.assign(
{
outDir: '.presite',
routes: ['/']
routes: ['/'],
},
configData,
flags,
{
baseDir: dir
baseDir: dir,
}
)

const logger = new Logger({ verbose: !flags.quiet })

const server = new Server({
baseDir: config.baseDir
baseDir: config.baseDir,
outDir: config.outDir,
})

const writer = new Writer({
outDir: config.outDir
outDir: config.outDir,
})

logger.log(`Copy static assets`)
await Promise.all([server.start(), writer.copyFrom(config.baseDir)])

const crawler = new Crawler({
hostname: server.hostname,
port: server.port!,
options: {
routes: config.routes
routes: config.routes,
},
writer,
logger
logger,
})

await crawler.crawl()
Expand All @@ -101,7 +103,7 @@ async function main() {
await cli.runMatchedCommand()
}

main().catch(error => {
main().catch((error) => {
console.error(error)
process.exit(1)
})
22 changes: 18 additions & 4 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -298,6 +298,20 @@
"@types/node" "*"
"@types/trouter" "*"

"@types/puppeteer-core@^2.0.0":
version "2.0.0"
resolved "https://registry.yarnpkg.com/@types/puppeteer-core/-/puppeteer-core-2.0.0.tgz#3b7fbbac53d56b566f5ef096116e1d60d504aa45"
integrity sha512-JvoEb7KgEkUet009ZDrtpUER3hheXoHgQByuYpJZ5WWT7LWwMH+0NTqGQXGgoOKzs+G5NA1T4DZwXK79Bhnejw==
dependencies:
"@types/puppeteer" "*"

"@types/puppeteer@*":
version "3.0.1"
resolved "https://registry.yarnpkg.com/@types/puppeteer/-/puppeteer-3.0.1.tgz#053ec20facc162b25a64785affccaa3e5817c607"
integrity sha512-t03eNKCvWJXhQ8wkc5C6GYuSqMEdKLOX0GLMGtks25YZr38wKZlKTwGM/BoAPVtdysX7Bb9tdwrDS1+NrW3RRA==
dependencies:
"@types/node" "*"

"@types/qs@*":
version "6.9.4"
resolved "https://registry.yarnpkg.com/@types/qs/-/qs-6.9.4.tgz#a59e851c1ba16c0513ea123830dd639a0a15cb6a"
Expand Down Expand Up @@ -3141,10 +3155,10 @@ supports-color@^7.1.0:
dependencies:
has-flag "^4.0.0"

taki@2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/taki/-/taki-2.0.0.tgz#0f3725f2ced9fbf1301323bdbf9c93dbecc5ea98"
integrity sha512-uT+Ero9eqzz5XWEXuhoYj1FhMZLJn7OeiuC6ZQP419XRqquiaXSdml+W+i0Aab8qwi55BLqsaxH2IiqGZlJMuA==
taki@2.2.2:
version "2.2.2"
resolved "https://registry.yarnpkg.com/taki/-/taki-2.2.2.tgz#79f44c1a04efbd171e7881caa980f667a5486abe"
integrity sha512-lKaHTw5RLFWbB4rs7vVo9O5UsC9/DIl51ijYKzgXQ44nHqgDxqPMHdCb2GnIthfC99lzvNdFup+qxjISKXV5tA==
dependencies:
debug "4.1.1"
html-minifier "4.0.0"
Expand Down

0 comments on commit b8a0467

Please sign in to comment.