关于 Redux 中间件

Redux 的中间件是定义一个函数,对 dispatch 进行改造,在发出 action 与执行
reducer 之间添加其他功能,这是对 Redux
进行功能拓展的方式。那么这个中间件的实现原理是什么呢?如何写一个 Redux
的中间件呢?

从 react-start 到 co 源码
(一)


这是一个系列文章。主要分为三篇,讲述了 react
开发环境的简单搭建,脚手架的开发以及 co 源码的分析。对读者了解 react 和
generator 有一定的帮助。这是第一篇简单的讲述了 react 开发环境的搭建。

React
全家桶实现一个简易备忘录


前言 总括: 本文采用 react+redux+react-router+less+es6+webpack,
以实现一个简易备忘录 (todolist) 为例尽可能全面的讲述使用 react
全家桶实现一个完整应用的过程。 代码地址:React 全家桶实现一个简易备忘录
原文博客地址:Rea…

redux 在 react
中的应用(基础篇)


依靠单枪匹马的 react
来构建应用的情况下,组件之间的通讯一直是个难题,借助于
redux,这个问题将迎刃而解,同时,redux
也使得构建一个复杂大型的应用成为可能,redux
是可选方案,但是作为学习对象,你千万不要错过!

12 步 30 分钟,完成用户管理的 CURD 应用
(react+dva+antd)


本文会一步步引导大家如何创建一个完整的 CURD
应用,包括列表、删除、编辑、创建,以及 loading 状态的自动处理等,基于
react, dva 和 antd 。

在 redux
上探索无需刷新前端页面的后端开发体验


后端应用为前端应用提供了状态(state)。借助
redux,我们可以在服务器重启后重新拉去数据,替换
action,构建相同条件下的新状态,从而不需要刷新页面来重启前端应用。这对于以重启非常迅速的脚本语言作为后端语言的应用,并且是同时进行前后端开发的场景来说,可以提供更好的开发体验。

简单几步助你优化 React
应用包体


本文从属于笔者的 Web 前端入门与最佳实践 中的 React
入门与最佳实践系列。本文首发于简单几步助你优化 React 应用包体 –
某熊的全栈之路 – SegmentFault,考虑到专栏知识体系的完善转发到了这里。

React 起手式: 来写个 TodoList


一个简单 TodoList 的教程,让初学者能够快速上手并且对 React
有个大概的了解 😀

正确掌握 React 生命周期
(Lifecycle)


1 React 用了这么久,经常遇到的问题是 setState 在这里写合适吗?
2 为什么 setState 写在这里造成了重复渲染多次?
3 为什么你的 setState 用的这么乱?
4 组件传入 props 是更新呢?重新挂载呢?还是怎样?

[英] Netflix:使用 React 构建高性能的 TV
用户界面


Netflix 在 2015 年就选择 React 作为前端架构,这篇文章总结了 Netflix
在解决性能问题的经验。

[译文] React:
一步一步搭建大型应用


翻译自
https://www.fullstackreact.com/articles/react-tutorial-cloning-yelp/
讲述了,从安装开发环境测试环境,到搭建应用,一步一步如何搭建答应完整的
react 应用的。

主要一下几方面:

  1. 环境配置
  2. 项目结构设计
  3. react 测试书写
  4. 路由和组件的设计

涉及到的知识:

React,Postcss, Webpack, css modules, react-router, karma, mocha,
enzyme, flexbox

基于 vue+vuex+localStorage
开发的本地记事本


本文采用
vue+vuex+localStorage+sass+webpack,实现一个本地存储的记事本。兼容 PC
端和移动端。

翻译 | 如何规模化 React
应用


译者: 朱乙(沪江前端开发工程师)

我们最近发布了 React Boilerplate
3.0,在发布前几个月,我们与数百位开发者进行了沟通,讨论了他们是如何构建和规模化
WEB 应用的。下面将我们从中学到的东西分享给大家。

React
实战:模仿卖座电影


一个使用 react、react-router、redux 高仿卖座电影网的项目

[译] 在 setState
中使用函数替代对象


React 中 setState 的新用法!

一个 react+redux
工程实例


这篇文章主要实现一个简单的例子,难度不大,但是贯穿了 react+redux
基本思想。
他将会是一个连续教程,这只是第一篇,不涉及 redux 中间件,redux
处理异步等内容,也不涉及 react 性能优化,不可变数据 immutable.js
的内容。但这些不涉及到的内容,都会随着这个 demo
的复杂度一步一步提升,在后续章节有分析和使用。

React
的四个概念简单介绍


React 的四个概念简单介绍:Virtual DOM;React 组件;Jsx 语法;Data
Flow(单向数据流)

CSS Modules 详解及 React 中实践 – pure render –
知乎专栏


CSS Modules 详解及 React 中实践

深入理解 React
高阶组件


高阶组件是一种很好的模式,很多 React
库已经证明了其价值。这篇文章中我们将会详细的讲解什么是
HOC,你能用它做什么,它有哪些局限,如何实现它。

React 中 setState
同步更新策略


