React Router v4(找不到页面)服务器端渲染

时间:2017-07-31 07:22:09

标签: javascript reactjs deployment react-router serverside-rendering

我花了两天多时间寻找解决问题的方法,我真的需要你的帮助。

将我的示例部署到服务器并到达site.com/home之类的页面后重新加载此页面后,我收到错误:找不到此服务器上找不到请求的URL / URL

在React Router文档中,我发现为了防止出现这个问题,我需要使用SSR,但每次尝试使用这些代码和其他代码来解决这个问题时,我都会遇到同样的错误。< / p>

来自https://reacttraining.com/react-router/

的示例代码

目录地图:

modules
  - App.js
node_modules
public
  - bundle.js
  - index.css
  - index.html
index.js
package.json
package-lock.json
server.bundle.js
server.js
webpack.config.js
webpack.server.config.js

App.js

import React from 'react'
import {
  BrowserRouter as Router,
  Route,
  Link
} from 'react-router-dom'

const App = () => (
  <Router>
    <div>
      <ul>
        <li><Link to="/">Home</Link></li>
        <li><Link to="/about">About</Link></li>
        <li><Link to="/topics">Topics</Link></li>
      </ul>

      <hr/>

      <Route exact path="/" component={Home}/>
      <Route path="/about" component={About}/>
      <Route path="/topics" component={Topics}/>
    </div>
  </Router>
)

const Home = () => (
  <div>
    <h2>Home</h2>
  </div>
)

const About = () => (
  <div>
    <h2>About</h2>
  </div>
)

const Topics = ({ match }) => (
  <div>
    <h2>Topics</h2>
    <ul>
      <li>
        <Link to={`${match.url}/rendering`}>
          Rendering with React
        </Link>
      </li>
      <li>
        <Link to={`${match.url}/components`}>
          Components
        </Link>
      </li>
      <li>
        <Link to={`${match.url}/props-v-state`}>
          Props v. State
        </Link>
      </li>
    </ul>

    <Route path={`${match.url}/:topicId`} component={Topic}/>
    <Route exact path={match.url} render={() => (
      <h3>Please select a topic.</h3>
    )}/>
  </div>
)

const Topic = ({ match }) => (
  <div>
    <h3>{match.params.topicId}</h3>
  </div>
)

export default App

index.html - 包含容器ID =&#34; app&#34;的简单页面和脚本src =&#34; bundle.js&#34;

index.js

import React from 'react'
import ReactDOM from 'react-dom'
import { BrowserRouter } from 'react-router-dom'
import App from './modules/App'

ReactDOM.render((
  <BrowserRouter>
    <App/>
  </BrowserRouter>
), document.getElementById('app'))

的package.json

    {
  "name": "",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "start": "if-env NODE_ENV=production && npm run start:prod || npm run start:dev",
    "start:dev": "webpack-dev-server --inline --content-base public/ --history-api-fallback",
    "start:prod": "npm run build && node server.bundle.js",
    "build:client": "webpack",
    "build:server": "webpack --config webpack.server.config.js",
    "build": "npm run build:client && npm run build:server"
  },
  "author": "",
  "license": "ISC",
  "dependencies": {
    "compression": "^1.6.1",
    "express": "^4.13.4",
    "http": "0.0.0",
    "if-env": "^1.0.0",
    "react": "^0.14.7",
    "react-dom": "^0.14.7",
    "react-router": "^2.0.0",
    "react-router-dom": "^4.1.2"
  },
  "devDependencies": {
    "babel-core": "^6.5.1",
    "babel-loader": "^6.2.2",
    "babel-preset-es2015": "^6.5.0",
    "babel-preset-react": "^6.5.0",
    "http-server": "^0.8.5",
    "webpack": "^1.12.13",
    "webpack-dev-server": "^1.14.1"
  }
}

server.js

import { createServer } from 'http'
import React from 'react'
import ReactDOMServer from 'react-dom/server'
import { StaticRouter } from 'react-router'
import App from './modules/App'

createServer((req, res) => {
  const context = {}

  const html = ReactDOMServer.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>
      <div id="app">${html}</div>
    `)
    res.end()
  }
}).listen(3000)

webpack.config.js

var webpack = require('webpack')
module.exports = {
  entry: './index.js',
  output: {
    path: 'public',
    filename: 'bundle.js',
    publicPath: '/'
  },
  plugins: process.env.NODE_ENV === 'production' ? [
    new webpack.optimize.DedupePlugin(),
    new webpack.optimize.OccurrenceOrderPlugin(),
    new webpack.optimize.UglifyJsPlugin()
  ] : [],
  module: {
    loaders: [
      { test: /\.js$/, exclude: /node_modules/, loader: 'babel-loader?presets[]=es2015&presets[]=react' }
    ]
  }
}

webpack.server.config.js

var fs = require('fs')
var path = require('path')
module.exports = {
  entry: path.resolve(__dirname, 'server.js'),
  output: {
    filename: 'server.bundle.js'
  },
  target: 'node',

  // keep node_module paths out of the bundle
  externals: fs.readdirSync(path.resolve(__dirname, 'node_modules')).concat([
    'react-dom/server', 'react/addons',
  ]).reduce(function (ext, mod) {
    ext[mod] = 'commonjs ' + mod
    return ext
  }, {}),

  node: {
    __filename: true,
    __dirname: true
  },

  module: {
    loaders: [
      { test: /\.js$/, exclude: /node_modules/, loader: 'babel-loader?presets[]=es2015&presets[]=react' }
    ]
  }
}

在localhost上一切正常。 我将非常感谢任何帮助。

1 个答案:

答案 0 :(得分:0)

从您的应用程序中删除路由器,因为您已将其添加到BrowserRouter和StaticRouter。

const App = () => (
  <div>
    <ul>
      <li><Link to="/">Home</Link></li>
      <li><Link to="/about">About</Link></li>
      <li><Link to="/topics">Topics</Link></li>
    </ul>

    <hr/>

    <Route exact path="/" component={Home}/>
    <Route path="/about" component={About}/>
    <Route path="/topics" component={Topics}/>
  </div>
)