antwarjs / antwar

A static site generator built with React and Webpack.
https://antwar.js.org/
MIT License
460 stars 35 forks source link

Support full React Functionality #103

Closed skipjack closed 8 years ago

skipjack commented 8 years ago

Creating this issue to discuss the possibility of supporting further React functionality after the initial render such as state, component lifecycle, type checking of incoming props, etc.

I guess this would mean including a copy of React on each static page, which might start to defeat the point of running a static build...

This seems somewhat related to #71, after quickly reading through the docs I'm still somewhat unsure of a recommended way to include raw scripts in the build.

bebraw commented 8 years ago

Would Preact work? It's so light, I see no harm in adding some kind of support for it. This probably has to be opt-in, but still, not too bad. It will get cached after initial loadimg anyway and the overhead is tiny.

skipjack commented 8 years ago

Never heard of Preact, I'll check it out. And yeah I figured you'd probably want to make this opt-in as I'm sure some people are fine with a simpler build.

skipjack commented 8 years ago

Preact seems like a great option. I didn't even realize anything like this was out there...

Just out of curiosity though, is there a recommended way of including other scripts aside from components. Can they be included via assets or something?

bebraw commented 8 years ago

I gave this some thinking. What if we ended up with something like this?

import React from 'react';
import { Interactive } from 'antwar';
import Container from './Container';
import Visualization from './Visualization';

export default props => {
  let { page } = props;

  return (
    <div className="splash">
      <Interactive id="./Visualization.jsx" component={Visualization} />

      <Container className="splash-content">
        <h1>{ page.title }</h1>
        <div dangerouslySetInnerHTML={{ __html: page.content }} />
      </Container>
    </div>
  );
};

We would annotate each interactive (read: generates script output) section of a layout/page using an Interactive component that accepts the component as a parameter. Passing that id is important too because when I render a page (build/static_page.js), I have access to the page output in a string format. After parsing I should have paths like project_path/components/Visualization.jsx.

The next step is to bundle these individual bits together so that we get the JS. Essentially I will need to write a file like this:

import React from 'react';
import ReactDOM from 'react-dom';
import Visualization from 'Visualization'; // alias for each

ReactDOM.render(
  <Visualization>, // this would be a good chance to pass custom data if you need it
  document.getElementById('./Visualization.jsx') // the id comes in handy here
);

// same for each captured bit so we get multiple imports and renders within the same file
...

After I have written this file, I can generate a bundle using webpack and output it to appropriate place. I probably need to give enough access to its configuration so we can hook up Preact in this step. For now it's ok to bundle it in.

I have a feeling a scheme like this would integrate well with Markdown later on. We would do a similar replacement there so we get inline JSX with a minimal script. I could probably use that myself.

Would this sort of setup work for you?

skipjack commented 8 years ago

Yea I'm pretty sure it would. Definitely needs to be per component, as you've described.

MoOx commented 8 years ago

What do you think about just supporting isomorphic rendering? Phenomic is doing this pretty great and it can be a good idea to merge our effort. Thoughts?

bebraw commented 8 years ago

I have no strong thoughts on isomorphic. For my use case it's enough I get something entirely static out of the generator to push on GitHub Pages.

In its current form Antwar is actually a very light wrapper on webpack. I've stripped a lot of code from it. The biggest bits have to do with routing (react-router 2 iirc) and optimized build process.

For build I run webpack only once and then multiprocess each file against the generated bundle. This is surprisingly fast as you get to benefit from your cores and going with templating like that is a cheap op.

bebraw commented 8 years ago

This particular problem actually means I need to bundle during the build process whenever interactive bits are in place. So that will slow it down a notch. But we'll see how much.

MoOx commented 8 years ago

Phenomic is also mainly a webpack wrapper with a specific loader for content. Here are some number for the build time (we also build in 2 steps, including a node script for static rendering)

bebraw commented 8 years ago

Yeah, esp. dev looks cool. If there's enough overlap, might as well merge projects. The key "selling point" of Antwar for me is the amount of power it provides through configuration. So if we can retain that, why not.