markdalgleish / static-site-generator-webpack-plugin

Minimal, unopinionated static site generator powered by webpack
MIT License
1.61k stars 97 forks source link

react router 2 compatibility #34

Open XOP opened 8 years ago

XOP commented 8 years ago

Changes have been introduced in the new version or react-router: https://github.com/reactjs/react-router/blob/master/upgrade-guides/v2.0.0.md

Plugin fails on routing now.

schneidmaster commented 8 years ago

Just needs a documentation update. This works for me with react-router 2.0:

import React from 'react';
import ReactDOM from 'react-dom';
import ReactDOMServer from 'react-dom/server';
import { Router, RouterContext, match, browserHistory, createMemoryHistory } from 'react-router';

import routes from './routes';
import template from './template.ejs';

// Client render (optional): 
if (typeof document !== 'undefined') {
  const outlet = document.getElementById('outlet');
  ReactDOM.render(<Router history={browserHistory} routes={routes} />, outlet)
}

// Exported static site renderer: 
export default (locals, callback) => {
  const history = createMemoryHistory();
  const location = history.createLocation(locals.path);

  match({ routes, location }, (error, redirectLocation, renderProps) => {
    callback(null, template({
      html: ReactDOMServer.renderToString(<RoutingContext {...renderProps} />),
      assets: locals.assets
    }));
  });
};
robinrendle commented 8 years ago

@schneidmaster Do you happen to have a repo of that working somewhere or perhaps a link to a tutorial that explains React Router 2 in more depth? I’m confused as to what’s going in with template.

schneidmaster commented 8 years ago

Hey @robinrendle -- the template part references the EJS template in the official documentation's example. You can check out this repo (particularly coffee/router.coffee) if you want a complete example of React Router 2 + static-site-generator-webpack-plugin.

MessyFork commented 8 years ago

Hi @schneidmaster I'm having trouble making the client render. Currently my project seems to serve files as just static html pages without javascript. routes.txt

Is this because of the way this is set up or is there something else I'm missing?

schneidmaster commented 8 years ago

@MessyFork Hard to tell without more context from your project. You also need webpack-dev-server, an index.html (or a plugin that generates it) with an #outlet ID, etc. Nothing in that snippet looks incorrect offhand though.

MessyFork commented 8 years ago

I've uploaded my project to this repo

My webpack config properly builds the static site into ./build and the dev-server also works properly disregarding my original issue.

One thing I noticed was when I downloaded and ran this example the react-detector plugin in chrome would light up. When using the dev-server on my project it does not.

(as a side note were you the developer for the Bernie repo you posted? I can't believe it was static this whole time)

schneidmaster commented 8 years ago
  1. You need to change bundle to bundle.js here so that doesn't 404
  2. You're correctly using document.getElementById('outlet') here but you are setting outlet as a class (not an id) here
  3. You're then going to get errors about html not being a permissible child of div -- this is a somewhat deeper problem with your setup, because your static renderer is always rendering the whole component (HTML included) but then when rendering over the static markup at runtime you're sticking the whole thing (html tags and all) inside div#outlet. You need to have your app's outmost component just be a div and then specially render it inside a <html> wrapper for static rendering, e.g. this code which references this full-page component.

And yep, I developed most of that. Static made a lot of sense because it was a high-traffic site that we couldn't have crash on election day, and React helped us make it interactive.

MessyFork commented 8 years ago

Goodness I have much to learn... Thank you so much it's taken me two days to get to this far and I was about to give up and just use plain HTML and CSS.

I started this project from looking at this post and got too excited before realizing that it used deprecated versions of React and Router when I updated both packages...

I saw your Root component earlier but I was unsure how you were able to pass in the location prop and use it like a Router component. I suppose there's no simpler method of doing this?

schneidmaster commented 8 years ago

No problem. Yeah, react-router changes its API annoyingly frequently, and not many people seem to do static site generation with React for whatever reason (I personally find it a very nice pattern) so it's a bit of a wild west.

The location bit works because of how the static site generator plugin works. It basically just renders & outputs HTML for each of the paths you give it (in your case, the ones in data.js) and then in the router you create a history location from the raw path. It's not actually necessary to pass the location to the Root component though -- it's only needed if you want to change the page meta content (title, etc) based on the current path (like what I did here).

Can't really say there's a simpler method of doing static generation, unfortunately. You could always deploy your site as a "regular"/non-static React site; this is worse for SEO because many page crawlers don't know how to javascript, but you might not care if it's just a portfolio site. You could also do server-side rendering with node.js; this is a quite good overview of React prerendering in general and server-side rendering specifically.

MessyFork commented 8 years ago

I first found out about React when I was building a instagram clone as a portfolio project. Wrote a whole backend with a REST API in django and decided it was time to make a pretty front for it. The main appeal for me was that it felt as if I was just writing a mobile app for the browser since the communication with the backend would be through ajax calls.

I think I get what's going on now in the router file from your explanations. I'll mess around and see if I can solve my problems now. Thank you so much again. Do you have a preferred mode of contact so I don't bog down this issue tracker?

schneidmaster commented 8 years ago

Yeah feel free to send me a mail, it's in my github profile.

bbrock25 commented 8 years ago

here's an example using react router 2.8.1. thanks for the great work!

https://github.com/spartansystems/react-webpack-static-example

svnm commented 8 years ago

I had some trouble getting started and eventually found my way to this issue, which thanks to @MessyFork, @schneidmaster and @bbrock25 gave me some nice examples. I set up my own fairly minimal example using static-site-generator-webpack-plugin over here and was just wondering if it would be useful to create a pr adding the example to this repo to make it easy for new users to get up and running.