我正在努力将我的react v0.14 redux v3.0 react-router v1.0代码库从客户端渲染转移到服务器端渲染,使用webpack v1.12捆绑和代码分割成块来加载路由和组件一经请求.
我跟随并将我的设置基于https://github.com/rackt/example-react-router-server-rendering-lazy-routes,因为我认为它提供了简单性和出色的实用程序.整天昨天我一直在努力转向服务器端渲染,但我遇到了一些我无法解决的问题,我不能完全确定它们是否因为webpack没有正确设置,如果我正在做在服务器/客户端或路由配置上的react-router出了什么问题,或者如果我设置了导致这些问题的redux的错误.
我遇到了以下问题:
>我能够加载初始页面,一切运行良好,但没有其他路线加载,并给了我GET http://localhost:3000/profile 404 (Not Found)
>索引/主页javascript可以工作,但所有资产(css)都呈现为text / javascript,因此样式不会显示,除非它们是内联的.
webpack.config.js
var fs = require('fs') var path = require('path') var webpack = require('webpack') module.exports = { devtool: 'source-map',entry: './client/client.jsx',output: { path: __dirname + '/__build__',filename: '[name].js',chunkFilename: '[id].chunk.js',publicPath: '/__build__/' },module: { loaders: [ { test: /\.jsx?$/,exclude: /(node_modules|bower_components)/,loader: 'babel-loader' } ] },plugins: [ new webpack.optimize.OccurenceOrderPlugin(),new webpack.optimize.DedupePlugin(),new webpack.optimize.UglifyJsPlugin({ compressor: { warnings: false },}),new webpack.DefinePlugin({ 'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV || 'development') }) ] }
server.js
import http from 'http'; import React from 'react'; import {renderToString} from 'react-dom/server'; import { match,RoutingContext } from 'react-router'; import {Provider} from 'react-redux'; import configureStore from './../common/store/store.js'; import fs from 'fs'; import { createPage,write,writeError,writeNotFound,redirect } from './server-utils.js'; import routes from './../common/routes/rootRoutes.js'; const PORT = process.env.PORT || 3000; var store = configureStore(); const initialState = store.getState(); function renderApp(props,res) { var markup = renderToString( <Provider store={store}> <RoutingContext {...props}/> </Provider> ); var html = createPage(markup,initialState); write(html,'text/html',res); } http.createServer((req,res) => { if (req.url === '/favicon.ico') { write('haha','text/plain',res); } // serve JavaScript assets else if (/__build__/.test(req.url)) { fs.readFile(`.${req.url}`,(err,data) => { write(data,'text/javascript',res); }) } // handle all other urls with React Router else { match({ routes,location: req.url },(error,redirectLocation,renderProps) => { if (error) writeError('ERROR!',res); else if (redirectLocation) redirect(redirectLocation,res); else if (renderProps) renderApp(renderProps,res); else writeNotFound(res); }); } }).listen(PORT) console.log(`listening on port ${PORT}`)
服务器utils的
与我上面发布的repo相同,例如react-react-router-server-rendering-lazy-routes只是导航到repo中的/modules/utils/server-utils.js.唯一的区别是createPage函数:
export function createPage(html,initialState) { return( ` <!doctype html> <html> <head> <Meta charset="utf-8"/> <Meta name="viewport" content="width=device-width,initial-scale=1"> <link rel="stylesheet" href="./../bower_components/Ionicons/css/ionicons.min.css"> <link rel="stylesheet" href="./../dist/main.css"> <title>Sell Your Soles</title> </head> <body> <div id="app">${html}</div> <script>window.__INITIAL_STATE__ = ${JSON.stringify(initialState)};</script> <script src="/__build__/main.js"></script> </body> </html> `); }
rootRoute.js
// polyfill webpack require.ensure if (typeof require.ensure !== 'function') require.ensure = (d,c) => c(require) import App from '../components/App.jsx' import Landing from '../components/Landing/Landing.jsx' export default { path: '/',component: App,getChildRoutes(location,cb) { require.ensure([],(require) => { cb(null,[ require('./UserProfile/UserProfileRoute.js'),require('./UserHome/UserHomeRoute.js'),require('./SneakerPage/SneakerPageRoute.js'),require('./Reviews/ReviewsRoute.js'),require('./Listings/ListingsRoute.js'),require('./Events/EventsRoute.js') ]) }) },indexRoute: { component: Landing } }
userProfileRoute.js
import UserProfile from '../../components/UserProfile/UserProfile.jsx'; export default { path: 'profile',component: UserProfile }
client.js
import React from 'react'; import { match,Router } from 'react-router'; import { render } from 'react-dom'; import { createHistory } from 'history'; import routes from './../common/routes/rootRoutes.js'; import {Provider} from 'react-redux'; import configureStore from './../common/store/store.js'; const { pathname,search,hash } = window.location; const location = `${pathname}${search}${hash}`; const initialState = window.__INITIAL_STATE__; const store = configureStore(initialState); // calling `match` is simply for side effects of // loading route/component code for the initial location match({ routes,location },() => { render( <Provider store={store}> <Router routes={routes} history={createHistory()} /> </Provider>,document.getElementById('app') ); });
我帮助你解决了不和谐,但我想我也会在这里发布答案.
原文链接:https://www.f2er.com/react/300889.html如果您使用babel6(而不是babel5)并在组件中使用export default,则需要将路由更新为以下内容:
getChildRoutes(location,(require) => { cb(null,[ require('./UserProfile/UserProfileRoute.js').default,require('./UserHome/UserHomeRoute.js').default,require('./SneakerPage/SneakerPageRoute.js').default,require('./Reviews/ReviewsRoute.js').default,require('./Listings/ListingsRoute.js').default,require('./Events/EventsRoute.js').default ]) }) }
有关更多详细信息,请参阅此SO讨论:Babel 6 changes how it exports default