我们在上文中提及,为了提高性能 React 将 setState
设置为批次更新,即是异步操作函数,并不能以顺序控制流的方式设置某些事件,我们也不能依赖于
this.state
来计算未来状态。典型的譬如我们希望在从服务端抓取数据并且渲染到界面之后,再隐藏加载进度条或者外部加载提示:

React 实现的 2048 小游戏
(新手入门~)


基于 React 和 Webpack 开发的一个 2048 小游戏,相对于枯燥的
TodoList,这个可能更有趣一点。

React.js: web 开发者的 14
个工具和资源


自从 Facebook 在 2013 年发布了库之后,React.js
正在快速被广大开发者所接受。它现在已经成为了 GitHub 上被收藏次数排名第 5
的开源项目,越来越多的企业正在寻找 React.js
开发者。本文为广大开发者介绍了 14 个工具和资源,助力 web 开发。

可能是注释写的最详细的 React 脚手架 ─
支持多入口及支持复杂业务分离


一个完善的 Koa+Webpack+React 集成开发环境, 实现了多页面应用入口

框架优点

· 支持多页面类型的 React 应用开发
· 实用 Koa 服务器进行构建, 扩展性更强
· 分为开发环境 (Dev) 和上线 (Prod) 环境, 可以自由选择并进行开发
· 支持 React 热加载, 可以实现 CSS 及 JS 的热加载效果
· 附加 Postcss 工具, 可实现 Sass 语法开发, 自动填充 CSS3 兼容方案及 CSS
雪碧图的自动化构建
· 使用了 CSS-Module 技术, 实现了样式的复用性和解决了样式污染

基于 React 的 fetch 请求测试工具 —
fetch-request


基于 dva antd 和 React 可以选择多种请求类型, 用于在开发中测试接口

在 React.js 中使用 PureComponent
的重要性和使用方式


如果你用 React,请学会使用 PureComponent

前端学习指南 – 广度 +
深度的探索


一篇由浅入深、逐步递进的学习指南,遵循曲线,将带你涉足前端开发过程中方方面面。若想在前端领域有更深的思考,也提供了相应的进阶篇,介绍技术背后的原理阐述、架构思考、编程方法论等。

用 React+Redux 写一个 RubyChina 山寨版
(二)


React+redux+react-router-redux+antd+es6+redux-thunk 的 RubyChina
山寨版,适合初学 ReactJs,一边写代码一边写文档,记录成长的痕迹

一个简单的甘特图 React 组件封装
gantt-for-react


甘特图一般用来做任务、项目管理。直观的看出任务的时间安排以及依赖关系。

[译] Netflix: 使用 React
构建高性能的电视用户界面


这篇文章总结了 Netflix 在使用 React 框架搭建其 UI
框架的过程中,性能优化方面的一些经验。

一张图学习 ES6 中的 React
生命周期与流程


为了理解 React
在学习生命周期的过程中想要一个生命周期的图,网上有一些流程,但是看着不够全,就尝试着画了一个,第一次弄,欢迎提意见

React
最少必要知识


去年 8 月左右,看到了 ThoughtWorks 发布的 2016
年技术雷达,里面重点推荐了 react.js
技术,加上前端技术栈三足鼎立中,react 也占据一席,其他两个分别是 vue.js
及 angular.js,而 react
和其他两个的区别在于,它颠覆了整个技术栈,自成一派,抛弃了 HTML 和
DOM,引入了 JSX 语法,让程序员可以更专注于逻辑代码。这一切让我对
react.js 充满了好奇,决定花时间学习一下,一探究竟。

简谈 react + redux
架构的特点和挑战


本文分别从 react 和 redux
各自的特点出发,分析了架构中二者的特点和问题所在。

JS
全栈教程


本课程是基于阮一峰的 js 全栈教程的视频版本,免费供大家观看

React 开发流程——利用 React
构建简单的可检索产品数据表


React 开发流程——利用 React 构建简单的可检索产品数据表

基于 Webpack 2 的 React Router
懒加载路由配置


基于 Webpack 2 的 React Router 懒加载路由配置承接基于 Webpack 2 的 React
组件懒加载,主要是对上一篇文章中的部分论述进行补充和修正,从属于 Web
前端入门与工程实践。

UXCore
组件单测的一些事儿


UXCore 是 XUX 团队开源的 PC 端 React UI 套件,作为一个支持企业级应用的
React UI
开源套件,为了保持项目的持续集成,良好的单元测试必不可少。本文来分享一下在编写单元测试的过程中遇到的一些问题和总结。

React-Manga 一个以 React 实现的漫画
WebApp


使用 React 实现的 WebApp
版开源漫画阅读器。目前已实现用户登录注册、提供漫画推荐、漫画搜索、漫画收藏、漫画阅读、历史记录
等功能。

React Toolbox – 符合 Material Design 规范的 React
组件


符合 Material Design 规范的 React 组件

浅析 React
之事件系统(二)


文章介绍了 React 的事件系统,比较了与原始事件的区别和如何合理使用 React
合成事件与原生时间

打造 redux
同构应用


