前言
下面是我们使用到技术栈:
webpack + react + redux + react-router + react-thunk + ES6 + ....
注意事项:
建议使用npm5.X 或者 yarn 包管理工具(最好不要使用cnpm,虽然安装包速度上很快,但是在文件关联上会有坑,之前用的时候被坑过)
一、新建项目目录

config : webpack 配置文件
dist: 打包后代码
src: 源码目录
二、基础配置
安装基础的包
// 生成默认package.josn 文件 npm init // 安装 webpack 和 webpack-dev-server npm install webpack webpack-dev-server --save-dev // 安装 react react-dom npm install react react-dom --save // 安装 babel-core 、babel-loader、babel-preset-env、babel-preset-react npm install babel-core babel-loader babel-preset-env babel-preset-react --save-dev // html-webpack-plugin 生成html文件 npm install html-webpack-plugin --sav-dev
添加 webpack 配置
先添加部分基础文件:
config/webpack/file.path.js
1 const { resolve } = require('path')
2
3 // 项目根目录
4 const projectPath = process.cwd()
5 // 代码地址目录
6 const srcPath = resolve(projectPath, 'src')
7 // 入口文件目录
8 const mainPath = resolve(srcPath, 'main')
9
10 // 入口文件
11 const indexJsPath = resolve(mainPath, 'index.jsx')
12 const indexHtmlPath = resolve(mainPath, 'index.html')
13
14 module.exports = {
15 srcPath,
16 mainPath,
17 indexJsPath,
18 indexHtmlPath
19 }
config/webpack.config.js
const HtmlWebpackPlugin = require('html-webpack-plugin')
const { srcPath, indexJsPath, indexHtmlPath } = require('./file.path.js')
// 生成HTML文件
const generateIndex = new HtmlWebpackPlugin({
inject: 'body',
filename: 'index.html',
template: indexHtmlPath
})
module.exports = {
// 基础目录(绝对路径),用于从配置中解析入口点和加载程序
// 默认使用当前目录,但建议在配置中传递一个值。这使得您的配置独立于CWD(当前工作目录)
context: srcPath,
// 入口文件
entry: indexJsPath,
// 输入配置
output: {
},
// 模块配置
module: {
rules: [
{
test: /\.jsx?$/,
use: 'babel-loader'
}
]
},
// 插件配置
plugins: [
generateIndex
]
}
添加 babel 配置 .babelrc:
.babelrc
1 {
2 "presets": [
3 "env", // babel 启动插件
4 "react" // 编译react语法插件
5 ]
6 }
添加入口文件 src/main/index.jsx:
1 import React from 'react'
2 import ReactDOM from 'react-dom'
3
4 const render = () => {
5 ReactDOM.render(
6 <h1>Hello React</h1>,
7 document.getElementById('app-container')
8 )
9 }
10
11 render()
添加 index.html
1 <!DOCTYPE html> 2 <html lang="en"> 3 <head> 4 <meta charset="UTF-8"> 5 <meta name="viewport" content="width=device-width, initial-scale=1.0"> 6 <meta http-equiv="X-UA-Compatible" content="ie=edge"> 7 <title>webpack react配置</title> 8 </head> 9 <body> 10 11 </body> 12 </html>
在package.json 中添加启动命令:
{
...
"scripts": {
"start": "webpack-dev-server --config config/webpack.config.js"
},
...
}
现在可以直接在cmd中运行:
npm run start
可以在浏览器打开 http://localhost:8080/ ,你可以看到一下效果:

