2016-09-06 125 views
0

我发现了很多有关SSR和React的信息,他们都采用完全不同的方法。所以我发现了一个在我的例子中看起来更有用的例子(React/graphQL/Apollo/Express/Webpack上的Web应用程序),但我坚持一个问题。下面的一些例子:服务器端渲染问题与路由导入

server.js

... 
    import {router} from './client/App'; 
    import React from 'react'; 
    import { renderToString } from 'react-dom/server'; 
    import { match, RoutingContext, Route } from 'react-router'; 
    ... 
    function renderApp(props, res) { 
     const markup = renderToString(<RoutingContext {...props}/>); 
     const html = createPage(markup); 
     write(html, 'text/html', res); 
    } 

    app.get('*', (req, res, next) => { 
      const location = hist.createLocation(req.path); 
      match({routes: router, location: location}, (err, redirectLocation, renderProps) => { 
       if (err) { 
        writeError('ERROR!', res); 
        next(err); 
       } else if (redirectLocation) { 
        redirect(redirectLocation, res); 
       } else if (renderProps) { 
        renderApp(renderProps, res); 
       } else { 
        writeNotFound(res); 
       } 
      }); 
     }); 
    ... 

App.js从我们进口路由器:

... 

import Login from './components/Login'; 
import Register from './components/Register'; 
... 
let routes = (
    <Route> 
     <Route path="login" component={Login}/> 
     <Route path="register" component={Register}/> 
     ... 
    </Route> 
); 

export let router = [{ 
    path: '/', 
    component: Layout, 
    indexRoute: { 
     component: View 
    }, 
    getChildRoutes(location, cb) { 
     require.ensure([],() => cb(null, routes)); 
    } 
}]; 

match({router, location},() => { 
    render(
     <ApolloProvider client={client}> 
      <div> 
       <Router routes={router} onUpdate={() => window.scrollTo(0, 0)} history={browserHistory}/> 
      </div> 
     </ApolloProvider>, 
     document.getElementById('root') 
    ); 
}); 

我试图做的一切都像在这个example,但问题是server.js当我尝试导入routerApp.js服务器不运行,并给我与React组件相关的错误(样式导入等一切我们可以在客户端上做的,但不能在服务器上)。

所以问题是,我做错了什么?如何在不存在此问题的情况下导入路线? 真的很烦人,我已经在这个小任务上花了很多时间。

我将不胜感激任何帮助,谢谢!

回答

1

如您所知,服务器端渲染会在您的节点服务器中呈现您的反应组件。但节点服务器不支持导入css/png文件。

如果您不想更改客户端代码,则可以尝试用户webpack-isomorphic-tools,它将帮助您生成一个assert.json文件,该文件可以使require('* .css')调用返回一个json对象并生成CSS类名映射,就像他们在webpack css-loader中做的一样。

如果你有兴趣,你可以看看demo

这里是你的WebPack同构,tools.js

var WebpackIsomorphicToolsPlugin = require('webpack-isomorphic-tools/plugin'); 


module.exports = { 


    assets: { 
    images: { 
     extensions: [ 
     'jpeg', 
     'jpg', 
     'png', 
     'gif' 
     ], 
     parser: WebpackIsomorphicToolsPlugin.url_loader_parser 
    }, 
    fonts: { 
     extensions: [ 
     'woff', 
     'woff2', 
     'ttf', 
     'eot' 
     ], 
     parser: WebpackIsomorphicToolsPlugin.url_loader_parser 
    }, 
    svg: { 
     extension: 'svg', 
     parser: WebpackIsomorphicToolsPlugin.url_loader_parser 
    }, 

    bootstrap: { 
     extension: 'js', 
     include: ['./src/theme/bootstrap.config.js'], 
     filter: function(module, regex, options, log) { 
     function is_bootstrap_style(name) { 
      return name.indexOf('./src/theme/bootstrap.config.js') >= 0; 
     } 
     if (options.development) { 
      return is_bootstrap_style(module.name) && WebpackIsomorphicToolsPlugin.style_loader_filter(module, regex, options, log); 
     } 

     }, 

     path: WebpackIsomorphicToolsPlugin.style_loader_path_extractor, 
     parser: WebpackIsomorphicToolsPlugin.css_loader_parser 
    }, 
    style_modules: { 
     extensions: ['less','scss'], 
     filter: function(module, regex, options, log) { 
     if (options.development) { 
         return WebpackIsomorphicToolsPlugin.style_loader_filter(module, regex, options, log); 
     } else { 
         return regex.test(module.name); 
     } 
     }, 
     path: function(module, options, log) { 
     if (options.development) { 
         return WebpackIsomorphicToolsPlugin.style_loader_path_extractor(module, options, log); 
     } else { 
         return module.name; 
     } 
     }, 
     parser: function(module, options, log) { 
     if (options.development) { 
      return WebpackIsomorphicToolsPlugin.css_modules_loader_parser(module, options, log); 
     } else { 
       return module.source; 
     } 
     } 
    } 
    } 
} 

