react boilerplate设计&&技术栈

为什么需要脚手架?

工作中经常会基于react开发一些项目,出于以下初衷,搭建react boilerplate显然是非常有意义的。

  • 新项目快速搭建环境
  • 保证项目代码结构一致性和规范
  • 工程化的落地与脚本复用
  • 技术栈的调研与选型,使用优质的npm库但不滥用

适用场景

现在还是有很多项目的接口依旧是采用java/php等传统后端语言编写,部署时基本是编译一个前端代码版本,然后把这些静态文件拷贝到java/php等对应的web服务器下。
为什么还是这种陈旧的状况呢?前端开发同学对于后端开发相关的技术积累(数据库、操作系统、网络等)还不够,业务熟悉度也不够,前后端全栈开发还存在一定难度,但相信这只是一个过渡时期。
因此,这个脚手架是基于该应用场景而设计,同时通过express提供web server,方便前后端接口联调测试。
后续会提供一个“前后端同构”、“react+express”的“全栈boilerplate”,方便过渡到“前后端全栈开发”上来。

安装与使用

npm install //安装所有的依赖包
npm run dev //启动开发环境
npm run build //编译一个产品版本的代码
npm start //启动产品环境进行测试

技术栈

react boilerplate中使用到了一些第三方的NPM库,这些库的引入,均是为了满足常见的一些使用场景需求,此处仅对其底层原理或者引入原因进行介绍,具体使用方法参考官方文档即可。

react

react是一个前端视图框架。它可以理解为是MVC中的View。

  • Virtual DOM
    痛点:复杂或者频繁的DOM操作通常是Web开发性能瓶颈。
    react引入了Virtual DOM机制,所有的DOM操作都是通过虚拟DOM进行,每当数据变化时,进行DOM diff,然后仅将需要变化的部分进行实际的浏览器DOM更新。
  • Render
    不再关注某个数据的变化如何更新到一个或多个具体的DOM上,只需要关心:在任意一个数据状态上,整个界面是如何Render的,且不像服务端Render,需要整个页面刷新
  • 组件化
    UI功能模块之间的分离:整个UI通过一个个独立的小组件构成大组件,每个组件只关心自己的逻辑,彼此独立。
    特征:可组合、可重用、可维护、可测试

react-router

react路由,当然,使用路由方便更新导航栏并使用对应的应用页面。更底层的原因是它提供了一套逻辑机制去拆分代码。
学习react-router官方文档了解更多

redux

当前组件间通信形式有:

  1. 嵌套组件间,上层组件向下层组件传递回调函数,下层组件触发回调来更新上层组件的数据。
  2. 以事件的形式,使用发布订阅的方式来通知数据更新。
  3. Flux/Redux
    当项目越来越大的时候,管理数据的事件或回调函数将越来越多,也将越来越不好管理了。
    Redux 是一个用来管理数据状态和 UI 状态的 JavaScript 应用工具。随着 JavaScript 单页应用(Single Page Applications, SPAs)开发日趋复杂,JavaScript 需要管理比任何时候都要多的 state (状态),Redux 被创造用来让 state 的更易于管理。
react boilerplate设计&&技术栈_第1张图片
Free-Converter.com-redux-article-3-03-30585450.jpg

redux更多可以学习:

  • redux官网
  • redux 介绍及配合 react开发
  • redux最佳实践

react-redux

react-redux主要是用来帮助react component与redux的“链接”的高阶组件(HOC)

redux-thunk

redux-thunk 是一个比较流行的 redux 异步 action 中间件,比如 action 中有 setTimeout 或者通过 fetch 通用远程 API 这些场景,那么就应该使用 redux-thunk 了。
redux-thunk 帮助统一了异步和同步 action 的调用方式,把异步过程放在 action 级别解决,对 component 没有影响。

redux-router

暂未引入

isomorphic-fetch

弃用传统的XMLHttpRequest,改用fetch api与后台服务器交换数据(更简单优雅的一套API,在最新版的Firefox和Chrome中已经提供支持)。
isomorphic-fetch为不兼容fetch api的环境提供支持,同时支持nodejs和浏览器环境(前后端同构)

es6-promise

ES6 promise polyfill,部分浏览器环境依旧还不支持Promise

工程化

需求

一个高性能、安全、可用的web网站,前端实践需要考虑:

  • 缓存
  • 压缩与合并
  • 混淆
  • 浏览器兼容
  • 按需加载
  • 首屏加速
  • 语法编译
  • ...

而为了提高开发效率,考虑以下:

  • 开发服务器
  • 热加载和热替换
  • 自动化脚本
  • ...

而这些,很多都依托于工程化落地去实践。

工欲善其事必先利其器

webpack1.x

引用webpack官方的一张示意图:


react boilerplate设计&&技术栈_第2张图片
what-is-webpack
  • 插件
    webpack有丰富的插件接口,可定制化
  • Loaders
    webpack通过loader支持各种文件预处理。允许将不同类型的静态资源进行打包(不仅仅是JavaScript)
  • 代码分块

代码模块在到达浏览器前,应当事先编译打包。存在两种倾向:
1. 一个模块一个请求
2. 所有模块一个请求

