如何在Webpack2中使用HMR实现React服务器端渲染?

时间:2017-04-10 18:03:29

标签: javascript reactjs express webpack react-router

我正在尝试使用我的使用HMR的反应应用程序实现服务器端渲染,并需要对我的问题进行一些澄清。服务器和前端之间似乎存在沟通错误,但我并不完全确定为什么会这样。

当我启动服务器时,浏览器会加载客户端index.html,我可以使用HMR编辑我的网站。但是,当我导航到主页旁边的另一个页面,并刷新浏览器时,服务器然后在我的handleRender函数中呈现html标记。网站html标记出现,但没有CSS和HMR不起作用。

总结一下,在第一次加载时,它会呈现应用程序客户端,但在刷新时,它会呈现应用服务器端。我认为这可能与我使用router.use(express.static(clientDir));的方式有关,但我不确定。任何澄清都会有所帮助!

客户端Index.html

<!doctype html>
<html>
    <head>
        <meta charset="utf-8">

        <title>Base Template</title>

        <link rel="stylesheet" type="text/css" href="/static/bundle.css">
    </head>
    <body id="body">
        <div class="root"></div>
        <script src="/static/bundle.js"></script>
    </body>
</html>

React App index.js

import React from 'react'
import ReactDOM from 'react-dom'
import { AppContainer } from 'react-hot-loader'
import { BrowserRouter } from 'react-router-dom'
import App from './App'

const root = document.querySelector('.root');

// Wraps our App in AppContainer
const render = (Component) => {
  ReactDOM.render(
    <BrowserRouter>
      <AppContainer>
        <Component/>
      </AppContainer>
    </BrowserRouter>,
    root
  );
};

// Renders our application
render(App);

// Checks if there have been changes and accepts them.
// This activates HMR and refreshes modules in the browser
if (module.hot) {
  module.hot.accept();
}

Express Server

import express from 'express'
import React from 'react'
import { renderToString } from 'react-dom/server'
import { StaticRouter } from 'react-router'
import { resolve } from 'path'
import routes from './routes'

// Imports our React App
import App from '../client/scripts/App'

// Create Express App
const app = express();

// Set the port for our server
app.set('port', process.env.PORT || 3000)

// Use routes to check if the environment is prod || dev
app.use(routes)

// Use handleRender for SSR
app.use(handleRender)

function handleRender(req, res) {
  const context = {};

  const html = renderToString(
    <StaticRouter location={req.url} context={context} >
      <App/>
    </StaticRouter>
  )

  if (context.url) {
    res.writeHead(301, {
      Location: context.url
    })
    res.end()
  } else {
    res.write(`
      <!doctype html>
      <head>
        <title>Redux Universal Example</title>
        <link rel="stylesheet" type="text/css" href="/static/bundle.css">
      </head>
      <body>
        <div id="app">${html}</div>
        <script type="javascript" src="/static/bundle.js"></script>
      </body>
    `)
    res.end()
  }
}

export default app

服务器路由

import express, { Router } from 'express'
import { resolve } from 'path'
import { isDev } from '../utils'

const router = Router();
const clientDir = resolve(`${__dirname}/../../client`);

if (isDev()) {
  const webpackDevMiddleware = require('webpack-dev-middleware')
  const webpack = require('webpack')
  const webpackConfig = require('../../../webpack.config')
  const webpackHotMiddleware = require('webpack-hot-middleware')

  const compiler = webpack(webpackConfig)

  // This compiles our app using webpack
  router.use(webpackDevMiddleware(compiler, {
    publicPath: webpackConfig.output.publicPath,
    noInfo: true
  }))

  // This connects our app to HMR using the middleware
  router.use(webpackHotMiddleware(compiler))
}

router.use(express.static(clientDir));

export default router

0 个答案:

没有答案