handcrafting-an-isomorphic-redux-application-with-love

React
服务端渲染缓慢原因浅析


缘何 React 服务端渲染的性能会如此之差;从设计理念的角度来看 React
本身专注于跨平台的界面库,其保证较好抽象层次的同时势必会付出一定的代价,并且
Facebook
在生产环境中并未大规模应用服务端渲染,也就未花费过多的精力来优化服务端渲染的性能。笔者也对比了下
React 与 Preact
有关服务端渲染的实现代码,确实高度的抽象需要额外的代码逻辑与对象创建,React
本身并没有冗余的部分,只是单纯地大量的毫秒级别额外对象操作的耗时的累加导致了最后性能表现的巨大差异。我们首先看下
Preact 的 renderToString 的函数实现,其紧耦合于 DOM
环境,以较低的抽象程度换取较少的代码实现:

基于 reactjs+redux+postcss+webpack2
的单页应用项目模板


基于 reactjs+redux+postcss+webpack2 的单页应用项目模板,webpack 已升级到
2.2.1。

使用 mobx 开发高性能 react
应用


react 作为模块化的 UI
层框架,在前端领域正处于如日中天的地位。但如果仅仅使用 react,往往需要在
UI
层中承载过多的业务逻辑,引入模块化的同时却破坏了分层。为此业界有很多解决方案,目前最流行的就是
redux,其适用于大型项目。而本文将详细介绍一种更灵活的、适合于中小型应用的数据层框架
mobx。

React 常用面试题目与分析 –
某熊的全栈之路


React 常用面试题目与分析从属于笔者的 Web
前端入门与工程实践,更多前端思考借鉴 2016 – 我的前端之路:
工具化与工程化

React Table – 适用于 React
的轻量级、可扩展的数据表格


亮点:轻量,压缩后 7kb;完全定制的 JSX
模板;支持客户端和服务器端的分页和多重排序;设计简洁,方便主题化;通过
props 和 callback 来高度定制。

React
爬坑记


趁年假研究了下 react,写了点坑

通用 React
兼容渲染引擎:Rax


Rax 是阿里开源的一个通用的 JavaScript
库。它具备快速、轻量级的,并可跨浏览器、Weex 和 Node.js
的特点。同时,它有 React 兼容的 API ,便于了解 React
的朋友们快速上手。喜欢的朋友可以了解下。

用 React+Redux 写一个 RubyChina 山寨版
(一)


React+Redux+react-router-redux+antd+babell+es6 的 RubyChina
山寨版,适合初学 ReactJS,一边写代码一边写文档,记录成长的痕迹

React-Redux-Appointment


React-Redux 小应用:React-Redux-Appointment

从 react-start 到 co 源码
(二)


这是一个系列文章。主要分为三篇,讲述了 react
开发环境的简单搭建,脚手架的开发以及 co 源码的分析。对读者了解 react 和
generator 有一定的帮助。这是第二篇讲述了 react 开发环境脚手架的开发。

介绍 roadhog —— 让 create-react-app
可配的命令行工具


roadhog 是一个 cli 工具,提供 server 和 build
两个命令,分别用于本地调试和构建。命令行体验和 create-react-app
一致,配置略有不同,比如默认开启 css modules,然后还提供了 JSON
格式的配置方式。

基于 React.js + Node.js 的开源博客框架
phoenix-blog-framework


phoenix-blog-framework 是我开发的一款个人博客框架。使用 React.js +
Typescript + CSS-Modules + pug 等技术做前端,用 Node.js + Mongodb +
Typescript 做后台开发。用 Markdown 做文章写作系统。

使用 React、Node.js、MongoDB、Socket.IO 开发一个角色投票应用 | 闲散人生
|
idlelife


在本教程里你将学习到如何使用 Node.js 构建一个 REST API、使用 MongoDB
保存和检索数据、使用 Socket.IO 跟踪在线的访问者,以及使用 React + Flux
和服务端渲染来构建单页面应用,最后将应用部署到云端。

[译] 编写 React
组件的最佳实践


当我一开始写 React
的时候,我记得有许多不同的方法来写组件,每个教程都大不相同。虽然从那以后
React 框架已经变得相当的成熟,但似乎仍然没有一种明确的写组件的 “正确”
方式……

React 开发中的 Provider 和 HOC
模式


React 开发中的 Provider 和 HOC 模式

将 React 应用优化到
60fps


作为 DOM 的抽象,React 自然也遵循了著名的抽象漏洞定理(详见 2016 –
我的前端之路: 工具化与工程化),引入 React
导致了在应用本身的性能消耗之外势必会增加额外的性能损耗。Dan Abramov 在
Twitter 上提到,React 并不能保证性能优于原生的 DOM
实现,但是它能够帮助大量的普通开发者构建大型应用的同时不必在初期就耗费大量的精力在性能优化上,在大部分用户交互界面上
React
已经能够帮我们进行合理的优化了。但是在应用开发的过程,特别是最后的细节优化阶段中,我们需要着眼于部分性能瓶颈页面,正确地认识这种限制的缘由以及相对应的处理方案。本文即是作者在构建自己的大型应用中经验的总结。

