2017-02-17 160 views
1

我试图用ReactJS构建我的第一个服务器端渲染。我已经基于我的代码this Redux tutorialReactJS服务器端热渲染(webpack-dev-server)渲染

运行时应用程序正常工作npm start(​​)。

我想使用热重载能够在开发环境上做一个应用程序快速调试。所以我在我的npm配置(webpack-dev-server --inline --hot)上添加了start选项。请注意,我没有index.html文件,因为react-router选择正确的JSX文件加载。

npm start打开我的公用文件夹并显示文件,但没有启动我的应用程序。通常我会点击一个index.html文件,但我没有。

我不明白发生了什么,不知道如何解决。帮助赞赏。

的package.json:

"scripts": { 
    "test": "echo \"Error: no test specified\" && exit 1", 
    "build": "webpack --config webpack.config.prod.js -p", 
    "start": "webpack-dev-server --inline --hot", 
    "dev": "webpack && node server.js" 
    }, 

webpack.config.js:

module.exports = { 
    entry: './client.js', 
    output: { 
     filename: 'bundle.js', 
     path: __dirname + '/public' 
    }, 
    module: { 
     loaders: [ 
      { 
       test: /\.jsx?$/, 
       exclude: /node_modules/, 
       loader: 'babel-loader', 
       query: { 
        presets: ['react', 'es2015', 'stage-0'] 
       } 
      } 
     ] 
    } 
}; 

server.js

require('babel-register')({ 
    presets: ['react', 'es2015', 'stage-0'] 
}); 

var express = require('express'); 
var config = require('config'); 
var app = express(); 

var serverConfig = config.get('serverConfig'); 

app.use(express.static('public')); 
app.use(require('./routes/index.jsx')); 

app.listen(serverConfig.port, function() { 
    console.log('FactoryWays server running on port ' + serverConfig.port); 
    console.log('Press CTRL-C to stop the server.'); 
}); 

个client.js

var ReactDOM = require('react-dom'); 
var React = require('react'); 
var routes = require('./routes/routes.jsx'); 
var Redux = require('redux'); 
var Provider = require('react-redux').Provider; 

function reducer(state) { return state; } 

var store = Redux.createStore(reducer, window.PROPS); 

ReactDOM.render(
    <Provider store={store}> 
     {routes} 
    </Provider>, document 
); 

路由/ index.jsx:

var router = require('express').Router(); 
var React = require('react'); 
var ReactDOMServer = require('react-dom/server'); 
var ReactRouter = require('react-router'); 
var Redux = require('redux'); 
var Provider = require('react-redux').Provider; 

function reducer(state) { return state; } 

router.get('*', function(request, response) { 
    var initialState = { title: 'Universal React' }; 
    var store = Redux.createStore(reducer, initialState); 

    ReactRouter.match({ 
     routes: require('./routes.jsx'), 
     location: request.url 
    }, function(error, redirectLocation, renderProps) { 
     if (renderProps) { 
      var html = ReactDOMServer.renderToString(
       <Provider store={store}> 
        <ReactRouter.RouterContext {...renderProps} /> 
       </Provider> 
      ); 
      response.send(html); 
     } else { 
      response.status(404).send('Not Found'); 
     } 
    }); 
}); 

module.exports = router; 

路由/ routes.jsx:

var React = require('react'); 
var ReactRouter = require('react-router'); 
var Router = ReactRouter.Router; 
var Route = ReactRouter.Route; 
var IndexRoute = ReactRouter.IndexRoute; 
var browserHistory = ReactRouter.browserHistory; 

module.exports = (
    <Router history={browserHistory}> 
     <Route path='/' component={require('../views/Layout.jsx')}> 
      <IndexRoute component={require('../views/Index.jsx')} /> 
     </Route> 
    </Router> 
); 

视图/ Layout.jsx:

var React = require('react'); 
var Link = require('react-router').Link; 
var connect = require('react-redux').connect; 

var Layout = React.createClass({ 
    _handleClick: function() { 
     alert(); 
    }, 
    render: function() { 
     var custom = this.props.custom; 
     return (
      <html> 
       <head> 
        <title>{custom.title}</title> 
        <link rel='stylesheet' href='/style.css' /> 
       </head> 
       <body> 
        <h1>{custom.title}</h1> 
        <p>Isn't server-side rendering remarkable?</p> 
        <button onClick={this._handleClick}>Click Me</button> 
        {this.props.children} 
        <ul> 
         <li> 
          <Link to='/'>Home</Link> 
         </li> 
         <li> 
          <Link to='/about'>About</Link> 
         </li> 
        </ul> 
        <script dangerouslySetInnerHTML={{ 
         __html: 'window.PROPS=' + JSON.stringify(custom) 
        }} /> 
        <script src='/bundle.js' /> 
       </body> 
      </html> 
     ); 
    } 
}); 

var wrapper = connect(
    function(state) { 
     return { custom: state }; 
    } 
); 

module.exports = wrapper(Layout); 

回答

3

请注意,我没有index.html文件作为反应,路由器选择合适的JSX文件加载

你仍然需要一个,如果你正在运行webpack-dev-server

Webpack用于将JavaScript捆绑在一起。而已。在你的情况下(基于你的webpack.config.js文件),它将在你的public目录中输出一个bundle.js文件。

Webpack Dev Server是一个简单的静态文件服务器来帮助开发。它不知道关于server.js中服务器配置的任何信息。

你的两个命令在你的包中。JSON需要不同的设置:

npm start

npm start运行webpack-dev-server。默认情况下,webpack-dev-server将提供当前目录的内容,因此您需要将index.html放置在项目的根目录中。 index.html的内容很简单:只包含一个script标签的样板HTML链接到您的bundle.js文件。

npm dev

当你运行npm dev但是,你滚你自己的服务器,在server.js定义。在这种情况下,它被配置为为您生成并提供index.html(以及您需要的所有其他静态文件)。

如果你想做热转储运行你自己的服务器,你可以添加webpack-dev-middleware到你的Express服务器。

+0

感谢@bejado的帖子。一些问题:1.我知道我的index.html内容应该等于'views/Layout.jsx'中的内容。然后,我可以从该内容创建一个index.html文件,并在'dev'和'start'中为它提供服务。请详细说明2.我的最终目标是运行我的服务器并进行热重新加载。那么,我应该将webpack-dev-server更改为webpack-dev-middleware?我应该在生产和开发中做到这一点(我不需要它)?我怎样才能配置这两个条件?如果可以,请详细说明两种情况。 – Mendes

+0

另外,我见过webpack-hot-middleware。这与什么有关? – Mendes