2016-09-06 160 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

感謝詳細的解答! –

相關問題