和你server.js应该是这样的

function renderFullPage (title, css, html, initialState) { 
    return ` 
     <!DOCTYPE html> 
      <html> 
       <head> 
       <title>${title}</title> 
       <style type="text/css">${css}</style> 
       </head> 
       <body> 
       <div id="app">${html}</div> 

       <script> 
        window.__INITIAL_STATE__ = ${JSON.stringify(initialState)}; 
       </script> 
       <script src="/assets/scripts/app.bundle.js"></script> 
       </body> 
      </html> 
    `; 
} 

const asyncStore = (store, renderProps) => { 
    let promise = Promise.all([ 
     store.dispatch(queryArtistList()), 
     store.dispatch(queryAuth()) 
    ]); 
    return promise; 
} 

const HomeCtrl = { 
    index: async (req, res) => { 
     // 补全同构应用运行时缺失的全局对象 
     global.window = { 
      navigator: { 
       userAgent: req.get('User-Agent'), 
      }, 
      location: { 
       protocol: req.protocol + ':', 
       hostname: req.hostname, 
      }, 
     }; 
     match({ routes, location: req.url }, async (err, redirectLocation, renderProps) => { 
      if (err) { 
       res.status(500).end(`Internal Server Error ${err}`); 
      } else if (redirectLocation) { 
       res.redirect(redirectLocation.pathname + redirectLocation.search + '/'); 
      } else if (renderProps) { 
       let store = configureStore(); 
       const state = store.getState(); 
       await asyncStore(store, renderProps); 
       const components = (<Provider store={store}> 
              <RouterContext {...renderProps} /> 
             </Provider>); 
       const html = renderToStaticMarkup(components); 

       res.end(renderFullPage('tokyo Artist', '', html, store.getState())); 

      } else { 
       res.status(404).end('Not found'); 
      } 
     }) 
    } 
} 

,并请确保,启动服务器后,你有你的生成webpack-asserts.json;

所以你app.js应该是这样的:

#!/usr/bin/env node 
const path = require('path'); 
const rootDir = path.resolve(__dirname, '..'); 
const fs = require('fs'); 

const babelrc = fs.readFileSync(rootDir + '/.babelrc', 'utf-8'); 
var config; 

try { 
    config = JSON.parse(babelrc); 
} catch (err) { 
    console.error('==>  ERROR: Error parsing your .babelrc.'); 
    console.error(err); 
} 

require('babel-register')(config); 

/** 
* Define isomorphic constants. 
*/ 
global.__CLIENT__ = false; 
global.__SERVER__ = true; 
global.__DEVELOPMENT__ = process.env.NODE_ENV !== 'production'; 
global.__DEVTOOLS__ = __DEVELOPMENT__; 


const WebpackIsomorphicTools = require('webpack-isomorphic-tools'); 
global.webpackIsomorphicTools = new WebpackIsomorphicTools(require('../webpack/webpack.isomorphic-tools')) 
    .development(__DEVELOPMENT__) 
    .server(__DEVELOPMENT__ ? __dirname : rootDir, function() { 
     require('../server/app.js'); 
    }); 
+0

感谢详细的解答! –