Giter Site home page Giter Site logo

boring-ssg's Introduction

Boring SSG

Static Site Generation So Good, It's Boring

Demo: https://boring-ssg.netlify.com

hello! This is an experimental react static site generator using Parcel and @reach/router! Putting together better tooling can make for a very fast and more accessible static site generator!

blog

Deploy on Netlify with NetlifyCMS

One click deploy on Netlify:

Deploy to Netlify

Try it out

  1. git clone https://github.com/sw-yx/boring-SSG.git
  2. cd boring-SSG
  3. yarn (or npm install)
  4. yarn start, this should build your pages into the /dist folder and serve from there.

Things to notice:

  • Site works with Javascript off
  • After the initial load, the app rehydrates and all routing is clientside (including dynamic routes)
  • If you refresh on any page, the server serves that page's HTML and rehydrates from there, it doesn't simply serve index.html and navigates you back.
  • for invalid URLs, 404 page is served.

Usage of boring-SSG

Everything inside /src should be a fully standalone app. @reach/router is used for accessibility-first routing and it has the very nice ability of nested routes which don't need a separate idiom to account for in the static page generation.

The static page generation is currently set up in boring.config.js. Currently the only active API here is getRoutes, where you only return an array of whitelisted routes for static page generation. This array can be programmatically generated, so you are free to write Node.js crawlers to import and (in future) inject data. You do not need to whitelist a "404" route, this is done for you in the background.

// Example boring.config.js
export default {
  getRoutes: async () => {
    // you can pull data sources in here
    return [
      {
        path: '/'
        // in future you can inject data here as well
      },
      {
        path: '/about'
      },
      {
        path: '/blog'
      }
    ]; // generate more pages based on data
  }
};

Discussion of Approach

Public API

Making the right tradeoff of developer ergonomics and flexibility is a very difficult needle to thread. I have studied Gatsby and a few of the more recent entries like Docusaurus and React-Static to get inspiration for this approach.

Ultimately I like React-Static's philosophy a lot, where everything inside src makes sense as a React app with no magic folders, and the static generation is all done in a single config.js file where you can also do data injection.

Due to lack of time I haven't been able to experiment/innovate here as much as I would want, but I definitely think there is a lot of promise here to create plugins with a small API surface area that reduce the level of configuration for 80% use cases.

Under the Hood

A key design consideration for me was to have a rehydrated static site, not just a simple static site. This raised the difficulty but I consider it mandatory in the modern JAMstack era.

I iterated through a couple of approaches before landing on the current method. I originally tried to generate a custom bundle for every generated page, but that proved extremely verbose and probably inadvisable for scaling.

There was another attempt I made at hooking into Parcel's internal Event system, but frankly they aren't well documented and didn't even seem to work at all. This would have been much nicer to hook into for page generation even without a whitelist, which is a very interesting goal, but could also be important for fast multi-asset bundling (incl code split by default). This is probably something to return to when Parcel v2 is out.

The current method is much simpler. Essentially the site generation process is fast because the SSR'ed pages and the bundle can be run in parallel. Because all we need to know from the bundle to inject into the page is the name of the bundle, the simplistic approach we have now (doesn't include multiple assets) is sufficient to generate the pages even before the bundler is done.

Performance: although of course boring-ssg does much less than Gatsby so this is a terrible measurement, I looked into the measured performance for essentially the same tasks (rendering gatsby-starter-netlify-cms from Markdown + JSX to JAMstack HTML) takes boring-ssg 2-6 seconds (depending on cache) and for Gatsby about 45 seconds, or about 87% less build time.

image image

The details

The rehydration is achieved by having a single app shell, called the "BoringShell", which hydrates the HTML if on clientside, but otherwise is just a thin shell around the actual App defined in /src. The accompanying Chrome React component handles the HTML meta tags and the asset injection based on its assets prop. (more work to do here to handle multiple assets)

Routing is done by simulating the route based on the config's whitelist. This makes rehydration very straightforward.

Data injection is a tricky topic. The very optimal approach is to chunk up data so that only necessary data is fetched for any particular route, but I didn't have time to coordinate how this might work between the server rendering and clientside bundle. So I essentially punted on it by opting for a "big ball of data" - just as we serve the same JS bundle for the entire site to rehydrate, we, we also serve the same json data ball for the entire site to use. It's not at all efficient but it made the project work within the timeframe.

CSS is another tricky bit. The gold standard (eg Gatsby) would inline CSS automatically so that the initial render looks good without flash of unstyled content. I have not gotten to it - and just serve a main css bundle.


Todos

  • Work out CSS/multiple asset bundling
  • basic data injection model (big ball of data)
  • Demonstrate split data injection model (may require creating addtional library level components)
  • Test production build
  • Inline css to every page.
  • NetlifyCMS integration

Prototype Goal

Currently this is just a "breakable toy" to do R&D for https://github.com/sw-yx/create-jamstack-app, which is the actual CLI based SSG that has the infrastructure to support a more maintainable and fast versino of boring-SSG.

boring-ssg's People

Contributors

swyxio avatar tsiq-swyx avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

boring-ssg's Issues

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.