A React SSR and SSG framework inspired by Next.js
npm install isomorph-webStale-While-Revalidate approach of handling serving.
getDataOnServer and getStaticProps and function to populate page meta data with getPageMeta.
useInitialData hook to access initial data fetched on the server across the entire component chain.
ISOMORPH_PUBLIC_... accessible on the client-side.
_error for handling 404s and 500s.
create-isomorph-app
create-isomorph-app.
npm i -g isomorph-web
npx create-isomorph-app [project directory] [?project name]
// ex:
npx create-isomorph-app my-isomorph-project "Isomorph App"
`
#### Setting Up Manually
As of now to setup an isomorph project, create a directory for your project. I'm assuming you have npm and Node.js already installed.
`
mkdir my-isomorph-project
cd ./my-isomorph-project
npm init -y
`
Once done with this, install isomorph-web using npm or yarn.
`
yarn add isomorph-web
// or
npm i --save isomorph-web
`
Create an src folder, this will house all your components, utils and project related JavaScript code. Inside it create a pages folder that will house your page files and have React components associated with them.
Check the Required Project Structure section to know the sample structure of isomorph projects.
Update your package.json file's scripts to the following:
`diff
"scripts": {
+ "build": "isomorph-web build",
+ "dev": "isomorph-web dev",
+ "start": "isomorph-web start"
}
`
Once done, run the dev server using:
`
npm run dev
`
$3
Your pages have to be housed inside the src/pages folder of your project directory.
`
.
├── src/
│ ├── pages/
│ │ ├── index.js
│ │ └── static-page.js
│ ├── components/
│ │ └── ...
│ └── utils/
│ └── ...
└── package.json
`
I'm currently working on adding dynamic route support soon.
$3
Pages are simple React component files that expose a default React component export, along with a few other exports to facilitate data fetching and meta data handling.
`javascript
// No need to 'import React from "react";', it's always in scope.
import useInitialData from "isomorph-web/package/hooks/useInitialData";
const PageComponent = () => {
const initialData = useInitialData(); // Use this hook to access data fetched for the page in getPropsOnServer/getStaticProps.
return (
<>
Data received from server: {initialData.variable}. I can even have
environment variables: {process.env.ISOMORPH_PUBLIC_ENV_VAR}.
>
);
};
export default PageComponent;
// For server-rendered pages, for static pages, use getStaticProps or skip both of these data fetcher functions.
export const getPropsOnServer = async (context) => {
console.log(
context.req,
context.res,
context.cookies, // Parsed cookie object for you
context.env, // Environment variables, would not be exposed to the client.
context.url // Request url path.
context.query // Request query parameters
);
const variable = await getVariableFromDatabase(context.url, context.cookies);
return { variable }; // This will be passed to the page component and can be accessed using the useInitialData hook.
};
// For static pages
export const getStaticProps = async (context) => {
console.log(
context.env, // Environment variables, would not be exposed to the client.
context.url // Request url path.
);
return { revalidate: 3 * 60, variable: 5 }; // Revalidate the page after 3 minutes, pass the rest of the payload as initial data.
};
`
$3
What's server-side and static rendering without SEO benefits. For that purpose, we have the getPageMeta function that will allow you to add all meta tags, link tags, script tags you need.
`javascript
// In your page file.
// src/pages/index.js
...
export const getPageMeta = () => {
return {
title: "Home Page",
meta: [
{
name: "description",
content: "A simple page generated on the server-side.",
},
{
name: "viewport",
content: "width=device-width, initial-scale=1.0",
},
],
links: [
{
rel: "stylesheet",
href: "https://cdn.jsdelivr.net/npm/bootstrap@4.3.1/dist/css/bootstrap.min.css",
},
],
scripts: [
{
type: "application/ld+json",
content: '{ type: "Your JSON LD data for rich results" }',
},
],
};
};
`
$3
Components rendered on the client-side are hydration-error free, that's because they are not hydrated in the first place, they are re-rendered, which means as long as your pages are not super heavy and big, you can avoid worrying about errors like HTML on server did not match the HTML on client which can be frustrating and error-prone when writing React apps that render and function on both the client and the server-side without any impact on page load and performance.
To find out whether your app is on the client-side, just use the following:
`javascript
typeof window === "undefined"; // If this is true, you're on the server-side.
`
$3
Environment variables are fully supported, use a .env file at the root of your folder to expose environment variables for your app. On the server-side and while rendering your page components on the server-side, you have access to all environment variables.
On the client-side, all environment variables starting with ISOMORPH_PUBLIC_ are automatically exposed.
$3
For handling custom UIs for 404 and 500 errors, you can create a pages/_error.js file.
`javascript
const ErrorComponent = ({ statusCode, error }) => {
// statusCode -> 404 | 500
// error -> The error message that was received from the server.
return (
<>
{statusCode}
{error}
>
);
};
export default ErrorComponent;
`
$3
Use the following command to compile your source code to production config.
`
npm run build
`
Use the following to start the server.
`
npm run start
``