React:颠覆式前端UI框架
先上干货。好文章:
Web应用的组件化开发?
关于React你需要知道的13件事 –
aimforsimplicity.com
一看就懂的ReactJs入门教程-精华版
React.js 2016
最佳实践
如何学习React
React项目构建三部曲
前端早读课收集发表系列
分享一个 react + redux
完整的项目,同时写一下个人感悟
———-对应的gitlab项目
大腿:基于webpack + react + react-router + redux + less + flex.css +
ES6
的React版cnode社区
解剖react组件的多种写法与演进
揭秘react生态体系

 

系统步骤学习文章:
React全家桶–从零到入门
React启蒙(译)
React.js
小书
阮一峰:React
技术栈系列教程

后台项目应用分享

选择UI框架:(我选择的是支付宝的Ant)
[译] 快速构建原型最好用的 10 个 ReactJS UI
框架

后台项目应用分享

webpack + react + redux + antd

  • 后台项目应用分享
    • 策略篇
      • 框架选择
      • 组件化开发
        • 组件?组件!
        • CSS in
          JS下的样式开发思路
        • 展示组件 VS
          容器组件
        • Action/Reducer
          应该和组件绑定吗
        • 调试Redux
      • 规范建议
        • 命名规范
        • 模块规范
      • 目录划分
    • UI篇
      • 如何引入ant
      • 如何定制antd
      • 动手写一个antd组件
    • 工具篇
      • devServer什么鬼
      • 不容忽视的HtmlWebpackPlugin
      • dllPlugin教程没有教你
      • SourceMap全方案
      • 拆分配置文件
    • 协同篇
      • 承载页
        • 纯静态 vs
          服务端渲染
        • 资源灰度 &
          回溯
      • 数据接口
        • 文档
        • mock
        • proxy
      • 权限控制
        • 页面权限
        • 操作权限

完整项目:
嘟嘟微生活——我司主项目基于React全家桶的前端架构。

策略篇

资源:
React
专题
我收集的Github项目
慕课网:React.js 开发参见问题
Q&A
我搭建的react脚手架

框架选择

兼容性IE9+

  • 组件化:React
  • 状态管理:React Redux
  • 前端路由: React Router
  • Ajax请求: Axios
  • UI库:Ant Design
  • 构建工具:Webpack

怎么学习一个新技术?从官网开始
怎么开始一个新项目?搭建环境

组件化开发

react vs vue? (理念思想)
如果做一件事有两个方案,一个简单,一件困难,不用考虑,选择困难的那个。
组件划分得越细,负责的事情越少,维护起来就越简单,逻辑就越清晰。

组件?组件!

(讨论)

编写react项目步骤:
目的是为了代码可复用性、可维护性
理解需求、分析需求、划分这个需求由哪些组件构成(拆分组件,保持你的组件无状态化)

CSS in JS下的样式开发思路

  • 样式跟着组件走

button-group.js
button-group.less
  • 使用工具方法

@import (reference) "~BaseLess";
.username{
    display: inline-block;
    max-width: 200px;
    .text-overflow() //使用单行溢出隐藏方法
}

注:在less文件中引用alias定义或node _modules下的less文件,需要在路径前加~

  • 使用compose实现样式复用

/* components/Button.css */
.base { /* 所有通用的样式 */ }

.normal {
  composes: base;
  /* normal 其它样式 */
}

.disabled {
  composes: base;
  /* disabled 其它样式 */
}
imp
  • 重置全局样式

.collapsed {
    //anticon类原样输出
    :global(.anticon) {
        font-size: 16px;
        margin-left: 8px;
    }
    :global(.anticon+span),
    :global(.ant-menu-submenu-vertical > .ant-menu-submenu-title:after) {
        display: none;
    }
}

扩展阅读:CSS Modules 详解及 React
中实践

前端组件化原则:
① 标准化
多人协作如果不制定一套标准的话,显然是进行不下去的,任何一个组件都应该遵守一套标准,可以使得不同区域的开发人员据此标准开发出一套标准统一的组件。(组建命名规则、就近原则、样式分离独立文件)。组件化要独立(数据、业务逻辑和交互)又要提供接口还要进行封装。
② 组合性
组件必定是需要相互嵌套组合的,这就需要组件间具有相互的独立性以及有良好的接口,这也是一个组件最基本的构成。
③ 重用性
组件内部应该是高聚合的,任何一个组件都应该是一个可以独立的单元,可以扩展到其他不同的应用场景。
④ 可维护性
任何一个组件应该都具有一套自己的完整的稳定的功能,仅包含自身的,与其它组件无关的逻辑,使其更加的容易理解,使其更加的容易理解,同时大大减少发生bug的几率。

展示组件 VS 容器组件

我们先来看一下Redux官方文档中的定义:

  展示组件 容器组件
作用 描述如何展现(骨架、样式) 描述如何运行(数据获取、状态更新)
直接使用 Redux
数据来源 props 监听 Redux state
数据修改 从props调用回调函数 向 Redux 派发 actions
调用方式 手动 通常由 React Redux 生成

