webpack-react入门

react是传说中最热门的框架, webpack呢又是比较火的一款模块加载器兼打包工具, 入门学习了一些东西, 在此记录一下

React

虚拟DOM机制

在平时的web开发中, 我们经常会跟DOM操作打交道, 然而复杂和频繁的DOM操作很容易造成性能问题

虚拟DOM是React引入的一个机制, 用React进行开发时, 所有DOM的构造都是通过虚拟DOM进行的

  • 每当有数据发生变化时, React会重新构建整个DOM树, 重建过程中, React会将当前整个DOM树与上次的DOM树作对比, 仅将需要变化的部分进行实际的浏览器更新

  • 批处理虚拟DOM的刷新, 在一个事件循环内的两次数据变化会被合并. 比如连续的将节点内容从A变成B, 又从B变成A, React认为UI没有发生变化

  • 虚拟DOM是内存数据, 性能极高, 对实际DOM的操作仅仅是有变化的部分(Diff), 开发人员不再需要关注某个数据的变化如何更新到一个或多个具体的DOM元素,而只需要关心在任意一个数据状态下,整个界面是如何Render的

组件化

React推荐以组件的方式去重新思考UI构成,将UI上每一个功能相对独立的模块定义成组件,然后将小的组件通过组合或者嵌套的方式构成大的组件,最终完成整体UI的构建

在React中,你按照界面模块自然划分的方式来组织和编写你的代码,对于评论界面而言,整个UI是一个通过小组件构成的大组件,每个组件只关心自己部分的逻辑,彼此独立。

React认为一个组件应该具有如下特征:

  • 可组合(Composeable):一个组件易于和其它组件一起使用,或者嵌套在另一个组件内部。如果一个组件内部创建了另一个组件,那么说父组件拥有(own)它创建的子组件,通过这个特性,一个复杂的UI可以拆分成多个简单的UI组件

  • 可重用(Reusable):每个组件都是具有独立功能的,它可以被使用在多个UI场景

  • 可维护(Maintainable):每个小的组件仅仅包含自身的逻辑,更容易被理解和维护

数据流

React实现了单向相应的数据流, 从而减少了重复代码

webpack

webpack是一款打包工具, 除了拥有丰富的插件外, 还有一套loader系统, 使得它能够支持多种规范的加载方式, 包括ES6/CommonJs/AMD等方式, 这是grunt和gulp所不具备的

安装webpack

npm install -g webpack

安装后就有了全局webpack命令, 直接执行webpack会默认使用当前目录的webpack.config.js做为配置文件, 若想指定别的配置文件, 可以执行webpack —config webpack.custom.config.js

一般会定义两个配置文件, 一个用于开发, 一个用于产品发布, 生产环境下面的打包文件不需要包含sourcemap等用于开发时的代码. 配置文件通常放置于项目根目录下, 本身是一个标准的CommonJS模块

配置webpack

需要一个配置文件webpack.config.js, 一个比较常规的配置文件如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
module.exports = {
entry:{
helloworld: 'app/main.js',
helloworld2: 'app/main2.js'
},
output: {
path: __dirname + '/assets/',
publicPath: "/assets/",
filename: 'bundle.js'
},
resolve: {
extensions: ['', '.js', '.jsx']
},
module: {
loaders: [{
test: /\.jsx?$/,
exclude: /node_modules/,
loader: 'babel'
}]
},
plugins: []
};
  • entry: 定义了打包后的入口文件,数组中的所有文件会按顺序打包, 每个文件进行依赖的递归查找,直到所有相关模块都被打包

  • output: 定义了输出文件的位置, path定义了打包文件存放的绝对路径, filename定义了打包结果文件的名称, publicPath为网站运行时的访问路径

  • resolve: 定义了解析模块路径时的配置, extensions指定了模块后缀, 引入模块时就可以不用写文件后缀了

  • module: 定义了对模块的处理, test定义了处理文件的正则, 一旦匹配, 就会用相应的loader对文件做处理, exclude表示除了node_modules路径下的文件

  • plugins: 定义了使用的插件

添加react

package.json:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
{
"name": "react-webpack",
"version": "1.0.0",
"description": "react-webpack-test",
"private": true,
"engines": {
"node": ">=0.10.0"
}
,

"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"build": "webpack",
"dev": "webpack-dev-server --devtool eval --progress --colors --hot --content-base dist"
}
,

"devDependencies": {
"autoprefixer-loader": "^3.2.0",
"babel-core": "^6.11.4",
"babel-loader": "^6.2.4",
"babel-preset-es2015": "^6.9.0",
"babel-preset-react": "^6.11.1",
"babel-preset-stage-0": "^6.5.0",
"css-loader": "^0.23.1",
"less": "^2.7.1",
"less-loader": "^2.2.3",
"style-loader": "^0.13.1",
"url-loader": "^0.5.7",
"webpack": "^1.13.1",
"webpack-dev-server": "^1.14.1"
}
,

"dependencies": {
"react": "^15.2.1",
"react-dom": "^15.2.1"
}

}

解释:

1
2
3
4
5
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"build": "webpack",
"dev": "webpack-dev-server --devtool eval --progress --colors --hot --content-base dist"
}

build配置打包命令, 命令行中可输入npm run build, 执行打包任务

dev配置本地调试server

  • webpack-dev-server 在 localhost:8080 建立一个Web服务器

  • devtool eval 为你的代码创建源地址。当有任何报错的时候可以让你更加精确地定位到文件和行号

  • progress 显示合并代码进度

  • colors 命令行中显示颜色

  • content-base dist 指向设置的输出目录dist

devDependencies中安装了一些常用loader, babel-preset-es2015支持ES2015, babel-preset-react支持jsx, babel-preset-stage-0支持ES7…

webpack.config.js:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
var path = require('path');

module.exports = {
entry: {
helloworld: [
'webpack/hot/dev-server',
'webpack-dev-server/client?http://localhost:8080',
path.resolve(__dirname, 'app/main.js')
],
},
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'bundle.js',
},
module: {
loaders: [{
test: /\.jsx?$/,
exclude: /node_modules/,
loader: 'babel',
query: {
presets:['es2015','stage-0','react']
}
}, {
test: /\.less$/,
loader: 'style-loader!css-loader!autoprefixer-loader!less-loader'
},{
test: /\.(png|jpg)$/,
loader: 'url-loader?limit=8192'
}]
}
};

webpack-dev-server实现修改源码后, 浏览器自动刷新

module中配置了一些loader, 分别对js/jsx, less, 以及图片png/jpg做了相关处理

helloworld demo

我的文件组织如下:

1
2
3
4
5
6
7
8
9
-app
component.jsx
helloComponent.less
main.js
-dist
index.html
bundle.js(打包后生成)
package.json
webpack.config.js

component.jsx

1
2
3
4
5
6
7
8
9
import React from 'react';

require('./helloComponent.less');

export default class Hello extends React.Component {
render() {
return <h1>Hello world</h1>;
}
}

main.js

1
2
3
4
5
6
7
8
9
import React from 'react';
import ReactDOM from 'react-dom';
import Hello from './component.jsx';

main();

function main() {
ReactDOM.render(<Hello />, document.getElementById('app'));
}

index.html

1
2
3
4
5
6
7
8
9
10
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8"/>
</head>
<body>
<div id="app"></div>
<script src="bundle.js"></script>
</body>
</html>

helloComponent.less

1
2
3
4
5
6
@color: #f7e0e8;


body {
background: @color;
}

运行npm run dev, 浏览器地址栏输入localhost:8080即可看到index.html的内容