webpack-3 react-router-4 react-15.6 升级记录
说明
1. react-router 升级到 4.1.2,API 变化很大,具体API解析,请看这篇文章react-router 4 升级攻略
2. 从 webpack 2.x 升级到 webpack 3.x ,基本上配置文件没有需要修改的地方,但是 webpack 3.x 做了一些升级,提供了更多的功能
3. react 从 15.4.x 升级到 15.6.x 基本上没有大的变化,但是其内部取消了一些功能,如果引用第三方组件库,可能会有警告
升级变化
1. webpack 作用域提升(scope hoisting)
老版本的 Webpack 需要将每个模块包裹在单独的函数闭包中以实现模块系统。而这些封装函数往往会使得浏览器中运行的 JavaScript 代码性能有所下降;而 Webpack 3 中提供了插件来允许开发者启用作用域提升特性来避免这种额外的性能损耗
// 在插件项加入以下插件
module.exports = {
plugins: [
new webpack.optimize.ModuleConcatenationPlugin()
]
};
作用域提升特性能够移除模块的封装函数,使用此功能后输出包的体积下降(有限)加载速度会加快
注意:开发环境使用此功能,会降低 HMR 的更新速度,所以在生产环境使用就好了
2. webpack-dev-server 自动打开的页面链接出现 undefined http://0.0.0.0:2222/undefined
查了一下,是 dev-server 更新的版本的问题,只要在 dev-server 配置上加上
openPage: ''
重新运行就行了
devServer: {
contentBase: defPath.DEV_PATH,
publicPath: '/',
historyApiFallback: true,
clientLogLevel: 'none',
host: ip,
port: 8090,
open: true,
openPage: '', // undefined 解决
hot: true,
inline: true,
compress: true,
stats: {
colors: true,
errors: true,
warnings: true,
modules: false,
chunks: false
}
}
3. HMR
版本升级后,之前的热模块更新写法会有问题,查找了资料,尝试出以下方案
1. babel 配置 webpack 配置 查看这一篇文章,没有变化
2. 项目入口代码
/*
app/js/index.js
入口文件, 配置 webpack 热加载模块
*/
import '../scss/index.scss';
import React from 'react';
import ReactDOM from 'react-dom';
import {AppContainer} from 'react-hot-loader';
import {Provider} from 'react-redux';
import {ConnectedRouter} from 'react-router-redux';
import injectTapEventPlugin from 'react-tap-event-plugin';
import createHistory from 'history/createBrowserHistory';
// 引入原始的配置模块
import store from './store/index';
import Root from './routes';
const history = createHistory();
const mountNode = document.getElementById('app');
// react 的插件,提供onTouchTap()
injectTapEventPlugin();
// 封装 render
const render = (Component) => {
ReactDOM.render((
<AppContainer>
<Provider store={store}>
<ConnectedRouter history={history} basename="">
<Component/>
</ConnectedRouter>
</Provider>
</AppContainer>
), mountNode);
};
render(Root);
console.log(process.env.NODE_ENV);
if (module.hot && process.env.NODE_ENV !== 'production') {
module.hot.accept('./routes.js', (err) => {
console.log('module hot');
if (err) {
console.log(err);
}
const NextComponent = require('./routes.js').default; // eslint-disable-line
render(NextComponent);
});
}
3. 路由部分代码
/*
Root, Router 配置
*/
import React from 'react';
import {Route, Switch, Redirect} from 'react-router-dom';
import {App, Home, Test} from './containers/index';
const Root = () => (
<div>
<Switch>
<Route path="/" render={(props) => (
<App>
<Switch>
<Route path="/" exact component={Home}/>
<Route path="/home" component={Home}/>
<Route path="/test" component={Test}/>
<Redirect from="/undefined" to={{pathname: '/', search: '?mold=redirect'}}/>
</Switch>
</App>
)}/>
<Route render={() => (<Redirect to="/"/>)}/>
</Switch>
</div>
);
export default Root;