结合官方定义,我们把组件分为三个层次:

  • 应用(App)
    整个管理系统是一个应用(单页模式一般只有一个应用,多页模式可能有多个应用)
  • 容器(Container):可以从路由访问得到的组件叫做容器,类似传统开发模式中的后端页面
  • 组件(Component):容器以外的组件都叫组件

哪些需要组件化?
要么可以复用的,要么就是一块比较大的逻辑比较复杂的单元。
复用代表这个组件要到处引用,一是为了抽象概念,二是为了后期更好地维护。
而比如像banner这种内部逻辑比较复杂的模块,为了更好梳理里面的逻辑也应该和父组件解耦,独立成一个单元。

Action/Reducer 应该和组件绑定吗

(讨论)

Why要组件化?
应对复杂的不同状态和情况。

调试Redux

(演示)

构建一个调试工具配置文件devtool.js

/**
 * redux调试工具
 */

import React from 'react';
import { createDevTools } from 'redux-devtools';
import LogMonitor from 'redux-devtools-log-monitor';
import DockMonitor from 'redux-devtools-dock-monitor';

export default createDevTools(
  <DockMonitor defaultIsVisible={false}
               toggleVisibilityKey="alt-h"
               changePositionKey="alt-q">
    <LogMonitor />
  </DockMonitor>
);

开发环境,在容器root.dev.js中引入调试工具

import React from 'react';
import DevTools from './devtools';
import Layout from 'components/layout';
import style from './style.less'

export default class Root extends React.Component {

  render () {
    return (
      <div className={style.root}>
        <Layout>{this.props.children}</Layout>
        <DevTools />
      </div>
    )
  }
}

开发环境,在store.dev.js中引入调试工具

import DevTools from 'containers/root/devtools'

export default function configureStore(initialState, reducers) {
    const store = createStore(
        ...
        compose(
            ...
            //redux调试工具
            DevTools.instrument()
        )
    );
    ...
    return store
}

为什么不直接从 JSX 直接渲染构造 DOM
结构,而是要经过ReactDOM.render中间这么一层呢?

规范建议

  1. 把这个结构渲染到 canvas 上,或者是手机 App 上
  2. 当数据变化,需要更新组件的时候,就可以用比较快的算法操作这个
    JavaScript 对象,而不用直接操作页面上的
    DOM,这样可以尽量少的减少浏览器重排,极大地优化性能。

命名规范

  • 变量名以驼峰方式,如:

const userInfo = {}
  • 类名以大写字母开头,如:

Class UserManager extend from React.Component{
    ...
}
  • 文件(夹)名一律小写,以下划线_或中杠线-作为分隔符
  • 文件(夹)名以下划线_区分类型,如:common_action.js,表示Action
  • 文件(夹)名以圆点.区分环境,如:root.dev.js,表示开发环境

react的一些情况:

模块规范

  • 同一目录下的模块之间以相对路径的方式引用
  • 不同目录下的模块之间以绝对路径的方式引用
  • 常用模块以alias的方式引用(推荐alias以大写字母开头,以区分模块路径引用)

思考:这样设计的好处是什么?

  1. 需要HTML结构写得好,然后拆分成react的开发方式
  2. 考虑复用性,脑子里要有类的继承概念。这里要一定的功力
  3. 是否能写成函数组件
  4. 要动态传参,写出那个接口形式
  5. 糅合redux
  6. 非双向绑定,需要自己触发状态更新
  7. 类似于java等后台的语法

目录划分

build                构建工具及配置
dist                 目标目录
src                  源码目录
mock                 mock数据
public               开发环境临时目录
node_modules         npm包目录
node_shrinkwrap      npm离线包目录

延伸阅读:为什么要有npm离线包?

build:构建工具及配置

build/
    lib/                                     工具库
        *.js
    shell/                                   部署脚本
        *.sh
    webpack.config.common.js                 webpack公共配置
    webpack.config.dev.js                    webpack开发环境配置
    webpack.config.prod.js                   webpack生产环境配置
    webpack.dll.config.js                    webpack.dllPlugin配置
    config.js                                构建配置

config.js示例:

const fs = require('fs');
const path = require('path');

//提取多文件共用配置、项目可定制的配置

const pkg = require('../package.json');
const src = path.resolve(__dirname, '../src');
const dist = path.resolve(__dirname, '../dist/resource')

