Skip to content
This repository has been archived by the owner on Nov 4, 2018. It is now read-only.

Add redux boilerplate #25

Closed
wants to merge 27 commits into from
Closed
Show file tree
Hide file tree
Changes from 7 commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
.idea
.DS_Store
tmp
spm_modules
node_modules
examples/**/dist
boilerplate/dist
1 change: 0 additions & 1 deletion .npmignore
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
.idea
.DS_Store
tmp
spm_modules
node_modules
examples
45 changes: 36 additions & 9 deletions bin/antd-init
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ var vfs = require('vinyl-fs');
var fs = require('fs');
var through = require('through2');
var path = require('path');
var inquirer = require('inquirer');
var join = path.join;
var basename = path.basename;

Expand All @@ -13,17 +14,43 @@ if (process.argv.length === 3 &&
return;
}

var cwd = join(__dirname, '../boilerplate');
var dest = process.cwd();
if (process.argv.length === 4 && process.argv[2] === '--type') {
init(process.argv[3]);
return;
}

vfs.src('**/*', {cwd: cwd, cwdbase: true, dot: true})
.pipe(template(dest))
.pipe(vfs.dest(dest))
.on('end', function() {
fs.renameSync(path.join(dest,'gitignore'),path.join(dest,'.gitignore'));
require('../lib/install');
inquirer.prompt({
name: 'type',
type: 'list',
message: 'Please select boilerplate type',
choices: [
{
name: 'plain react - for simple project',
value: 'plain-react',
},
{
name: 'redux - for complex project',
value: 'redux',
},
],
})
.resume();
.then(function(answers) {
init(answers.type);
});

function init(type) {
var cwd = join(__dirname, '../boilerplates', type);
var dest = process.cwd();

vfs.src('**/*', {cwd: cwd, cwdbase: true, dot: true})
.pipe(template(dest))
.pipe(vfs.dest(dest))
.on('end', function() {
fs.renameSync(path.join(dest,'gitignore'),path.join(dest,'.gitignore'));
require('../lib/install');
})
.resume();
}

function template(dest) {
return through.obj(function (file, enc, cb) {
Expand Down
20 changes: 20 additions & 0 deletions boilerplates/redux/.eslintrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
{
"parser": "babel-eslint",
"extends": "eslint-config-airbnb",
"rules": {
"spaced-comment": [0],
"no-unused-vars": [0],
"no-empty": [0],
"react/wrap-multilines": [0],
"react/no-multi-comp": [0],
"no-constant-condition": [0],
"react/jsx-no-bind": [0],
"react/prop-types": [0],
"arrow-body-style": [0],
"react/prefer-stateless-function": [0],
"semi": [0]
},
"ecmaFeatures": {
"experimentalObjectRestSpread": true
}
}
109 changes: 109 additions & 0 deletions boilerplates/redux/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
# react-redux-boilerplate

A boilerplate with react, redux, redux-saga, react-router, webpack, babel, css-modules ...

## 环境准备

先安装依赖

```bash
$ npm install
```

想要更好的开发体验,还需安装两个 Chrome 插件:[Redux DevTools](https://chrome.google.com/webstore/detail/lmhkpmbekcpmknklioeibfkpmmfibljd) 和 [LiveReload](https://chrome.google.com/webstore/detail/livereload/jnihajbhpnppcggbcgedagnkighmdlei) 。

## 启动调试

```bash
$ npm start
$ open http://localhost:8989/
```

## 构建代码

```bash
$ npm run build

// 构建但不压缩
$ npm run build -- --no-compress
```

## 目录结构

```
.
├── /dist/ # 构建输出的文件会在这里
├── /node_modules/ # 第三方类库和工具
├── /src/ # 应用源码
│ ├── /components/ # React components
│ ├── /constants/ # 常量 (比如 action types 等)
│ ├── /containers/ # React containers
│ ├── /entries/ # 应用入口
│ ├── /reducers/ # reducers
│ ├── /routes/ # 路由信息
│ ├── /sagas/ # redux-sagas
│ └── /services/ # 处理和服务器的交互
├── proxy.config.js # 配置 dora-plugin-proxy,用于 mock 和在线调试
├── webpack.config.js # 扩展 webpack 配置
└── package.json # 配置入口文件、依赖和 scripts
```

## 系统组织

![](https://camo.githubusercontent.com/068c4ff126977b861cff3338428bdde6927f7dad/68747470733a2f2f6f732e616c697061796f626a656374732e636f6d2f726d73706f7274616c2f43684d775a42755a6c614c725377652e706e67)

详见:[React + Redux 最佳实践](https://github.com/sorrycc/blog/issues/1)

## 内置类库

- [react](https://github.com/facebook/react)
- [redux](https://github.com/reactjs/redux)
- [redux-saga](https://github.com/yelouafi/redux-saga)
- [redux-actions](https://github.com/acdlite/redux-actions)
- [react-router](https://github.com/reactjs/react-router)
- [reselect](https://github.com/reactjs/reselect)
- [classnames](https://github.com/JedWatson/classnames)
- [isomorphic-fetch](https://github.com/matthew-andrews/isomorphic-fetch)
- [react-router](https://github.com/reactjs/react-router)
- [react-router-redux](https://github.com/reactjs/react-router-redux)

## 工具特性

热替换和 LiveReload

> 基于 [Webpack Vanilla HMR](https://webpack.github.io/docs/hot-module-replacement-with-webpack.html),支持 `components`, `containers`, `reducers`, `routers` 目录的模块热替换,其余目录的修改则会自动刷新页面。

> CSS 的自动刷新需通过 [LiveReload](https://chrome.google.com/webstore/detail/livereload/jnihajbhpnppcggbcgedagnkighmdlei) Chrome 插件配合使用。

> - [Why Vanilla HMR](https://github.com/reactjs/redux/pull/1455)

支持 css-modules

> 后缀为 `.module.less` 或 `.module.css` 的会被解析为 css-modules
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

需要做这个后缀区分么?


内置支持 jsx-control-statements
Copy link
Member

@afc163 afc163 Apr 17, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

个人不推荐用这个,太像传统模板了。

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

嗯,不要内置吧


> jsx 里可以通过 If, Else 和 For 标签来实现控制语句

运行错误和语法错误的提醒

> 通过 [redbox-react](https://github.com/KeywordBrain/redbox-react) 和 webpack hmr overlay 提示运行错误和语法错误

自动引入 `reducer` 和 `saga`

> 通过 webpack 的 `require.context` 黑魔法批量引入 `reducer` 和 `saga`,新增、删除和重命名时会更方便

自动安装 npm 依赖

> ![](https://camo.githubusercontent.com/898e02d6539900efe65fadbfd15e2a1d7ce4dccf/68747470733a2f2f6f732e616c697061796f626a656374732e636f6d2f726d73706f7274616c2f4b6541474f776a70746a6152684d6d2e676966)

数据 mock 和线上调试

> 通过 dora-plugin-proxy 实现,详见:https://github.com/dora-js/dora-plugin-proxy#规则定义

...

## License

MIT

4 changes: 4 additions & 0 deletions boilerplates/redux/gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
dist
node_modules
.DS_Store
npm-debug.log
47 changes: 47 additions & 0 deletions boilerplates/redux/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
{
"private": true,
"entry": {
"index": "./src/entries/index.js"
},
"dependencies": {
"antd": "^0.12.13",
"atool-build": "0.6.x",
"babel-plugin-antd": "^0.3.2",
"babel-polyfill": "^6.3.14",
"classnames": "^2.2.3",
"history": "^2.0.1",
"isomorphic-fetch": "^2.2.1",
"jsx-control-statements": "^3.1.0",
"react": "0.14.x",
"react-dom": "0.14.x",
"react-redux": "4.4.x",
"react-router": "^2.0.1",
"react-router-redux": "^4.0.1",
"redux": "3.3.x",
"redux-actions": "0.9.x",
"redux-saga": "^0.9.5",
"reselect": "^2.0.3"
},
"devDependencies": {
"babel-eslint": "^6.0.2",
"dora": "0.3.x",
"dora-plugin-browser-history": "^0.1.1",
"dora-plugin-livereload": "^0.3.0",
"dora-plugin-proxy": "^0.6.1",
"dora-plugin-webpack": "0.6.x",
"dora-plugin-webpack-hmr": "^0.1.0",
"eslint": "^2.7.0",
"eslint-config-airbnb": "^6.2.0",
"eslint-plugin-react": "^4.2.3",
"pre-commit": "1.x",
"redbox-react": "^1.2.2"
},
"pre-commit": [
"lint"
],
"scripts": {
"start": "dora --plugins \"proxy,webpack,webpack-hmr,livereload?enableJs=false,browser-history?index=/src/entries/index.html\"",
"build": "atool-build",
"lint": "eslint --ext .js,.jsx src/"
}
}
14 changes: 14 additions & 0 deletions boilerplates/redux/proxy.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// More Examples: https://github.com/dora-js/dora-plugin-proxy#规则定义

module.exports = {
'/webapi/*': 'http://1.1.1.1',

'/api/async_count': function(req, res) {
setTimeout(function() {
res.json({
success: true,
data: Math.floor(Math.random() * 2) === 1,
});
}, 500);
},
};
28 changes: 28 additions & 0 deletions boilerplates/redux/src/components/Count/Count.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import styles from './Count.module.less';
import React, { Component, PropTypes } from 'react';
import classnames from 'classnames';
import { Button } from 'antd';
import { COUNT_DECREASE, COUNT_DECREASE_ASYNC, COUNT_REDUCE } from '../../constants/count';

const Count = ({ dispatch, count }) =>
<div className={classnames({
[styles.normal]: count % 2 === 0,
[styles.odd]: count % 2 === 1,
})}>
<div>{count}</div>
<Button className={styles.button} size="small" onClick={() => { dispatch({ type: COUNT_DECREASE }); }}>+</Button>
<Button className={styles.button} size="small" onClick={() => { dispatch({ type: COUNT_REDUCE }); }}>-</Button>
<Button className={styles.button} size="small" type="primary" onClick={() => { dispatch({ type: COUNT_DECREASE_ASYNC }); }}>+ (async)</Button>
<br /><br />
<If condition={count % 2 === 0}>
<span>even</span>
<Else />
<span>odd</span>
</If>
</div>

Count.propTypes = {
count: PropTypes.any,
};

export default Count;
10 changes: 10 additions & 0 deletions boilerplates/redux/src/components/Count/Count.module.less
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@

.normal {
background: #fafafa;
}
.odd {
background: #ccc;
}
.button {
margin-right: 3px;
}
4 changes: 4 additions & 0 deletions boilerplates/redux/src/constants/count.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@

export const COUNT_DECREASE = 'count/decrease';
export const COUNT_REDUCE = 'count/reduce';
export const COUNT_DECREASE_ASYNC = 'count/decrease/async';
18 changes: 18 additions & 0 deletions boilerplates/redux/src/containers/App.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import React, { Component, PropTypes } from 'react';
import { connect } from 'react-redux';
import { createSelector } from 'reselect';
import Count from '../components/Count/Count';

const App = (props) =>
<Count {...props} />

App.propTypes = {
};

const selectors = createSelector([
state => state.count,
], (count) => {
return { count };
});

export default connect(selectors)(App);
16 changes: 16 additions & 0 deletions boilerplates/redux/src/entries/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Demo</title>
<link rel="stylesheet" href="index.css" />
</head>
<body>

<div id="root"></div>

<script src="common.js"></script>
<script src="index.js"></script>

</body>
</html>
Loading