blazingly-ssr
blazingly-ssr copied to clipboard
Design
Hi!
I'm interested in building an SSR tool on top of Parcel as well.
I've built numerous SSR solutions in the past and learned couple of things.
As discussed in https://github.com/parcel-bundler/parcel/issues/3464, I believe a tool can be designed to not only support SSR but to also support all kinds of other app types.
This can be achieved by allowing the user to configure when and where a page is rendered:
-
renderToDom: Boolean
- If set to true, the page is rendered to the DOM (in the browser). -
renderToHtm: Boolean
- If set to true, the page is rendered to HTML (in Node.js). -
renderHtmlAtBuildTime: Boolean
- Whether the page is rendered to HTML at request-time or at build-time.
This design enables all kinds of app types, for example:
- SSR is added to a page by setting
renderToHtml: true
. - Static Rendering is achieved by setting
renderHtmlAtBuildTime: true
. - A Static Website can be obtained by setting
renderHtmlAtBuildTime: true
to all pages. - Removing browser-side JavaScript can be done by setting
renderToDom: false
. (The page isn't loaded nor rendered in the browser.) - MPA (or SPA) is when a page has
renderToHtml: false
andrenderToDom: true
. - Etc.
The amount of extra code to support renderToDom
, renderToHtml
, renderHtmlAtBuildTime
is little and well worth it considering that it allows the user to implement any app type.
A second design that I believe to be important is to give the user full control over how his pages are rendered. This can be achieved by allowing the user to define two functions htmlRender
and domRender
that the tool then uses to render his pages.
For example:
import React from 'react';
// The user defines a page with a so-called "page config":
export default {
route: '/hello/:name',
view: initialProps => (
<div>
Hello {initialProps.name}, welcome to Goldpage.
</div>
),
};
// render/htmlRender.js
// Here we use React but we could use any other view library to
// render our pages, such as Vue.
const React = require('react');
const ReactDOMServer = require('react-dom/server');
module.exports = htmlRender;
// `page` is the page config and `page.view` is the root component of the page
// that the user defined in the page config.
// `initialProps` are the initial props for the root component.
async function htmlRender({page, initialProps}) {
const html = (
ReactDOMServer.renderToStaticMarkup(
React.createElement(page.view, initialProps)
)
);
return html;
}
// render/domRender.js
import React from 'react';
import ReactDOM from 'react-dom';
export default domRender;
async function domRender({page, initialProps, CONTAINER_ID}) {
const element = React.createElement(page.view, initialProps);
const container = document.getElementById(CONTAINER_ID);
if( page.renderToHtml ){
ReactDOM.hydrate(element, container);
} else {
ReactDOM.render(element, container);
}
}
This design allows the tool to be used with any view library (Vue, React, React Native Web, Preact, ...) and makes it super easy to integrate with the ecosystem (Vuex, Vue Router, Redux, React Router, ...).
I'd be up to join forces to build an SSR tool on top of Parcel.