Last active
February 26, 2018 05:28
-
-
Save jonjaques/0b118d527b7527f7973f1ea108ae42a4 to your computer and use it in GitHub Desktop.
Reload your app on the server too; `web.js` is the entrypoint on the browser, `renderer.js` is a verrry simple middleware for server rendering. Ideally you wouldn't be passing content in the entry points, only config.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import React from 'react' | |
import Foo from './foo' | |
import {hot} from 'react-hot-loader' | |
export default hot(module)(App) | |
function App(props) { | |
return <h1> | |
{props.message} | |
<Foo foo={100} /> | |
</h1> | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import Path from 'path' | |
import * as Pirates from 'pirates' | |
import Webpack from 'webpack' | |
import WebpackDevMiddleware from 'webpack-dev-middleware' | |
import WebpackHotMiddleware from 'webpack-hot-middleware' | |
export default function DevMiddleware() { | |
const env = process.env.NODE_ENV || 'development' | |
const [web, server] = require('../../webpackfile.babel') | |
const webCompiler = Webpack(web(env)) | |
const serverCompiler = Webpack(server(env)) | |
const devMiddleware = WebpackDevMiddleware(webCompiler, { | |
logLevel: 'warn', | |
publicPath: web(env).output.publicPath | |
}) | |
const hotMiddleware = WebpackHotMiddleware(webCompiler) | |
const serverMiddleware = WebpackServerMiddleware(serverCompiler, 'dist/node.js') | |
return [ | |
devMiddleware, | |
hotMiddleware, | |
serverMiddleware | |
] | |
} | |
// Only cares about one module | |
function WebpackServerMiddleware(compiler, path) { | |
const appPath = Path.resolve(path) | |
// Build an instance of the dev middleware so we can | |
// plunder it's memory filesystem | |
const dev = WebpackDevMiddleware(compiler, {logLevel: 'warn'}) | |
const booty = dev.context.compiler.outputFileSystem | |
// Hook into require so we can use the memoryFs provided by webpack | |
Pirates.addHook(hook, { exts: ['.js', '.jsx'], matcher }) | |
return middleware | |
function hook (code, filename) { | |
return booty.readFileSync(filename).toString() | |
} | |
function matcher (filename) { | |
return booty.existsSync(filename) | |
} | |
function middleware (req, res, next) { | |
// We actually use the dev middleware here not because we need it, but because it | |
// has code to hold up the request until the bundle is finished compiling | |
dev(req, res, (err) => { | |
try { | |
// Blow away cached module | |
delete require.cache[appPath] | |
// Attach the module to the response for use | |
// further down the middleware chain | |
res.locals.app = require(appPath) | |
} catch(err) { | |
console.log(`Error compiling app: \n` + err.stack) | |
} finally { | |
next(err) | |
} | |
}) | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import React from 'react' | |
import ReactDOM from 'react-dom/server' | |
export default function Renderer() { | |
return (req, res, next) => { | |
if (!res.locals.app) throw new Error("Couldn't locate app") | |
const App = res.locals.app.default | |
const tree = <App message="Hello, friend" /> | |
res.type('html').send(` | |
<!doctype html> | |
<div id="application">${ReactDOM.renderToString(tree)}</div> | |
<script src="/assets/web.js"></script> | |
`.trim()) | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import Path from 'path' | |
import Express from 'express' | |
import compression from 'compression' | |
import {json} from 'body-parser' | |
import devMiddleware from './middleware/dev' | |
import renderer from './middleware/renderer' | |
import errorHandler from './middleware/errors' | |
const app = Express() | |
export default app | |
app.use(compression()) | |
app.use(json()) | |
if (__DEVELOPMENT__) { | |
app.use(devMiddleware()) | |
} | |
app.use('/assets', | |
Express.static(Path.resolve('dist')), | |
Express.static(Path.resolve('assets')) | |
) | |
app.use(renderer()) | |
app.use(errorHandler()) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import React from 'react' | |
import ReactDOM from 'react-dom' | |
import Foo from './app' | |
const pageNode = document.getElementById('application') | |
ReactDOM.hydrate(<Foo message="Hello, friend" />, pageNode) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import Path from 'path' | |
import Webpack from 'webpack' | |
import NodeExternals from 'webpack-node-externals' | |
module.exports = [ | |
config('web'), | |
config('node'), | |
] | |
export function config(target = 'web') { | |
return env => { | |
const c = { | |
target, | |
context: Path.resolve('app'), | |
entry: { | |
[target]: target === 'web' ? ['./web.js'] : ['./index.js'], | |
}, | |
output: { | |
filename: '[name].js', | |
path: Path.resolve('dist') | |
}, | |
module: { | |
rules: [ | |
{ test: /\.jsx?$/, | |
loader: 'babel-loader', | |
include: [ | |
Path.resolve('app'), | |
Path.resolve('lib') | |
] | |
} | |
] | |
}, | |
externals: [], | |
plugins: [], | |
} | |
if (target === 'web') { | |
c.entry[target].unshift('babel-polyfill') | |
c.output.publicPath = '/assets' | |
if (env === 'production') { | |
c.plugins.push(new Webpack.optimize.UglifyJsPlugin()) | |
} | |
else { | |
c.entry[target].unshift('webpack-hot-middleware/client') | |
c.plugins.push(new Webpack.HotModuleReplacementPlugin()) | |
} | |
} | |
else if (target === 'node') { | |
c.output.libraryTarget = 'commonjs2' | |
c.externals = [NodeExternals()] | |
c.node = false | |
} | |
return c | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment