因为技术选型react,所以最近开始学react,首先肯定是搭建个简单环境,网上找了半天才找到正常的教程,也是本文参考的教程可能是因为webpack版本等一些其他原因吧,我使用的是webpack3+,当然大家也可以选择react官方的脚手架—create-react-app。
本文主要将完成以下目标
1. 使用webpack进行模块管理,并进行简单配置
2. 实现热更新,也就是监听代码变动并刷新浏览器
3. 实现HMR,也就是代码动态替换
一:引入webpack并简单配置
首先在根目录下创建package.json和webpack.config.js必备文件,默认已经安装npm:
$ npm init
$ webpack init
$ npm install --save react react-dom
$ npm install --save-dev webpack babel-cli babel-loader babel-preset-es2015 babel-preset-react
安装好依赖,现在package.json应该是这样的
"devDependencies": {
"babel-cli": "^6.24.1",
"babel-loader": "^7.1.1",
"babel-preset-es2015": "^6.24.1",
"babel-preset-react": "^6.24.1",
"webpack": "^3.3.0"
},
"dependencies": {
"react": "^15.6.1",
"react-dom": "^15.6.1"
}
webpack.config.js
const path = require('path')
const root = __dirname
module.exports = {
// 入口文件
entry: path.resolve(root, 'src/main.js'),
// 出口文件
output: {
filename: 'bundle.js',
path: path.resolve(root, 'dist')
},
// loaders
module: {
rules: [
{test: /\.jsx?$/, use: ['babel-loader'], exclude: /node_modules/}
]
}
}
babel基本上是必备插件了,也是最流行的转码器,当然babel也有不同的版本、不同的各种说法,包括babel-cli,babel-ployfill等,在这边我们不就详解了,可以自己参照官网。
简单介绍一下,这个定义的loader,test即为匹配的文件名正则,use表示使用的loader,exclude表示不需要匹配的文件,也就是不去匹配依赖里面的jsx。
同时,因为使用了babel,所以我们需要一个耳熟能详的文件—-.babelrc,根目录创建好,并填写
{
"presets": [
["es2015", {"modules": false}], // 因为webpack 2 本身已支持es6 module
"react"
]
}
然后需要index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>React Demo</title>
</head>
<body>
<div id="app"></div>
<script src="dist/bundle.js"></script>
</body>
</html>
main.js
import React from 'react'
import ReactDOM from 'react-dom'
ReactDOM.render(
<h1>Hello, world!</h1>,
document.getElementById('app')
)
配置一下,npm scripts
"scripts": {
"dev": "webpack --config webpack.config.js"
}
然后运行,打开浏览器就可以看到效果了
$ npm run dev
二:热更新进行实时编译
最基本的自动化应该就是热更新了吧,这里我们使用webpack-dev-server创建本地服务器监听你的代码,然后实时生成bundle.js
先配置html-webpack-plugin插件动态生成HTML文件,将我们根目录下的index.html改名为template.html,这是动态index.html的模板,他将在dist文件夹中生成,减少我们以后对html操作的时间,这不是我们关心的重点。
先安装:
$ npm install webpack-dev-server html-webpack-plugin --save-dev
改template.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>React Demo</title>
</head>
<body>
<div id="app"></div>
<!-- js文件会自动插入到这里,无需自己填写 -->
</body>
</html>
修正webpack.config.js的html-webpack-plugin的配置:
const HtmlWebpackPlugin = require('html-webpack-plugin')
module.exports = {
// ...
// 其他配置保持不变
// ...
plugins: [
new HtmlWebpackPlugin({
title: 'React Demo',
template: path.resolve(root, 'template.html')
})
]
}
引入webpack-dev.server
entry: [
'webpack-dev-server/client',
path.resolve(root, 'src/main.js')
],
output: {
filename: 'bundle.js',
path: path.resolve(root, 'dist'),
publicPath: '/'
},
// ...
// 其他配置保持不变
// ...
devServer: {
contentBase: path.resolve(root, 'dist'),
publicPath: '/',
port: 8080,
historyApiFallback: true
}
package.json中的scripts修改如下:
"scripts": {
"dev": "webpack-dev-server --config webpack.dev.js"
}
现在使用npm run dev就可以启动一个8080本地服务器监听你的代码变动并刷新浏览器,html和js都是动态编译的了
三:热替换
在动态监听代码的同时,增加编译效率,每次编译都进行代码的diff,只替换有所变动的地方,当你项目小或许烦恼还比较少,当项目大了之后,我有个同事,每次build都需要几分钟,那几分钟我们只能无聊的刷朋友圈。。 另外这个还可以保留你调试的进度,直接增量构建不会让你刷新从头再来。
先安装依赖
$ npm install --save-dev react-hot-loader@next
添加webpack.config.js
const webpack = require('webpack')
module.exports = {
entry: [
'react-hot-loader/patch', // 激活HMR
'webpack-dev-server/client',
'webpack/hot/only-dev-server',
path.resolve(root, 'src/main.js')
],
// ...
// 其他配置保持不变
// ...
devServer: {
hot: true, // 激活服务器的HMR
contentBase: path.resolve(root, 'dist'),
publicPath: '/',
port: 8080,
historyApiFallback: true
},
plugins: [
new HtmlWebpackPlugin({
title: 'React Demo',
template: path.resolve(root, 'template.html')
}),
new webpack.HotModuleReplacementPlugin(), // 热替换插件
new webpack.NamedModulesPlugin() // 执行热替换时打印模块名字
]
}
修改一下.babelrc配置
{
"presets": [
["es2015", {"modules": false}],
"react"
],
"plugins": [
"react-hot-loader/babel" // 添加HMR支持
]
}
同时在你的main.js中使用react-hot-loader,将你的所有内容写在App.js中并导入
import React from 'react'
import ReactDOM from 'react-dom'
import { AppContainer } from 'react-hot-loader'
import App from './App'
const render = (App) => {
ReactDOM.render(
<AppContainer>
<App />
</AppContainer>,
document.getElementById('app')
)
}
render(App)
if (module.hot) {
module.hot.accept('./App', () => render(App))
}
此时再运行npm run dev,你修改代码后就可以体会到增量构建的魅力了。