diff --git a/package.json b/package.json index 03c5567..09f3211 100644 --- a/package.json +++ b/package.json @@ -10,6 +10,7 @@ "ssg": "node ./ssg.js", "ssg:serve": "node ./ssg.js && http-server ./dist", "ssr": "nodemon --watch lib --watch www ./ssr.js", + "streaming": "nodemon --watch lib --watch www ./ssr-streaming.js", "start": "yarn ssr" }, "dependencies": { diff --git a/ssg.js b/ssg.js index c954a14..ebe9011 100644 --- a/ssg.js +++ b/ssg.js @@ -37,7 +37,7 @@ for (const entry of entries.filter(entry => entry.endsWith('.js'))) { - WCC + WCC - SSG ${ eagerJs.map(script => { diff --git a/ssr-streaming.js b/ssr-streaming.js new file mode 100644 index 0000000..ee64925 --- /dev/null +++ b/ssr-streaming.js @@ -0,0 +1,595 @@ +import fastify from 'fastify'; +import fastifyStatic from 'fastify-static'; +import path from 'path'; +import stream, { Readable } from 'stream'; +import { renderToString } from './lib/wcc.js'; + +const app = fastify({ logger: true }); +const port = 3001; + +app.register(fastifyStatic, { + root: new URL('./www', import.meta.url).pathname, + prefix: '/www' +}) +app.register(fastifyStatic, { + root: new URL('./lib', import.meta.url).pathname, + prefix: '/lib', + decorateReply: false +}) + +function* renderPageStreaming(html, assets) { + const lazyJs = []; + const eagerJs = []; + + for(const asset in assets) { + const a = assets[asset]; + + a.tagName = asset; + + if(a.moduleURL.href.endsWith('.js')) { + if(a.hydrate === 'lazy') { + lazyJs.push(a) + } else { + eagerJs.push(a) + } + } + } + + yield ` + + + + WCC - Streaming (SSR) + `; + yield ` + ${ + eagerJs.map(script => { + return ` + + + ` + }).join('\n') + } + `; + yield ` + ${ + lazyJs.map(script => { + return ` + + ` + }).join('\n') + } + `; + + yield ` + + +

+++++++++++++Start of Stream++++++++++++++

+ ${html} +

+++++++++++++Start of Stream++++++++++++++

+ ` + + yield ` + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ` + + yield ` +

+++++++++++++End of Stream++++++++++++++

+ ` + + yield ` + + + `; +} + +app.get('/*', async (request, reply) => { + const { url } = request; + + if(path.extname(url) === '') { + const pageRoute = url === '/' ? '/index' : url; + const entryPoint = `./www/pages${pageRoute}.js` + + console.debug({ url }); + console.debug({ pageRoute }) + console.debug({ entryPoint }) + + const { html, assets } = await renderToString(new URL(entryPoint, import.meta.url), false); + + // https://github.com/fastify/fastify/issues/805#issuecomment-369172154 + const buffer = new stream.Readable(); + buffer._read = ()=>{}; + + for(const data of renderPageStreaming(html, assets)) { + buffer.push(data); + } + + buffer.push(null) + + reply.type('text/html').send(buffer) + + // TODO - related to favicon? + // Promise may not be fulfilled with 'undefined' when statusCode is not 204", + // "stack":"FastifyError: Promise may not be fulfilled with 'undefined' when statusCode is not 204 + // reply + // .header('Content-Type', 'text/html; charset=utf-8') + // .header('Transfer-Encoding', 'chunked') + // .send(Readable.from(await renderPage(html, assets))); + } +}); + +const start = async () => { + try { + await app.listen(port) + } catch (err) { + app.log.error(err) + process.exit(1) + } +} + +start() \ No newline at end of file diff --git a/ssr.js b/ssr.js index 7d72e56..4ed166c 100644 --- a/ssr.js +++ b/ssr.js @@ -3,6 +3,7 @@ import fastifyStatic from 'fastify-static'; import { renderToString } from './lib/wcc.js'; const app = fastify({ logger: true }); +const port = 3000; app.register(fastifyStatic, { root: new URL('./www', import.meta.url).pathname, @@ -47,7 +48,7 @@ app.get('/*', async (request, reply) => { - WCC + WCC - SSR ${ eagerJs.map(script => { return `` @@ -90,7 +91,622 @@ app.get('/*', async (request, reply) => { - ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html} + ${html}