Skip to content
This repository has been archived by the owner on Jun 17, 2024. It is now read-only.

Commit

Permalink
[update] 更新项目, readme
Browse files Browse the repository at this point in the history
  • Loading branch information
lawler61 committed Jun 20, 2019
1 parent bc1991d commit 817e47a
Show file tree
Hide file tree
Showing 78 changed files with 7,506 additions and 333 deletions.
7 changes: 7 additions & 0 deletions .babelrc
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,13 @@
"plugins": [
"react-hot-loader/babel",
"@babel/plugin-syntax-dynamic-import",
[
"import",
{
"libraryName": "antd-mobile",
"style": true
}
],
[
"@babel/plugin-proposal-decorators",
{
Expand Down
3 changes: 3 additions & 0 deletions .eslintignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,6 @@ node_modules/
build
dist
config
server
app/mobx
app/tools
12 changes: 8 additions & 4 deletions .eslintrc
Original file line number Diff line number Diff line change
Expand Up @@ -36,10 +36,7 @@
],
"comma-dangle": [
"error",
"always-multiline",
{
"functions": "ignore"
}
"always-multiline"
],
"quotes": [
"error",
Expand All @@ -51,6 +48,13 @@
"args": "after-used"
}
],
"no-use-before-define": [
"error",
{
"functions": false,
"classes": false
}
],
"no-console": "off",
"consistent-return": "off",
"react/jsx-filename-extension": [
Expand Down
6 changes: 6 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@
.idea
.project

# vscode
.vscode

# npm
node_modules
npm-debug.log
Expand All @@ -17,5 +20,8 @@ package-lock.json
build
dist

# bak
*.bak

# cache
.cache
154 changes: 140 additions & 14 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,26 +1,152 @@
# init-react-project
To initialize your react project
# react-lighter

## 初始化 react 项目
to initialize your react project as simple as lighting a fire

初始化 react 项目

## 技术栈

react + mobx + router + antd + axios

## 目录结构

```markdown
├── src // 项目主目录
│ ├── assets
│   ├── components // 可重用组件
│   ├── index.tsx
│   ├── interface.ts
│   ├── mobx // mobx 注入工具
│   ├── pages // 项目界面
│   │   ├── 404
│   │   └── Example
│   ├── routes
│   ├── tools // 脚手架
│   ├── utils
│   └── websocket
└── config // webpack 配置
```

## 运行

```bash
yarn or npm i // 下载包
yarn dll // 预编译
yarn start // 本地开发
yarn build // 项目打包
yarn server // 加载打包后的项目
yarn or npm i

yarn dll

yarn start // for dev

yarn build && yarn server // for prod
```

## 特点

待更新
### 一、热加载

采用 [react-hot-loader](https://github.com/gaearon/react-hot-loader) 配合 babel,可实现样式替换、节点改变不影响 state 等功能,达到局部热加载的效果

### 二、抽离 dll

使用 webpack DllReferencePlugin 插件,先把 react 抽离成 dll,在后续开发中能更快加载

### 三、多线程打包

使用 [happypack](https://github.com/amireh/happypack) 启动多线程,实现光速打包

### 四、css 处理

1. 使用 [postcss](https://github.com/postcss/postcss) 提供样式兼容

2. 使用 [mini-css-extract-plugin](https://github.com/webpack-contrib/mini-css-extract-plugin) 抽离 css

3. 使用 [purgecss-webpack-plugin](https://github.com/FullHuman/purgecss-webpack-plugin) 去除无用 css

4. 使用 [postcss-px-to-viewport](https://github.com/evrone/postcss-px-to-viewport) 规范长度单位

### 五、mobx 注入

参考:

- [用mobx构建大型项目的最佳实践](https://juejin.im/post/5c627df76fb9a049c232e990)

- [mobx 项目最佳实践](https://github.com/luruozhou/mobx-example)

1. mobx 分层:views、actions、stores

> views 派发 actions,由 actions 做逻辑处理后调用 stores 做数据持久化,views 通过注入的 stores 获取到最新的数据。典型的 MVC 架构
>
> 解决了 mobx 中数据随处可定义、逻辑交互方法随处可声明等问题
2. 唯一数据源

## TODO
> 每个 view 绑定 store 数据源,顶层 view 保存着全局数据源,类似于 redux 的 createStore 机制
>
> 实现了 stores 间交叉引用的可能,同时能够达到 redux 中 initialState 的“数据恢复”机制
1. react-hot-loader 监听 css 变化(react-hot-loader 不能监听抽离的 css 代码) √
3. 按需实例化

> 通过 [ts-plugin-mmlpx 插件](https://github.com/mmlpxjs/ts-plugin-mmlpx),实现 stores 和 actions 的自动查找和绑定、通过 Object.defineProperty 实现按需实例化,提高性能
4. tools 脚手架使用

> 参见 [mobx example 开发章节](https://github.com/luruozhou/mobx-example#%E5%BC%80%E5%8F%91)
### 六、Axios 封装

参考

- [axios restful 封装](https://github.com/zhaotoday/rest)

将 axios 进行 restful 风格的封装,配合 interceptor 和 histroy 进行权限验证和跳转

使用:

1. GET /users/:id

```js
request.setPath('users').get({ uri: 'lawler' })
```

2. POST /users

```js
request.setPath('users').post({
data: { email: 'lawler61@163.com', password: '123456' }
})
```

3. PUT /users/:id

```js
request.setPath('users').put({
uri: 'lawler', data: { name: 'jeffery' }
})
```

4. DELETE /users/:id

```js
request.setPath('users').delete({ uri: 'lawler' })
```

5. GET /users/:id/articles?page=2&limit=10

```js
request.setPath('users/{id}/articles').replace('lawler').get({
query: { page: 2, limit: 10 }
})
```

6. PATCH /users/:id/articles/:id

```js
request.setPath('users/{id}/articles/{id}').replace('lawler', 'react 学习之路').patch({
data: { title: '前端学习' }
})
```

2. 懒加载组件 √
## 项目展示

3. 去除无用 css 代码 (不能使用 css 分离,否则无法去除)√
1. [问答系统 前端 -> https://github.com/lawler61/qa-app](https://github.com/lawler61/qa-app)

4. 制作成脚手架
2. [线上地址,去看看 -> https://qa.omyleon.com](https://qa.omyleon.com)
116 changes: 116 additions & 0 deletions config/createMobxTransformer.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
// https://github.com/mmlpxjs/ts-plugin-mmlpx

const ts = require('typescript')

const defaultOptions = {
bindings: ['mStore', 'mAction']
}

const createTransformer = (options = defaultOptions) => {
const transformer = context => {
const bindings = []

let fileName, pageName

const visitor = node => {
if (ts.isSourceFile(node)) {
;[pageName, fileName] = getFileNameFrom(node.fileName)
return ts.visitEachChild(node, visitor, context)
}

if (ts.isImportDeclaration(node)) {
node.forEachChild(importChild => {
if (
ts.isImportClause(importChild) &&
importChild.namedBindings &&
ts.isNamedImports(importChild.namedBindings)
) {
importChild.namedBindings.elements.forEach(
({ propertyName, name }) => {
// import {mStore as otherName} from './store.js'
const lib = node.moduleSpecifier.text // './store.js' 暂时没用到
const namedBinding =
(propertyName && propertyName.getText()) || name.getText() // mStore
const aliasBinding = propertyName && name.getText() //otherName
if (options.bindings.indexOf(namedBinding) > -1) {
bindings.push(aliasBinding || namedBinding)
}
}
)
}
})

return node
}

if (node.decorators) {
node.decorators.forEach(decorator => {
const { expression } = decorator
if (
ts.isIdentifier(expression) &&
bindings.indexOf(expression.getText()) > -1
) {
// 调用形式 @mStore @mAction
decorator.expression = ts.createCall(expression, undefined, [
ts.createObjectLiteral([
ts.createPropertyAssignment(
ts.createLiteral('page'),
ts.createLiteral(`${pageName}`)
),
ts.createPropertyAssignment(
ts.createLiteral('name'),
ts.createLiteral(`${fileName}`)
)
])
])
} else if (
ts.isCallExpression(expression) &&
ts.isIdentifier(expression.expression) &&
bindings.indexOf(expression.expression.getText()) > -1
) {
// 调用形式 @mStore({...someProps}) @mAction({...someProps})
let arg0 = expression.arguments[0]
if (ts.isObjectLiteralExpression(arg0)) {
decorator.expression = ts.createCall(
expression.expression,
undefined,
[
ts.createObjectLiteral([
ts.createPropertyAssignment(
ts.createLiteral('page'),
ts.createLiteral(`${pageName}`)
),
ts.createPropertyAssignment(
ts.createLiteral('name'),
ts.createLiteral(`${fileName}`)
),
...arg0.properties
]),
...expression.arguments.slice(1)
]
)
}
}
})

return node
}

return ts.visitEachChild(node, visitor, context)
}

return node => ts.visitNode(node, visitor)
}

return transformer
}

function getFileNameFrom(path) {
let reg = /([^\/]+)\/(?:actions|stores)\/(.+)\.(?:t|j)sx?$/
let matched = path.match(reg)
let pageName = matched && matched[1]
let fileName = matched && matched[2]
return [pageName, fileName]
}

module.exports = createTransformer
24 changes: 14 additions & 10 deletions config/options.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
const { main, name, author } = require('../package.json')

const entryDir = main.split('/')[0]
const { basePath, main, name, author } = require('../package.json')

const entryDir = basePath
const outputDir = 'dist'

// 必要参数
Expand All @@ -14,9 +13,9 @@ const baseOptions = {
purifycssFile: [`${entryDir}/*.html`, `${entryDir}/**/*.js`],
assetsPath: 'assets',
moduleToDll: {
react: ['react', 'react-dom', 'react-router-dom']
react: ['react', 'react-dom', 'react-router-dom'],
},
dllFiles: ['react.dll.js', 'react.manifest.json']
dllFiles: ['react.dll.js', 'react.manifest.json'],
}

// 可选参数
Expand All @@ -25,11 +24,16 @@ const extraOptions = {
// 选择 true 在开发模式中 react-hot-loader 不能热加载抽离出去的 css [https://github.com/gaearon/react-hot-loader]
// 选择 false purifycss-webpack 不能去除无用的 css [https://github.com/FullHuman/purgecss-webpack-plugin]
useCssExtract: false,
copyConfig: { // 是否有不需要处理,直接拷贝的文件
needsCopy: true,
copyConfig: {
// 是否有不需要处理,直接拷贝的文件
needsCopy: false,
fromPath: `${entryDir}/docs`,
toPath: `${outputDir}/docs`
}
toPath: `${outputDir}/docs`,
},
}

module.exports = Object.assign(baseOptions, { entryDir, outputDir }, extraOptions)
module.exports = Object.assign(
baseOptions,
{ entryDir, outputDir },
extraOptions
)
Loading

0 comments on commit 817e47a

Please sign in to comment.