module.exports = {

    /*
     * 以下配置在项目中通常不需要变动
     */

    //package.json
    pkg,
    //源文件路径,使用绝对路径
    src,
    //导出路径,使用绝对路径
    dist,
    //静态资源目录,使用绝对路径
    contentBase: path.resolve(__dirname, '../public'),
    //导出资源映射表路径,使用绝对路径
    manifest: path.resolve(__dirname, '../dist/manifest'),
    //资源映射表名称,如下配置将根据当前日期生成对应的资源映射表
    manifestFileName: function() {
        return `${new Date().getFullYear()}-${new Date().getMonth()+1}-${new Date().getDate()}.json`
    },
    //dll生成路径
    dllPath: {
        development: path.resolve(src, 'vendor'),
        production: dist
    },
    //dll资源映射
    dllManifest: {
        development: path.resolve(src, 'vendor/dll-manifest.json'),
        production: path.resolve(dist, 'dll-manifest.json')
    },
    //js压缩配置
    UglifyJsOptions: {
        compress: {
            //不输出警告
            warnings: false
        },
        //不输出注释
        comments: false
    },

    /*
     * 以下配置在项目中通常需要定制
     */

    //生产环境中前端资源路径(需要与nginx配置保持一致),可以为域名url
    publicPath: '/Public/',
    //模块别名,相对于conf.src路径配置
    //- 推荐以大写字母开头,以区分非别名
    alias: {
        // 起别名:"module" -> "new-module" 和 "module/path/file" -> "new-module/path/file"
        // "module": "new-module",
        // 起别名 "only-module" -> "new-module",但不匹配 "module/path/file" -> "new-module/path/file"
        // "only-module$": "new-module",
        // 起别名 "module" -> "./app/third/module.js" 和 "module/file" 会导致错误
        // 模块别名相对于当前上下文导入
        // "module": "./app/third/module.js"
        "Coms": "components/common",
        "ActionTypes$": "utils/action_types.js",
        "Api$": "utils/api.js",
        "Helper$": "utils/helper.js",
        "Ajax$": "utils/ajax.js",
        "BaseLess$":"utils/baseless/baseless.less"
    },
    //代理配置
    proxy: {
        "/": {
            target: "http://test-matrix-v2.yileyoo.com",
            changeOrigin: true
        }
    },
    //mock配置
    mock: {
        //mock目录,使用绝对路径
        mockPath: path.resolve(__dirname, '../mock'),
        //支持设置统一接口后缀,如:.do
        apiExt: ''
    },
    //html模板配置
    template: {
        all:{
            title:'Matrix管理平台'
        },
        development:{
            serverOutput:'<script src="/server/output"></script>'
        },
        production:{
            serverOutput:'<script>window.REDUX_STATE = {!! $jsData !!};</script>'
        }
    },
    theme: path.resolve(src, 'theme/red.less')
}

dist:存放构建结果

dist/
    resource
        index_xxx.html
        app_xxx.js
        vendor_xxx.js
        app
    manifest
        2017-x-x.json

src:源码目录

