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.js
file : 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
header
component andnav-bar
are 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-plugin
inquintype-node-build
would 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.js
file, theChunkExtractor
extracts 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
renderLoadableReduxComponent
which will return a ready-to-render HTML string that is passed to thelayout.ejs
template for SSR.Example: The below
render-layout.js
file will pass thetopbar
,navbar
andfooter
HTML 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
.