完整代码地址:https://github.com/haozhaohang/library/tree/master/webpack%20react%E9%85%8D%E7%BD%AE/lessons%201
三、高级配置
1. 添加 react-router
// 安装 react-router-dom npm install react-router-dom --save
添加 src/main/app.js
1 import React, { Component } from 'react'
2 import { BrowserRouter, Route, Link } from 'react-router-dom'
3
4 import Home from '../containers/Home'
5 import About from '../containers/About'
6 import Topics from '../containers/Topics'
7
8 // BrowserRouter 下只能有一个子元素
9 class App extends Component {
10 render() {
11 return (
12 <BrowserRouter>
13 <div>
14 <ul>
15 <li><Link to="/">Home</Link></li>
16 <li><Link to="/about">About</Link></li>
17 <li><Link to="/topics">Topics</Link></li>
18 </ul>
19
20 <hr/>
21
22 <Route exact path="/" component={Home}/>
23 <Route path="/about" component={About}/>
24 <Route path="/topics" component={Topics}/>
25 </div>
26 </BrowserRouter>
27 )
28 }
29 }
30
31 export default App
添加 containers/Home/index.js
1 import React, { Component } from 'react'
2
3 const Home = () => {
4 return (
5 <div>
6 Home
7 </div>
8 );
9 }
10 export default Home
添加 containers/About/index.js
1 import React from 'react' 2 3 const About = () => ( 4 <div> 5 about 6 </div> 7 ) 8 9 export default About
添加 containers/Topics/index.js
import React from 'react'
const Topics = () => {
return (
<div>
topics
</div>
);
}
export default Topics
修改 src/main/index.jsx 文件
1 import React from 'react'
2 import ReactDOM from 'react-dom'
3
4 import App from './app.js'
5
6 const render = Component => {
7 ReactDOM.render(
8 <Component />,
9 document.getElementById('app-container')
10 )
11 }
12
13 render(App)
路由我们添加完了,可以运行项目, 在浏览器 http://localhost:8080/ 预览效果。
react-router路由有 BrowserRouter和HashRouter 两种路由,两者的区别:
BrowserRouter 使用HTML5 历史API, HashRouter 使用哈希值
例如:如果同一个修改用户信息路由,在BroserRouter下显示 user/edit,而在HashRouter 下显示为 #/user/edit
刷新页面BrowserRouter会向服务端发送请求,后台要做一定处理,而HashRouter 不会向服务端发送请求
在react-router 4.0 的文档中有这样一段话:
注意: 使用 hash 的方式记录导航历史不支持 location.key 和 location.state。 在以前的版本中,我们为这种行为提供了 shim,但是仍有一些问题我们无法解决。 任何依赖此行为的代码或插件都将无法正常使用。 由于该技术仅用于支持传统的浏览器,因此在用于浏览器时可以使用 <BrowserHistory> 代替。
完整代码地址:https://github.com/haozhaohang/library/tree/master/webpack%20react%E9%85%8D%E7%BD%AE/lessons2
2.配置redux 、react-thunk
// 安装redux react-redux npm install redux react-redux react-thunk --save
添加 src/main/store.js
1 import { combineReducers, createStore, applyMiddleware } from 'redux'
2 import thunk from 'redux-thunk'
3
4 import rootReducers from '../reducers'
5
6 const middleware = [thunk]
7
8 const store = createStore(
9 combineReducers(rootReducers),
10 {},
11 applyMiddleware(...middleware)
12 )
13
14 export default store
添加 src/reduxcers/index.js
1 function userInfo(state = {}) {
2 return {
3 name: 'react'
4 }
5 }
6
7 export default {
8 userInfo
9 }
修改 src/main/app.js
1 import { Provider } from 'react-redux'
2 import store from './store'
3
4 ...
5
6 render() {
7 return (
8 <Provider store={store}>
9 ...
10 </Provider>
11 )
12 }
13
14 ...
修改 src/tontainers/Home/index.js
1 import React, { Component } from 'react'
2 import { connect } from 'react-redux'
3
4 const Home = ({ userInfo }) => {
5 return (
6 <div>
7 Home
8 <div>
9 这是redux中的数据
10 {userInfo.name}
11 </div>
12 </div>
13 );
14 }
15
16 const mapStateToProps = ({ userInfo }) => {
17 return {
18 userInfo
19 }
20 }
21
22 const mapDispatchTopProps = {}
23 // 使用connect 关联redux
24 export default connect(mapStateToProps, mapDispatchTopProps)(Home)
redux我们添加完了,可以运行项目, 在浏览器 http://localhost:8080/ 预览效果。
完整代码地址:https://github.com/haozhaohang/library/tree/master/webpack%20react%E9%85%8D%E7%BD%AE/lessons3
3.配置 react 热加载
修改 config/webpack.config.js
1 const webpack = require('webpack')
2
3 ...
4
5 // 插件配置
6 plugins: [
7 ...
8 // 开启全局的模块热替换(HMR)
9 new webpack.HotModuleReplacementPlugin(),
10 // 热加载中可以输入更加友好的模块名
11 new webpack.NamedModulesPlugin()
12 ]
13
14 ...
15
16 devServer: {
17 hot: true
18 }
19 ...
这样配置已经可以实现热加载了,但是并不算结束,还需要配置 react-hot-loader 的热加载插件,这是因为 webpack-dev-server只能即时的刷新页面,但是组件中的状态保存不住,因为React有一些自己的语法(jsx)是HotModuleReplacementPlugin处理不了。而react-hot-loader 在 --hot 基础上做了额外的处理,来保证状态可以存下来。
// 安装 react-hot-loader npm install react-hot-loader --save
修改 .babelrc
{
"presets": [
["env", {
"modules": false
}],
"react"
],
"plugins": ["react-hot-loader/babel"]
}
添加 react-hot-loader/patch 和 publicPath 到 webpack.config.js,
1 ...
2
3 module.exports = {
4 ...
5 // 入口文件
6 entry: [
7 'react-hot-loader/patch',
8 indexJsPath
9 ],
10
11 // 输入配置
12 output: {
13 publicPath: '/'
14 },
15
16 ...
17 }
18
19 ...
修改 src/main/index.jsx
import React from 'react'
import ReactDOM from 'react-dom'
import { AppContainer } from 'react-hot-loader'
import App from './app.js'
const render = Component => {
ReactDOM.render(
<AppContainer>
<Component />
</AppContainer>,
document.getElementById('root'),
)
}
render(App)
// Webpack Hot Module Replacement API
if (module.hot) {
module.hot.accept('./containers/App', () => { render(App) })
}
react-hot-loader 就配置完成了,现在更改三个页面中的文件,就可以在页面中实时看到。
配置时注意事项:
- 必须将webpack配置中output下publicPath设置为"/",否则无法实现热加载
- 将.babelre 中设置babel env预设更改为不使用Babel转换成ES2015模块 [ "env": { "modules": false } ]
- react-hot-loader在webpack-dev-server的热加载基础上做了额外的处理,所以必须要打开webpack-dev-server的 hot模式 才可以实现热加载
react-hot-loader我们添加完了,可以运行项目, 在浏览器 http://localhost:8080/ 预览效果。
完整代码地址:https://github.com/haozhaohang/library/tree/master/webpack%20react%E9%85%8D%E7%BD%AE/lessons4
4. 配置各种资源的loader
css资源加载器
// 安装 style-loader css-loader postcss-loader npm install style-loader css-loader postcss-loader --save-dev
下面是webpack.config.js 中的配置
1 ...
2 // 模块配置
3 module: {
4 rules: [
5 ...
6 {
7 test: /\.css$/,
8 use: [
9 {
10 loader: 'style-loader'
11 },
12 {
13 loader: 'css-loader',
14 options: {
15 importLoaders: 1
16 }
17 },
18 {
19 loader: 'postcss-loader'
20 }
21 ]
22 }
23 ...
24 ]
25 },
26 ...
使用postcss需要添加postcss.config.js
module.exports = {
plugins: [
// 添加你需要的插件,这个后面会提到
]
}
之前一直使用sass,但是这里并没有选择sass、less等css预处理框架,个人认为postcss是一个平台,提供了丰富的插件,可以更好处理css。
图片资源的加载
// 安装 url-loader file-loader npm install url-loader file-loader --save-dev
下面是webpack.config.js 中的配置
1 ...
2 // 模块配置
3 module: {
4 rules: [
5 ...
6 {
7 test: /\.(png|jpg|gif)$/,
8 use: [
9 {
10 loader: 'url-loader',
11 options: {
12 limit: 8192
13 }
14 }
15 ]
16 },
17 ...
18 ]
19 },
20 ...
url-loader: 可以将图片小于8192(根据limit设置而定)的图片装成base64和源码添加在一起,减少请求,提高加载速度。
file-loader: 对url-loader无法处理的图片资源(大于limit设置的值),使用此loader进行处理,当然这个loader还可以加载字体图标等文件,这里就不在详细添加了。
完整代码地址:https://github.com/haozhaohang/library/tree/master/webpack%20react%E9%85%8D%E7%BD%AE/lessons5
基本的配置都讲完了,后续系列中会讲到优化webpack配置、开发生成配置的拆分、构建优化和服务代理,mock数据等功能
如果本文对你有帮助,请给个 star,感谢^_^
来源:https://www.cnblogs.com/hzh-fe/p/8024195.html