src/
    ----------------------------------------------------
    actions/                Redux Action目录
        *_action.js
    reducers/               Redux Reducer目录
        *_reducer.js
    store/                  Redux Store目录
        index.js
        store.dev.js
        store.prod.js
    ----------------------------------------------------
    routes/                 React路由目录
        index.js
    ----------------------------------------------------
    containers/             React容器目录
        root/
            index.js
            root.dev.js
            root.prod.js
            devtools.js
    components/             React组件目录
        common/             React公共组件目录(alias:Coms)
        page_1/
            index.js
            *.js
            *.less             
        ...                 React页面组件
        page_n/
    ----------------------------------------------------             
    vendor/                 第三方库目录
        vendor.js
        verdor.js.map
        dll-manifest.json
    static/                 静态资源目录
        favicon.ico         
    utils/                  工具目录
        ajax.js             ajax工具(alias:Ajax)
        api.js              api工具(alias:Api)
        action_types.js     action类型工具(alias:ActionTypes)
        helper.js           常用工具方法(alias:Helper)
        baseless/*.less     常用less方法(alias:BaseLess)
    theme/                  主题目录
        *.less 
    ----------------------------------------------------
    config/                 配置目录
        *_config.js         
    ----------------------------------------------------

mock:存放mock数据的目录

mock/
    *.js
    *.json

public:开发环境临时目录

public/
    index.html                      

npm package:npm包

node_modules                npm包目录
node_shrinkwrap             npm离线包目录

other files:根目录下其他文件

.gitignore                  git忽略配置
.gitlab-ci.yml              gitlab-ci配置
npm-shrinkwrap.json         npm包版本锁定配置
package.json                npm包配置
webpack.config.js           webpack配置入口
README.md                   说明文档

一些重要的概念:
通过querySelector和querySelectorAll来选择选择DOM,传
. # element a[target]
querySelectorAll返回的一个nodeList集合是非实时的结果。
所谓的 JSX 其实就是 JavaScript 对象

UI篇

一些方法:
用ReactDOM代替react
子—>父,props
子—>父,绑定一个回调函数
子->爷,订阅
事件的传递或数据的交互,Redux对这些组件的状态进行管理。
Redux(全局状态):

如何引入ant

  • 使用
    babel-plugin-import(推荐)

// .babelrc or babel-loader option
{
  "plugins": [
    ["import", { libraryName: "antd", style: "css" }] // `style: true` 会加载 less 文件
  ]
}

然后只需从 antd
引入模块即可,无需单独引入样式。等同于下面手动引入的方式。

// babel-plugin-import 会帮助你加载 JS 和 CSS
import { DatePicker } from 'antd';
  1. 不同身份的用户有不同的使用方式(比如普通用户和管理员)
  2. 多个用户之间可以协作
  3. 把交互和UI联系起来
    每个独立的组件、最后整合成一个组件集合
    拆分、组合、嵌套
    手动管理数据和 DOM
    之间的关系会导致代码可维护性变差、容易出错。写一个同一个的开关来改变状态,切记不可手动的操作DOM
    mount,把组件的 DOM 元素插入页面,并且在 setState 的时候更新页面:

如何定制antd

antd通过less变量提供了较灵活的主题定制功能。(参考:修改 Ant Design
的样式变量)

需要修改babel-loader配置:

{
  "plugins": [
    ["import", { 
        libraryName: "antd", 
        style: true // 这里需要修改为`style: true`以实现主题配置
    }]
  ]
}

这里我们做了简单的封装:

1)在src/theme目录建一个主题文件,如:red.less(参考:antd默认主题文件)

@primary-color: #f00;

2)在build/config.js文件配置主题文件的路径

{
    ...
    theme: path.resolve(src, 'theme/red.less')
}

后续我们还将推出主题配置监听多主题切换等功能,敬请期待~

ReactJS庞大的生态系统、自定义渲染器JSX使用Virtual Dom降低DOM渲染
前端框架要考虑什么?

动手写一个antd组件

任意在项目中可复用的组件,都可以通过antd组件组合成一个通用(业务)组件。
注意,这里的组件是Component(见前面的定义)类型。

(演示)

  1. 函数式编程
  2. 模块化
  3. 模块加载器 Webpack
  4. 包管理器 npm
  5. 自动部署/编译/构建流水线,如果一直做重复的事情的话生命是很短暂的。
  6. CSS预处理sass
  7. 构建框架,处理基本的布局和样式,方法论,
  8. 测试工具
  9. 代码质量监控工具 eslint

工具篇

devServer什么鬼

  • 一个node express应用
  • 提供静态资源服务
  • 支持文件监听
  • 支持热加载
  • 支持路由代理
  • 支持接口转发

调用方式非常简单,在命令行执行:

webpack-dev-server --env development --port 3000 --hot --inline --progress --open

webpack中的相关配置:

//开发服务器配置
devServer: {
    //告诉服务器从哪里提供内容。只有在你想要提供静态文件时才需要。
    //devServer.publicPath 将用于确定应该从哪里提供 bundle,并且此选项优先。
    contentBase: [
        conf.contentBase,
        path.join(conf.src, 'static'),
        path.join(conf.src, 'vendor')
    ],
    //信息显示配置
    stats: "normal",
    //是否显示全屏遮罩
    overlay: true,
    //watch配置
    watchOptions: {
        ignored: /node_modules/,
        aggregateTimeout: 300,
        poll: 100
    },
    //联调模式下,使用数据代理
    proxy: isDebug ? conf.proxy : {},
    //开启浏览器历史
    historyApiFallback: true,
    //扩展devServer
    setup(app) {
        //非联调模式下,使用mock数据
        !isDebug && makeMock(app, conf.mock)
    }
}

不容忽视的HtmlWebpackPlugin

  • 自动引用webpack生成的资源,支持过滤
  • 默认支持ejs模板,可以注入变量,语法亲和
  • 社区生态好,一众扩展插件可以满足各种需求(参考)

dllPlugin教程没有教你

教程很多,随便找一篇:怎样令webpack的构建加快十倍、DllPlugin的用法

不实用!!!

get√到打开方式后,我们来针对实际情况做个总结:

  • 区分开发和生产环境
  开发环境 生产环境
警告信息
内容压缩
文件hash
SourceMap 可选
  • 怎么在页面引用

使用add-asset-html-webpack-plugin插件

{
    plugins:[
        ...
        // 在入口页面中引入静态资源
        new AddAssetHtmlPlugin({
            //通过dllManifest读取dll文件名
            filepath: path.resolve(conf.dllPath[NODE_ENV], `${dllManifest.name}.js`)
        })
    ]
}
  • 加一个库就必须手写一下entry不需要!!!

 entry: {
   //读取package.json中的依赖
   vendor: Object.keys(conf.pkg.dependencies)
 }
  • 完整的webpack.dll.config.js

const path = require('path');
const webpack = require('webpack');
const conf = require('./config');

module.exports = function( /*通过命令行参数--env传入*/ NODE_ENV) {
  //是否生产环境
  const isProd = NODE_ENV === 'production';
  //文件名(不带后缀)
  const name = `[name]${isProd?"_[chunkhash:8]":""}`;
  //输出文件路径
  const filePath = conf.dllPath[NODE_ENV];
  //输出manifest路径
  const manifest = conf.dllManifest[NODE_ENV];
  //sourcemap配置
  const devtool = isProd ? '' : 'source-map';
  //插件
  let plugins = [
      new webpack.DllPlugin({
        //解析包路径的上下文,这个要跟接下来配置的 webpack.config.js 一致。
        context: __dirname,
        //manifest.json文件的输出路径,这个文件会用于后续的业务代码打包
        path: manifest,
        //dll暴露的对象名,要跟output.library保持一致
        name: name
      })
    ];
  //生产环境使用压缩版
  if (isProd) {
    plugins = plugins.concat([
      //变量定义
      new webpack.DefinePlugin({
        'process.env.NODE_ENV': JSON.stringify(NODE_ENV)
      }),
      // js压缩配置
      new webpack.optimize.UglifyJsPlugin(conf.UglifyJsOptions)
    ])
  }
  return {
    entry: {
      //读取package.json中的依赖
      vendor: Object.keys(conf.pkg.dependencies)
    },
    output: {
      path: filePath,
      filename: name + '.js',
      //需要与filename保持一致,用于页面引用
      library: name
    },
    devtool,
    plugins
  }
};

