我通过React找到了很多关于SSR的信息,并且所有这些信息都采用了完全不同的方法。所以我找到了一个看起来更有用的例子(React / graphQL / Apollo / Express / Webpack上的web-app),但我坚持一个问题。下面是一些例子:
actions
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
我尝试了这个example中的所有内容,但问题是在...
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')
);
});
我尝试从server.js
服务器导入router
并不能运行并给我与React组件相关的错误(样式导入等等我们可以在客户端上执行的所有功能,但不能在服务器上执行)。
所以问题是,我做错了什么?如果没有这个问题我怎么能导入路线? 我已经在这个小任务上花了那么多时间,真的很烦人。
我会感激任何帮助,谢谢!
答案 0 :(得分:1)
如您所知,服务器端呈现是在节点服务器中呈现您的react组件。但节点服务器不支持导入css / png文件。
如果您不想更改客户端代码,可以尝试用户webpack-isomorphic-tools,它会帮助您生成一个assert.json文件,该文件可以生成require(&#39; *。 css&#39;)调用返回json
个对象并生成CSS类名称映射,就像它们在webpack css-loader
中一样。
如果您有兴趣,可以查看demo。
这是你的webpack-isomorphic-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');
});