我有一个有多条路线的SPA。我正在尝试使用Webpack 2和React Router 4实现基于路由的Code Splitting。我能够根据路由创建不同的块。例如,对于主页,我有vendor.js
,main.js
和home.js
。所有三个文件都已成功加载,但我没有看到任何输出。正在呈现null
。以下是React开发人员工具和使用的代码的屏幕截图。我可以知道我在这里失踪了什么吗?
App Component / App.js
import React, { Component } from 'react';
import { BrowserRouter, Route, Switch } from 'react-router-dom';
import NotificationContainer from '../containers/NotificationContainer';
class App extends Component {
constructor(props) {
super(props);
}
render() {
return (
<div>
<NotificationContainer />
<BrowserRouter>
<Switch>
<Route
exact
path="/"
getComponent={(nextState, callback) => {
// import('./homepage/index').then(module => callback(null, module.default));
require.ensure(
[],
require => {
callback(null, require('./homepage/index').default);
},
'home'
);
}}
/>
<Route
path="/login"
getComponent={(nextState, callback) => {
require.ensure(
['../containers/LoginContainer'],
require => {
require('../containers/LoginContainer');
},
'login'
);
}}
/>
<Route
path="/forgetPassword"
getComponent={(nextState, callback) => {
require.ensure(
['../containers/ForgetPasswordContainer'],
require => {
require('../containers/ForgetPasswordContainer');
},
'forgetPassword'
);
}}
/>
<Route
path="/generateNewPassword"
getComponent={(nextState, callback) => {
require.ensure(
['../containers/GenerateNewPasswordContainer'],
require => {
require('../containers/GenerateNewPasswordContainer');
},
'generateNewPassword'
);
}}
/>
<Route
path="/signup"
getComponent={(nextState, callback) => {
require.ensure(
['../containers/SignupContainer'],
require => {
require('../containers/SignupContainer');
},
'signup'
);
}}
/>
<Route
path="/contact"
getComponent={(nextState, callback) => {
require.ensure(
['./Contact'],
require => {
require('./Contact');
},
'contact'
);
}}
/>
<Route
path="/tech"
getComponent={(nextState, callback) => {
require.ensure(
['./Tech'],
require => {
require('./Tech');
},
'tech'
);
}}
/>
<Route
path="/error"
getComponent={(nextState, callback) => {
require.ensure(
['./Error'],
require => {
require('./Error');
},
'error'
);
}}
/>
<Route
path="/user/dashboard"
getComponent={(nextState, callback) => {
require.ensure(
['../containers/DashBoardContainer'],
require => {
require('../containers/DashBoardContainer');
},
'dashboard'
);
}}
/>
<Route
path="/movie/:movieId"
getComponent={(nextState, callback) => {
require.ensure(
['../containers/MovieContainer'],
require => {
require('../containers/MovieContainer');
},
'movieContainer'
);
}}
/>
<Route
getComponent={(nextState, callback) => {
require.ensure(
['./Error'],
require => {
require('./Error');
},
'error'
);
}}
/>
</Switch>
</BrowserRouter>
</div>
);
}
}
export default App;
Webpack配置
const webpack = require('webpack');
var BundleTracker = require('webpack-bundle-tracker');
var BundleAnalyzer = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
module.exports = {
entry: './src/index.js',
output: {
path: __dirname + '/public/assets/js',
filename: '[name].js',
chunkFilename: '[name].js',
publicPath: 'assets/js/'
},
plugins: [
new BundleTracker({ filename: './webpack-stats.json' }),
new webpack.DefinePlugin({
'process.env': {
NODE_ENV: JSON.stringify('production')
}
}),
new webpack.optimize.CommonsChunkPlugin({
name: 'vendor',
filename: '[name].js',
minChunks: module => /node_modules/.test(module.resource)
}),
new webpack.LoaderOptionsPlugin({
minimize: true,
debug: false
}),
new webpack.optimize.UglifyJsPlugin({
beautify: false,
mangle: {
screw_ie8: true,
keep_fnames: true
},
compress: {
screw_ie8: true,
warnings: false
},
comments: false
}),
new BundleAnalyzer({ analyzerMode: 'static' })
],
resolve: {
modules: ['node_modules'],
extensions: ['*', '.js', '.jsx']
},
module: {
loaders: [
{
test: /\.js$/,
loader: 'babel-loader',
options: {
plugins: [
[
'transform-semantic-ui-react-imports',
{
convertMemberImports: true,
addCssImports: false,
importMinifiedCssFiles: false,
addLessImports: false,
addDuplicateStyleImports: false
}
]
],
presets: [['es2015', { modules: false }], 'react', 'stage-2', 'node6']
}
}
]
},
node: {
console: true,
fs: 'empty',
net: 'empty',
tls: 'empty'
}
};
主页组件|主页/ index.js
import React, { Component, PropTypes } from 'react';
import LayoutContainer from '../../containers/LayoutContainer';
import Hero from './Hero';
import About from './About';
import Working from './Working';
class Homepage extends Component {
render() {
return (
<LayoutContainer scrollBound={600}>
<div className="homepage-container">
<p>Here</p>
<Hero />
<About />
<Working />
</div>
</LayoutContainer>
);
}
}
export default Homepage;
答案 0 :(得分:1)
在所有情况下,您都没有调用<Route
path="/login"
getComponent={(nextState, callback) => {
require.ensure(['../containers/LoginContainer'], require => {
require('../containers/LoginContainer');
}, 'login');
}}
/>
,因此组件不会返回到路径。例如,这个:
<Route
path="/login"
getComponent={(nextState, callback) => {
require.ensure(['../containers/LoginContainer'], require => {
callback(null, require('../containers/LoginContainer'));
}, 'login');
}}
/>
......应该是:
{{1}}
答案 1 :(得分:0)
除非react-router
的文档是一个大骗子,否则路由不再是getComponent
方法。但是,滚动你自己的延迟加载组件并不是太糟糕。我必须为一个更奇特的路由器做一个,这种方法也适用于react-router@4
。首先,创建一个简单的HOC:
export default function DeferredComponent(loadingFn) {
return class DeferredComponentInstance extends React.Component {
constructor() {
super(...arguments);
this.state = {
InnerComponent: Spinner
};
}
componentDidMount() {
loadingFn((err, component) => {
if (err) {
throw err; // Maybe render an error component instead?
}
this.setState({ InnerComponent: component });
});
}
render() {
const { InnerComponent } = this.state;
return <InnerComponent { ...this.props }/>;
}
};
}
...现在你可以像这样使用它:
<Route
path="/login"
component={DeferredComponent(cb => {
require.ensure(['../containers/LoginContainer'], require => {
cb(null, require('../containers/LoginContainer').default);
});
})}
/>