Skip to content

Instantly share code, notes, and snippets.

@loganhenson
Last active May 9, 2020 22:17
Show Gist options
  • Select an option

  • Save loganhenson/2d807af7c2497603b88f775b3319e2d3 to your computer and use it in GitHub Desktop.

Select an option

Save loganhenson/2d807af7c2497603b88f775b3319e2d3 to your computer and use it in GitHub Desktop.
import { listenAndServe } from 'https://deno.land/std/http/mod.ts'
import { readFileStr } from 'https://deno.land/std/fs/mod.ts'
import { match } from 'https://cdn.pika.dev/path-to-regexp@^6.1.0'
const render = async ({ page, state }) => {
return `
<!doctype html>
<html lang=en>
<head>
<meta charset=utf-8>
<link href="https://unpkg.com/tailwindcss@^1.0/dist/tailwind.min.css" rel="stylesheet">
<script src="https://unpkg.com/react@16/umd/react.development.js" crossorigin></script>
<script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js" crossorigin></script>
</head>
<body>
<div id="app">
</div>
<script type="module">
const setPage = async (url, page, state) => {
const Page = await import('/' + page + '.js')
ReactDOM.render(
React.createElement(
Page.default,
state
),
document.getElementById('app')
);
if (url === window.location.pathname + window.location.search) {
window.history.replaceState({url: url, page: page, state: state}, '', url)
} else {
window.history.pushState({url: url, page: page, state: state}, '', url)
}
}
window.visit = async (url) => {
const result = await fetch(url, {
headers: {
'Content-Type': 'application/json',
}
})
const jsonResult = await result.json()
await setPage(url, jsonResult.page, jsonResult.state)
}
window.addEventListener('popstate', async (e) => {
if (e.state) {
await setPage(e.state.url, e.state.page, e.state.state)
}
})
setPage(window.location.pathname, '${page}', ${
JSON.stringify(state)
})
</script>
</body>
</html>
`
}
const getMatchedAndParams = (url, matchers) => {
let params = {}
const matched = matchers.find(({ matcher, _ }) => {
let matched = matcher(url)
if (matched) {
params = matched.params
return matched
}
return false
})
return [matched, params]
}
export default (routes) => {
const matchers = Object.keys(routes).map(
(route) => {
return {
matcher: match(route, { encode: encodeURI, decode: decodeURIComponent }),
handler: routes[route],
}
}
)
console.log('listening on 0.0.0.0:3001')
listenAndServe({ port: 3001 }, async (req) => {
// .js assets.
if (req.url.endsWith('.js')) {
const path = `./public/${req.url}`
let headers = new Headers()
headers.set('Content-Type', 'application/javascript')
try {
const js = await readFileStr(path)
return req.respond({
body: js,
headers: headers,
})
} catch (e) {
return req.respond({ status: 404, headers: headers })
}
}
// Json Application Routing.
if(req.headers.get('Content-Type') === 'application/json') {
const [matched, params] = getMatchedAndParams(req.url, matchers)
if (matched) {
const handler = await matched.handler(params)
let headers = new Headers()
headers.set('Cache-Control', 'no-cache, no-store')
return req.respond({ body: JSON.stringify(handler), headers: headers, })
} else {
return req.respond({ body: JSON.stringify({page: '404', state: {}}) })
}
}
// Normal Application Routing.
if (!req.url.includes('.')) {
const [matched, params] = getMatchedAndParams(req.url, matchers)
if (matched) {
const handler = await matched.handler(params)
return req.respond({ body: await render(handler) })
} else {
return req.respond({ body: (await import('./public/404.js')).default() })
}
}
})
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment