Support Loadable Component
This tutorial was contributed by Athira and Amogh
Loadable components is a library to solve the React code-splitting client-side, server-side, critical CSS, by loading all the scripts asynchronously to ensure optimal performances.
The first step towards implementing this is passing the files(components) for which code splitting and SSR is needed.
The quintype-node-build has the default webpack and babel config. This has to be modified a little bit for the quintype-node-build to accept the entry files.
-
In
quintype-build.config.jsfile : The naming and the structure of the keys in the config object has to be the same as shown below, only the entry files are configurable.In the example shown below, the
headercomponent andnav-barare the components that are targetted and the corresponding path has to be the value of typestring.
const quintypeBuildConfig = require("@quintype/build/config/quintype-build");
const loadableConfigObj = {
loadableConfig: {
entryFiles: {
topbar: "./app/isomorphic/components/layouts/header",
navbar: "./app/isomorphic/components/layouts/header/nav-bar",
footer: "./app/isomorphic/components/layouts/footer"
}
}
};
const modifiedBuildConfig = { ...quintypeBuildConfig, loadableConfigObj };
module.exports = modifiedBuildConfig;
-
@loadable/webpack-plugininquintype-node-buildwould generate a stats file, which will then be utilized in the app to extract the CSS string that needs to be injected.In the example shown below in
app/server/handlers/render-layout.jsfile, theChunkExtractorextracts the specific entry points from the stats file.extractor.getCssString()gets the css as a raw string.
const statsFile = path.resolve("stats.json");
const extractor = new ChunkExtractor({ statsFile, entrypoints: ["topbar", "navbar", "footer"] });
export const getCriticalCss = async () => {
const criticalCss = await extractor.getCssString();
return criticalCss.trim();
};
export async function renderLayout(res, params) {
...
const criticalCss = await getCriticalCss();
...
res.render(
"pages/layout",
Object.assign(
{
...
criticalCss: criticalCss,
...
},
params
)
);
}
In views/pages/layout.ejs file, the raw CSS string is injected as shown below:
<head>
...
<style>
<%- criticalCss %>
</style>
...
</head>
-
The next step is rendering the HTML on the server side. For this, we have created a component called the
renderLoadableReduxComponentwhich will return a ready-to-render HTML string that is passed to thelayout.ejstemplate for SSR.Example: The below
render-layout.jsfile will pass thetopbar,navbarandfooterHTML to the layout.
import { renderLoadableReduxComponent } from "@quintype/framework/server/render";
...
...
const statsFile = path.resolve("stats.json");
const extractor = new ChunkExtractor({ statsFile, entrypoints: ["topbar", "navbar", "footer"] });
// renderLayout is passed to isomorphicRoutes
export async function renderLayout(res, params) {
...
res.render(
"pages/layout",
Object.assign(
{
...
topbar: renderLoadableReduxComponent(Header, params.store, extractor),
navbar: renderLoadableReduxComponent(NavBar, params.store, extractor),
footer: renderLoadableReduxComponent(Footer, params.store, extractor),
...
},
params
)
);
}
Note: Hydrate the components if necessary to attach any event handlers.
In views/pages/layout.ejs file, the HTML string is injected as shown below:
<body>
...
<div><%- topbar %></div>
...
<header><%- navbar %></header>
...
...
<footer><%- footer %></footer>
...
</body>
Note: To view the changes locally, run ./run-prodish instead of ./run.