React路由器服务器端无法正常工作

时间:2016-11-02 14:27:54

标签: javascript node.js reactjs heroku react-router

我的应用代码在这里:https://github.com/WebTerminator/aldemar/commits/master

我正在努力让我的反应应用程序在服务器端工作,在这个阶段它部分工作。

我遇到的问题是:(sam问题发生在localhost上)

如果我在浏览器中导航它一切正常,我刷新此URL的时刻https://aldemar-productions.herokuapp.com/projects/margam2我收到如下控制台错误:

  

bundle.js:1 Uncaught SyntaxError:意外的令牌<   enter image description here

如果我刷新其他网址,例如“https://aldemar-productions.herokuapp.com/projects”或“https://aldemar-productions.herokuapp.com/about”,则可以正常使用。

server.js

import express from 'express';
import path from 'path';
import React from 'react';
import { renderToString } from 'react-dom/server';
import { match, RouterContext } from 'react-router';
import routes from './src/client/app/config/routes.jsx';

let port = process.env.PORT || 8080;
let app = express();

app.use(express.static('src/client/'));

// app.get('/', (req, res) => {
//  res.sendFile(path.resolve(__dirname + '/src/client/index.html'))
// });

app.get('*', (req, res) => {
  match(
    { routes, location: req.url },
    (err, redirectLocation, renderProps) => {

      // in case of error display the error message
      if (err) {
        return res.status(500).send(err.message);
      }

      // in case of redirect propagate the redirect to the browser
      if (redirectLocation) {
        return res.redirect(302, redirectLocation.pathname + redirectLocation.search);
      }

      // generate the React markup for the current route
      let markup;
      if (renderProps) {
        // if the current route matched we have renderProps
        markup = renderToString(<RouterContext {...renderProps}/>);
      } 
      // else {
      //   // otherwise we can render a 404 page
      //   markup = renderToString(<NotFoundPage/>);
      //   res.status(404);
      // }

      // render the index template with the embedded React markup
      return res.sendFile('index.html', {root : __dirname + '/src/client/'});
    }
  );
});

app.listen(port);
console.log('server started');

routes.jsx

import React from 'react';
import { Route, Router, browserHistory } from 'react-router';
import ReactDOM from 'react-dom';

import Wrapper       from './../components/wrapper.jsx';
import Home          from './../components/home.jsx';
import Projects      from './../components/projects.jsx';
import SingleProject from './../components/projectContent/singleProject.jsx';
import About         from './../components/aboutUs.jsx'

if(typeof window !== 'undefined') {
    console.log('here baby');
    ReactDOM.render((
        <Router history={browserHistory} >
            <Route component={Wrapper} >
                <Route path="/" component={Home} />
                <Route path="projects" component={Projects} />
                <Route path="projects/:id" component={SingleProject} />
                <Route path="about" component={About} />
            </Route>
        </Router>
    ), document.getElementById('app'));
}

singleProject.jsx(我从url获取ID参数以加载特定数据)

import React from 'react';

import Video       from  './../video.jsx';
import Overview    from  './overview.jsx';
import Photography from  './photography.jsx';
import Details     from  './details.jsx';
import Cast        from  './cast.jsx';

import porgectsCollection from './../../data/projectInfo.js';

import { StickyContainer, Sticky } from 'react-sticky';

class Nav extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      mobileMenu: false
    };
  }
  showMobileMenu () {
    this.setState({ mobileMenu: !this.state.mobileMenu });
  }
  render () {
    let links = this.props.project.links.map(function(el, i){
      return <li key={i}>{el}</li>;
    });
    const open = this.state.mobileMenu ? ' open' : '';

    return (
      <Sticky stickyClassName="sticky-nav" topOffset={-100}>
        <span onClick={this.showMobileMenu.bind(this)} className="mobile-trigger">X</span>
        <nav className={"secondary-nav" + open}>
          <ul>
            {links}
          </ul>
        </nav>
      </Sticky>
    );
  }
}

class SingleProject extends React.Component {
  getProjectDataFromUrl() {
    return **porgectsCollection.filter(el => el.title === this.props.params.id)**;
  }
  render () {
    let data = this.getProjectDataFromUrl(),
        project = data[0];
    return (
        <section className="project-page">
        <StickyContainer>
          <Video project={project} />
          <Nav project={project} />
          <Overview project={project} />
          <Photography project={project} />
          <Details project={project}  />
          <Cast project={project} />
        </StickyContainer>
        </section>
    );
  }
}

export default SingleProject;

当我点击这样的网址“https://aldemar-productions.herokuapp.com/projects/margam2”时,根据我的路线收集“margam2”:

<Route path="projects/:id" component={SingleProject} />

我根据该参数加载特定数据。我相信这个问题就在于做服务器端渲染。

UPDATE-1

在我的index.html的头部添加这个内容可以在我刷新页面时显示内容,但缺少CSS:

<base href="/" />

http://localhost:8080/css/style.css可以完全访问css,但是当我刷新“http://localhost:8080/projects/margam2”时,会显示内容但不显示css。

2 个答案:

答案 0 :(得分:1)

经过2天的研究,这对我有所帮助:

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title></title>
    **<base href="/" />**
    <link rel="stylesheet" href="./css/foundation.min.css">
    <link href="https://fonts.googleapis.com/css?family=Montserrat:400,700" rel="stylesheet">
    <link rel="stylesheet" href="./css/font-awesome.min.css">
    <link rel="stylesheet" href="./css/style.css">
    <link rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/slick-carousel/1.6.0/slick.min.css" />
    <link rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/slick-carousel/1.6.0/slick-theme.min.css" />
  </head>
  <body>
    <div id="app"></div>
    <script src="./public/bundle.js" type="text/javascript"></script>
  </body>
</html>

然而我也在我的控制台中发现了这个:

browser.js:49警告:不推荐使用自动设置basename,将在下一个主要版本中删除。语义与basename略有不同。请在createHistory

选项中明确传递basename

所以需要为此找到解决方案。

<强>更新-1

我认为,甚至更好的解决方案。我已经相对于绝对更改了资产路径表单:

查看每个本地资产前面的“/”

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title></title>
    <link rel="stylesheet" href="/css/foundation.min.css">
    <link href="https://fonts.googleapis.com/css?family=Montserrat:400,700" rel="stylesheet">
    <link rel="stylesheet" href="/css/font-awesome.min.css">
    <link rel="stylesheet" href="/css/style.css">
    <link rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/slick-carousel/1.6.0/slick.min.css" />
    <link rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/slick-carousel/1.6.0/slick-theme.min.css" />
  </head>
  <body>
    <div id="app"></div>
    <script src="/public/bundle.js" type="text/javascript"></script>
  </body>
</html>

答案 1 :(得分:0)

在项目的页面上,您使用的是内联关闭div,如下所示:

<div id="app" />

在所有其他页面中,您使用的是空div

<div id="app" > </div>

这是正确的方法。

React-Router不会重新呈现您的网页,只会将您的反应代码“重新添加”到您的 id =“app”
这就是为什么当你打开它点击它时工作,当你刷新它时,它就会崩溃。