扩展阅读:webpack
构建性能优化策略小结
思考:相比其他方案,dllPlugin的优势在哪里?

SourceMap全方案

  • loader中启用SourceMap

{
    loader: 'xxx-loader',
    options: {
        ...
        sourceMap: true
    }
}
  • devtools中配置SourceMap类型

开发环境:唯快不破,最大化满足调试需求

{   
    ... 
    devtool: 'cheap-module-eval-source-map'
}

生产环境:需要考虑安全性和性能

{    
    ...
    devtool: 'source-map'
}

扩展阅读:Webpack devtool source
map

拆分配置文件

webpack.config.common.js       公共配置
webpack.config.dev.js          开发环境配置
webpack.config.prod.js         生产环境配置

拆分原则:

  • module
    resolve在开发和生产环境中的配置差异性相对较小,非常适合抽取到公共配置中
  • entryoutputplugins
    相对来说开发和生产环境有不同的配置,因此放到devprod各自配置中
  • devtooldevServer 等仅出现在开发环境的配置直接放入dev配置中

协同篇

承载页

纯静态 vs 服务端渲染

  • 纯静态:服务端仅提供数据接口,彻底不需要后端维护,缺点是无法做资源回溯和切换
  • 服务端渲染:服务端提供数据接口,并将部分数据或状态渲染到页面,缺点是耦合了前后端部署逻辑

对服务端渲染的改进:

  • 将后端模板指向前端部署目录的html文件,如: index.html
  • 使用固定的后端模板,将数据或状态以JSON对象的方式输出
  • 使用HtmlWebpackPlugin,将后端模板注入到自动生成的页面中

build/config中的配置:

//html模板配置
template: {
    all:{
        title:'Matrix管理平台'
    },
    development:{
        serverOutput:'<script src="/server/output"></script>'
    },
    production:{
        serverOutput:'<script>window.REDUX_STATE = {!! $jsData !!};</script>'
    }
}

webpack中的配置:

{
    plugins:[
     ...
     // 根据模板创建入口页面
     new HtmlWebpackPlugin(Object.assign({
         template: path.resolve(conf.src, 'index.ejs'),
         filename: path.resolve(conf.contentBase, 'index.html')
     }, /*全环境模板配置*/conf.template.all, /*当前环境模板配置*/conf.template[NODE_ENV]))
    ]
}

index.ejs模板中引用

<!DOCTYPE html>
<html>

<head>
    <meta charset="utf-8">
    <title><%= htmlWebpackPlugin.options.title %></title>
    <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
</head>

<body>
    <div id="root" style="height: 100%"></div>
    <%= htmlWebpackPlugin.options.serverOutput %>
</body>

</html>

资源灰度 & 回溯

使用
assets-webpack-plugin插件,在webpack中生成资源映射json文件

{
    plugins:[
        ...
        //生成资源映射表
        new AssetsPlugin({
            path: conf.manifest,
            filename: conf.manifestFileName(),
            processOutput: function (assets) {
              //注入dll依赖信息
              assets.vendor = {
                'js': conf.publicPath + dllManifest.name + '.js'
              };
              return JSON.stringify(assets);
            }
        })
    ]
}

两种方案:

  • 同一个html模板,仅切换资源。需提供资源映射表
  • 不同html模板,切换模板。需要提供模板映射表

数据接口

文档

——接口定义,告诉我们有哪些接口,接口支持哪些http方法,每个接口字段的含义是什么等

(演示)

mock

——接口没有开发完成,前端根据接口文档模拟的数据

(演示)

proxy

——接口已经开发完成,使用代理的方式实现本地接口联调

webpack中的相关配置:

devServer:{
    ...
    proxy: {
      "/api": "http://localhost:3000"
    }
}

权限控制

页面权限

前端:

  • react-router中定义所有页面的路由
  • 页面初始化时,请求后端接口获取菜单权限
  • 仅显示具备权限的菜单

后端:

  • 提供获取菜单权限的接口
  • 将接受到的路由请求作过滤,具备权限的则转向前端页面
  • 将404/500等错误路由转到前端页面

操作权限

前端:

  • 请求后端接口获取操作权限
  • 根据操作权限控制操作按钮是否显示

后端:

  • 提供获取操作权限的接口

相关文章