Building Static Sites without React - Using React (Part 2/3)

Managing Javascript, stylesheets, and other assets in the pipeline can be a difficult task. We have problems like: How do we get rid of the React runtime in the bundle? How do we optimize our CSS files? And how do we deal with the static files?

This is a continuation of the first part of "Building Static Sites without React - Using React" so please make sure to read the first part before moving on.

Let's talk about dealing with Javascript files. If we use a conventional "import" within the component files then we'll end up having to bundle all of those files (which is nice) together with React's runtime (which is also nice but we don't want that for this case). Webpack currently doesn't provide an easy way to tell which part of our script should be included in the bundle. As a result, we have to explicitly avoid importing modules statically and go for Dynamic Import.

Development First

We can't just dynamically import required scripts anywhere in a component file. We need to think "development-first" while we're carving out our path. Think of the time we're developing our pages, the scripts included in each component need to start executing only after the component has been rendered. For example, if we want to make a color-shifting title for a page, the title itself should be there before the shifting color script starts. How can we achieve that? The answer is in the HOOK (yeah, pun intended) and the one we're using is useEffect

In other words, we are in fact creating a custom hook that wraps around the useEffect hook. We call it "useScripts".
// src/useScripts.js
import { useEffect } from "react";

export function useScripts(scriptLoaders) {
  useEffect(() => {
    loadScripts(scriptLoaders);
  });
}

// Each dynamic import is asynchronous
async function loadScripts(scriptLoaders) {
  for (const load of scriptLoaders) {
    await load();
  }
}

Development with Storybook

In this project, we'll use Storybook for development. Let's set it up (might take a while).
npx -p @storybook/cli sb init

Let's get rid of the auto-generated stories files and create stories for our Home and AboutUs pages.
// stories/pages.stories.js
import React from "react";

import Home from "../pages/Home";
import AboutUs from "../pages/AboutUs";

export default { title: "Pages" };

export { Home, AboutUs };

Now our project structure should look like this
├── pages
│   ├── AboutUs.jsx
│   └── Home.jsx
├── scripts
│   └── build.js
├── src
│   └── useScripts.js
├── stories
│   └── pages.stories.js
├── babel.config.js
├── package.json
└── webpack.config.js

Now run
yarn storybook

Then we go to localhost:6006
Our stories start here...


Let's create our scripts, namely: src/home.js and src/about-us.js
// home.js
console.log("home.js");

const title = document.getElementById("home");

let cyan = true;

title.style.transition = "color 0.5s";

setInterval(() => {
  title.style.color = cyan ? "cyan" : "black";
  cyan = !cyan;
}, 1000);

//about-us.js
console.log("about-us.js");

Now, let's import both of them through useScripts.

//Home.jsx
import React from "react";
import { useScripts } from "../src/useScripts";

const Home = () => {
  useScripts([() => import("../src/home")]);
  return <h1 id="home">Home Page</h1>;
};

export default Home;

import React from "react";
import { useScripts } from "../src/useScripts";

const AboutUs = () => {
  useScripts([() => import("../src/about-us")]);
  return <h1>About Us</h1>;
};

export default AboutUs;

As you can see, after entering the Home page, we expect home.js to execute and display color shifting of the title in a second interval.

Voila!
Home page color shifting


Stylesheets

As I mentioned about how normal import statements would include React's runtime along with it, stylesheets and assets import won't do so. We can just import them normally.

Let's create the pages/Home.css file and modify related files.
// Home.css
#home {
  transition: color 0.2s;
}

// Home.jsx
import React from "react";
import { useScripts } from "../src/useScripts";

import "./Home.css"; // import stylesheets

const Home = () => {
  useScripts([() => import("../src/home")]);
  return <h1 id="home">Home Page</h1>;
};

export default Home;

We can delete the imperative transition line in home.js as well
// home.js
console.log("home.js");

const title = document.getElementById("home");

let cyan = true;

// title.style.transition = "color 0.5s"; <-- remove this

setInterval(() => {
  title.style.color = cyan ? "cyan" : "black";
  cyan = !cyan;
}, 1000);

And that's pretty much it for development. That’s where we’ll stop for now. We haven't yet talked about the building process resulting in the final HTML, JS and CSS files, but please stay tuned for that in the next part!
Like 3 likes
Aun Trirongkit
Aun Jessada - A full-stack Javascript developer interested in frontend, animations and user interface interaction. Experienced in game development, React and NodeJS. Also, a part-time musician, singer and songwriter.
Share:

Join the conversation

This will be shown public
All comments are moderated

Get our stories delivered

From us to your inbox weekly.