以上两种都是次优解,当项目有一定复杂度和规模时,我们考虑分chunk传输。
webpack允许将代码分块,通过确定代码分割点,实现按需加载,加速首屏加载。

  • 开发工具
    webpack提供开发中间件和开发服务器,自动重新加载,并且生成SourceUrls和SoureMaps,方便调试。
  • 性能
    webpack使用异步I/O操作,多级缓存和增量编译机制
  • 支持
    webpack同时支持AMD和CommonJs的模块定义方式。因此支持使用绝大部分的已有库。
  • 优化
    webpack有很多优化手段减少静态文件大小,并且通过生成hash值方便浏览器请求缓存
  • HMR
    在不刷新浏览器的条件下,应用最新的代码更新

webpack配置

下面是webpack开发环境的配置:

/**
 * Created by candice on 17/1/26.
 */
const path = require('path'),
    webpack = require('webpack'),
    HtmlWebpackPlugin = require('html-webpack-plugin'),
    ProgressBarPlugin = require('progress-bar-webpack-plugin');

module.exports = {
    devtool: 'eval-source-map',
    context: path.resolve(__dirname, '..'),
    entry: {
        bundle: [
            'webpack-hot-middleware/client?path=/__webpack_hmr&timeout=20000',
            './client/index',
        ],
        vendor: [
            'react',
            'react-dom',
            'redux',
            'react-redux',
            'es6-promise',
            'isomorphic-fetch'
        ]
    },
    output: {
        path: path.resolve(__dirname, '../build/client'),
        filename: 'js/[name].js',
        chunkFilename: 'js/chunk.[name]-[hash].js',
        publicPath: '/'
    },
    module: {
        loaders: [{
            test: /\.js$/,
            exclude: /node_modules/,
            loader: 'babel',
            query: {
                presets: ['es2015', 'react', 'stage-0', 'react-hmre'],
            }
        }, {
            test: /\.scss$/,
            loaders: [
                'style',
                'css?modules&camelCase&importLoaders=1&localIdentName=[name]__[local]__[hash:base64:8]',
                'sass'
            ]
        }, {
            test: /\.(png|jpg|jpeg|gif|svg|woff|woff2|ttf|eot)/,
            loader: 'url?limit=8000&name=img/[name]-[hash].[ext]'
        },
            {
                test: /\.json$/,
                loader: 'json'
            }, {
                test: /\.html$/,
                loader: 'html?minimize=false'
            }]
    },
    resolve: {extensions: ['', '.js', '.json', '.scss', '.html']},
    plugins: [
        new webpack.optimize.OccurenceOrderPlugin(), // 根据模块调用次数,给模块分配ids,常被调用的ids分配更短的id,使得ids可预测,降低文件大小,该模块推荐使用
        new webpack.optimize.DedupePlugin(), //打包的时候删除重复或者相似的文件
        new webpack.optimize.CommonsChunkPlugin({
            names: ['vendor'],
            filename: 'js/[name].js'
        }),
        new webpack.HotModuleReplacementPlugin(),  //热替换
        new webpack.NoErrorsPlugin(),  //报错但不退出webpack进程
        new webpack.DefinePlugin({'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV)}), //定义变量
        new HtmlWebpackPlugin({                       //生成html
            filename: './index.html',
            template: './client/index.html',
            favicon: './client/common/assets/favicon.ico',
        }),
        new ProgressBarPlugin({summary: false})
    ],
};

loader介绍

  • babel-loader:处理JS文件的加载,通过preset完成es2015和JSX到JS的文件转换
  • css-loader:处理css中路径引用等问题
  • css-loader?modules通过modules查询参数启用css-module。
    css-module意义主要在于:局部作用域和模块依赖
  • style-loader:动态把样式写入css
  • sass-loader: sass编译器
  • url-loader:处理图片
  • html-loader:处理html文件

plugin介绍

  • OccurenceOrderPlugin:webpack为每个模块指定唯一的id,通过该插件,webpack会分析和为模块按优先级排序,为最经常使用的分配一个最小的ID
  • DedupePlugin:打包的时候删除重复或者相似的文件
  • CommonsChunkPlugin:处理公共模块
  • UglifyJsPlugin:JS混淆处理
  • HotModuleReplacementPlugin: 配置代码自动编译和热替换插件

目录结构

/build/ compile输出
       /client 前端代码compile输出
       /server 服务端代码compile输出

/client/     前端目录
     /common/ 公共代码
             /actions/   redux actions
             /assets/    公共静态资源
             /components/   公共木偶组件
             /containers/   公共智能组件
             /reducers/     redux reducers
             /sass/         公共样式和公共组件样式
             /store/        redux store
             /util/         工具类与函数
             /config/       配置相关
     /module_a/ a模块
             /components/
             /containers/
             /sass/
     /module_b/ b模块
             /components/   木偶组件
             /containers/   智能组件
             /sass/         样式
     /index.html   入口html文件
     /index.js     入口js文件
     /routes.js    路由文件
/server/  服务端目录,用来mock服务端接口联调测试
        /routes/  控制层:api服务路由
        /app.dev.js    开发环境下的app.js
        /app.prod.js   产品环境下的app.js
     
     
/node_modules/ 第三方库
/tools/
       /webpack.config.dev.js  开发环境下的webpack配置
       /webpack.config.prod.js 产品环境下的webpack配置
/.babelrc     babel配置文件
/package.json  
/readme.md    说明文档

附上:react boilerplate源码

你可能感兴趣的:(react boilerplate设计&&技术栈)