@ozo/react-rock

React 移动端开发脚手架,基于CRA3,通用、开箱即用。

Usage no npm install needed!

<script type="module">
  import ozoReactRock from 'https://cdn.skypack.dev/@ozo/react-rock';
</script>

README

[TOC]

React 模板工程

本模板工程是通用工程,支持前端开发和中后台开发。

基于 create-react-app v3(简称 cra3)创建,整合了 react router 等基础组件,旨在作为基础工程以便能快速衍生其他复杂工程模板。

本文档部分内容来自官方文档create-react-app 项目地址,详情参考 中文文档, 英文文档

技术特性

该工程的主要技术特性如下:

  • SCSS / CSS Modules 样式处理(不熟悉的同学,先学习下:)
  • 公共 SCSS mixins 支持
  • 基于 fetch 数据请求
  • 支持 mobx 状态管理*
  • 支持 Fusion Design 平台,UI 和前端协同*
  • 支持公共主题可配置
  • Eslint / Stylelint / Prettier 代码检查
  • Markdownlint 规范 详情 规则
  • 代码提交日志规范
  • 支持装饰器 @ @babel/plugin-proposal-decorators
  • 支持可选链运算符 ?. @babel/plugin-proposal-optional-chaining
  • 支持空位合并运算符 ?? @babel/plugin-proposal-nullish-coalescing-operator

更多特性,赶快体验!

CRA3 升级的特性,可以参考 releases[https://github.com/facebook/create-react-app/releases/tag/v3.0.1], 英文文档中文文档

CRA2 升级的特性,可以参考英文文档中文文档

项目规范

文件结构

├── .vscode/          			 # vscode相关
│   └── launch.json  		  	 # 存放调试配置,如Debugger for Chrome调试配置等
├── build/          		  	 # 构建目录,构建后创建
│
├── doc/            		  	 # 文档目录,存放项目相关文档
├── node_modules/   		  	 # node依赖模块,安装组件后自动创建
├── public/         		  	 # 静态文件
│   ├── favicon.ico 		  	 # H5 icon,浏览器地址栏图标
│   ├── ie.html  		       	 # ie及低版本浏览器兼容提示
│   ├── index.html  		  	 # 应用入口页模板,如果要引入第三方JS可以放在这个目录*
│   ├── logo*.png  		     	 # Web App应用图标,默认包括1x和3x两种尺寸
│   ├── manifest.json		  	 # Web App配置文件
│   └── robots.txt		    	 # robots协议配置文件
│
├── src/             		  	 # 项目root
│   ├── mock/           		 # mock目录,根据项目需要创建
│   ├── api/         		  	 # 项目api相关
│   	├── Agent.js    	  	 # 接口请求处理逻辑,默认采用fetch
│   	├── ApiUrl.js   	  	 # 接口请求api地址注册
│   	├── ResponseCode.js	     # 错误码定义
│   	└── index.js      		 # 接口的统一export
│
│   ├── assets/      		  	 # 公共静态资源(组件除外),如图片/字体/json等,文件名一律小写
│   	├── font/      		  	 # 公共字体
│   	├── img/      		  	 # 公共图片,应当按模块分文件夹存放
│   	└── index.js    	  	 # 公共资源的统一export
│
│   ├── components/	       	 # 组件集合,用于存放与业务无关的(展示型组件)、可复用的组件
│   	├── xxx/      		  	 # xxx组件
│   		├── components/   	 # 组件独有的子组件,目录结构与父级一致
│   		├── img/      	  	 # 组件的图片目录
│   		├── xxx.jsx	      	 # 组件的jsx文件
│   		├── xxx.scss    	 # 组件的scss文件,按需选择
│   		├── xxx.module.scss* # 组件的scss文件,开启css-modules,按需选择
│   		├── xxx.mdx	  	  	 # 组件的说明文档(功能复杂组件可选)
│   	  	└── index.js 	     # 组件的export
│   	└── index.js    	  	 # 所有组件的统一export
│
│   ├── constants/     		  	 # 常量目录(可选)
      └── index.js	  	  	 # 常量的统一export

│   ├── layouts/     		  	 # 项目布局集合,用于路由分层
│   	├── xxxLayout/  	  	 # xxx布局组件
│   		├── components/   	 # 布局独有的子组件,目录结构与通用组件一致
│   		├── style/    	     # 布局主题scss文件
│   		├── xxx.jsx	      	 # 组件的jsx文件
│   		├── xxx.scss      	 # 组件的scss文件
│   		├── xxx.module.scss* # 组件的scss文件,开启css-modules
│       ├── menuConfig.js 		 # 菜单配置(顶部导航/侧边导航/底部导航等)
│   	  └── index.js 	    	 # 布局的export
│   	└── index.js    	  	 # 布局的统一export
│
│   ├── modules/    		  	 # 业务组件集合(目录结构与layouts一致)
│   	├── xxx/  		  	  	 # 各模块目录
│   	└── index.js	  	  	 # 容器组件相关的统一export
│
│   ├── pages/      		  	 # 页面级组件,用于组合modules/layouts等,目录结构=通用组件
│   	├── xxx/  			  	 # 各页面目录
│   	└── index.js      		 # 页面的统一export
│
│   ├── stores/      		  	 # 数据store相关,与mobx等库配合
│   	├── Store.js    	 	 # 数据层的基础类
│   	├── xxxStore.js  	  	 # 各业务store,需要继承Store基类
│   	└── index.js	  	  	 # store相关的统一export
│
│   ├── utils/      		  	 # 辅助工具集合,项目通用方法、函数等
│   	├── xxx.js  	 	   	 # 各辅助工具
│   	├── polyfill.js    		 # 浏览器补丁相关
│   	└── index.js	  	  	 # 辅助工具类的统一export
│
│   ├── settings.scss			 # 项目scss变量定义,用于重置基础变量
│   ├── App.js      		  	 # 应用入口组件
│   ├── App.css / .scss*
│   ├── App.test.js
│   ├── index.js    		  	 # React入口js
│   ├── index.css / .scss
│   ├── router.js		 	   	 # 全局路由处理逻辑
│   ├── routerConfig.js 		 # 全局路由配置
│   ├── serviceWorker.js
│   ├── setupProxy.js 			 # 全局代理配置
│   └── vendorConfig.js 		 # 用于配置第三方库splitting的范围
│
├── tests/          		  	 # 存放测试用例
├── .babelrc.js			         # babel 自定义配置文件
├── .commitlintrc.js	    	 # 提交日志规范相关
├── .editorconfig       		 # 编辑器配置文件
├── .env		       	      	 # 环境变量配置文件,公共变量配置
├── .env-cmdrc.test.js  		 # 环境变量测试文件
├── .env-cmdrc.js      			 # 环境变量配置文件,不同环境的变量配置
├── .eslintignore     			 # eslint 忽略配置,类似 .gitignore
├── .eslintrc.js       			 # eslint 配置文件
├── .gitattributes     		     # 指定由 git 使用的文件和路径的属性
├── .gitignore          	     # git 提交忽略配置文件
├── .lintmdrc           	     # markdownlint 配置文件
├── .lintstagedrc.js    	     # lint-staged 配置文件
├── .npmignore          	     # npm 提交忽略配置文件
├── .nvmrc             		     # 配置项目所使用的 node 版本(采用nvm管理node版本)
├── .prettierignore     		 # prettier 忽略配置,类似 .gitignore
├── .prettierrc.js   	  		 # prettier 配置文件
├── .stylelintignore	  		 # stylelint 忽略配置,类似 .gitignore
├── .stylelintrc.js			     # stylelint 配置文件
├── .yarnrc              	     # yarn 配置文件
├── config-overrides.js			 # 在不eject的情况下,扩展webpack配置
├── jsconfig.json        	     # 指定根文件和js语言服务提供的功能选项
├── package.json		      	 # 包含项目的基本信息、项目的依赖以及项目的相关执行命令等
├── package-lock.json     	     # npm 依赖包版本lock
├── README.md				     # 描述此项目的功能、特点、API 等信息
├── server.js       	  		 # 本地构建服务器
├── server.test.js  	  		 # 本地开发测试服务器
└── yarn.lock            	     # yarn 依赖包版本lock

以上结构是项目的推荐结构;带有 * 的文件为可选。

以上未提及的文件夹或文件,不用关注。 以上各目录中的统一 export 不包括第三方组件,且未使用的组件应避免在此导出。

命名规范

详情参见项目级规范

组件分类

规范中将组件划分为通用组件和业务组件两大类。

通用组件(复用级别:框架级)

通用组件也叫展示型组件,与具体业务解耦,只负责接收指定格式的数据进行 UI 展示。可在大多数项目中通用。约定存放在**src/components**目录中。

为便于沉淀通用组件库,并提高其可维护性。约定将通用组件划分以下 4 类:

  • basis:基础型组件,构成网页的基本元素。例如图标、按钮等;
  • layout:布局型组件,用于组织页面布局,例如网格系统、两侧留白、水平留白等;
  • block:区块/模块型组件,具有独立的功能,低于页面级的组件,例如支持筛选和分页的表格,可以嵌套;
  • template:模板型组件,可重用的复杂 UI 结构,一般为页面级组件,例如支付成功页等。

业务组件(复用级别:项目级)

业务组件是指与项目紧密相关的组件,一般会捆绑具体的数据或状态,也叫容器型组件。分为以下 3 类:

  • modules(src/modules:功能组件,用于归类项目开发中,无法沉淀为框架级的、但项目内可复用的功能块,一般由数据或状态 + 通用组件组成。例如购物车模块、用户登录等。

  • pages (src/pages:页面组件,用于归类按页面流划分的页面组件,一般由项目级 modules + **通用组件(布局类组件等)**组成。

  • layouts(src/layouts:结构组件,主要用于对整个项目的页面结构做归类,抽出公共的页面级容器组件。例如可定义:

    - MainLayout:用于一级页面,带有一级导航、标题栏、底部导航等。
    - BaseLayout:用于二级页面,如商品列表、商品详情等。
    - BlankLayout:什么都不带,100%高的容器,用于404 等特殊页面布局等。
    
    当然,也可以根据业务需求划分,如 GoodDetailLayout 商品详情模块、UserLayout 登录/注册/忘记密码等。其原则是可重用,便于组织页面。
    

开发须知

  • 推荐通过各类目录下的 index.js 统一 export。便于对该目录下的资源或组件进行统一注册、替换和添加描述备注等,提高可维护性。
  • 通过@、@/components、@components 等别名来引入组件。
  • 开发前先根据页面梳理组件,并对组件分级;做好 store 划分,提取公共数据处理逻辑。
  • 尽量做到页面均由布局组件+ 通用组件/项目级功能组件组成,不含原子标签(div、span 等)。

依赖环境

  • node 8+
  • babel 7
  • webpack 4
  • React 16+
  • ES6+
  • node-sass 4+
  • jest + react-testing-library

安装

默认使用 yarn,npm 可能无法正常安装 node-sass。若yarn安装node-sass失败,可通过cnpm单独安装node-sass。

> yarn

命令行

  • yarn start/npm start 启动开发环境,会自动在浏览器打开 http://localhost:3000,支持热更新。
  • yarn build 生产环境打包
  • yarn test 进行测试
  • yarn commit 命令行提交,类型选择
  • yarn version changlog 及版本管理

推荐编辑器 Visual Studio Code,如果出现 vscode 占用系统资源 100%的情况,请检查是否安装了 SCSS InterliSense 、IntelliSense for CSS class names in HTML 插件,若存在,请关闭这类插件。****

开发相关

修改入口页标题

如果要修改网页标题,请修改 package.json 的 title 字段;或者修改 public/index.html 中的标签内容。 还可替换 favicon.ico 为自己的 ico。 manifest.json 中的信息也一并修改。</p> <h3><a id="" class="anchor" aria-hidden="true" href="#"></a>使用全局别名</h3> <p>已定义以下全局别名:<code>@</code>代表src目录、<code>@theme</code>代表当前项目配置的主题(在package.json中配置);</p> <pre><code class="language-js">// package.json { "buildConfig": { "theme": { "alifd": "@alifd/theme-xxx" } }, } </code></pre> <blockquote> <p>使用别名,scss 名称@import 时需要写完整,文件名中的_ 和 .scss 后缀名不能少。 使用第三方库的 css 时,可以通过<code>~</code>引入或写全<code>node_modules</code>的路径。</p> </blockquote> <h3><a id="" class="anchor" aria-hidden="true" href="#"></a>组件的异步加载</h3> <p>默认情况下,webpack 会将引用到的包都打包到同一个 JS 文件中,入口 js 文件体积可能会很大。通过按需加载,可以使之变小。方法引入:</p> <pre><code class="language-js">import { lazy } from '@ozo/lazy-loader'; const Login = lazy(() => import('./UserLogin')); <Route path='/Login' component={Login}/> </code></pre> <blockquote> <p>更多用法可查看<a href="https://www.npmjs.com/package/@ozo/lazy-loader"> <code>@ozo/lazy-loader</code>的使用说明</a>。</p> </blockquote> <h3><a id="import" class="anchor" aria-hidden="true" href="#import"></a>组件Import顺序</h3> <p>统一编写习惯,方便团队成员形成统一的“表达“,减轻代码阅读负担。推荐顺序为:</p> <ul> <li>通用基础库:prop-types、classnames、lodash-es等</li> <li>react基础库:react、react-dom、react-router-dom等</li> <li>mobx、redux基础库:mobx、mobx-react等</li> <li>第三方组件库:@alifd/next等,库附带的样式文件跟随其后</li> <li>项目级组件:@/components/xxx</li> <li>页面级组件:./components/xxx</li> <li>项目级工具类:@/utils/xxx</li> <li>页面样式文件:css、scss文件,注意引入顺序,按影响程度引入,影响最直接的放在最后</li> <li>图片、json等静态资源,比较多时可考虑单独的文件集中导入/导出管理</li> </ul> <blockquote> <p>webpack生产打包时,scss的顺序是按照代码执行的顺序,谁先import就先打包谁。</p> </blockquote> <h3><a id="" class="anchor" aria-hidden="true" href="#"></a>设计与开发协同</h3> <p>详情参见<a href="https://zhuanlan.zhihu.com/p/158206021">UI 设计与前端协同</a>。</p> <h3><a id="css" class="anchor" aria-hidden="true" href="#css"></a>CSS 样式编写</h3> <h5><a id="scss" class="anchor" aria-hidden="true" href="#scss"></a>定义 SCSS 变量</h5> <p>项目开发中,对于在主题包之外的公共特性,如颜色、字号等,统一定义到<code>src/settings.scss</code>文件中,以便于后期维护和管理。注意命名规范和分组。</p> <pre><code class="language-scss">// ./src/settings.scss $modal-color: #f33; // 组件的xxx.scss @import '@/settings'; //引入路径根据组件scss文件位置进行修正 .content { color: $modal-color; } </code></pre> <h5><a id="scss-mixins" class="anchor" aria-hidden="true" href="#scss-mixins"></a>使用 SCSS mixins</h5> <p>脚手架默认引入了一些常用的 mixins,使用方法参考:https://github.com/inier/mixins。</p> <pre><code class="language-scss">@import '@/settings'; //引入路径根据组件scss文件位置进行修正 /*-------- 极细边框 --------*/ // 上、右、下、左边框 .border-t { @include onepx-scale(#eee, top, after, 2px); } .border-r { @include onepx-scale(#eee, right, after, 2px); } </code></pre> <p>此外,也可以在 <code>@/settings.scss</code> 文件中自定义 mixins。</p> <h5><a id="css-module" class="anchor" aria-hidden="true" href="#css-module"></a>不开启 CSS-Module</h5> <p>css 样式可以选择是否开启 CSS-Module 功能,先介绍不开启的方式。</p> <p>第 1 步:样式文件命名为 xxx.scss;</p> <pre><code class="language-scss">.content { padding: 10px; .logo { width: 40px; } } </code></pre> <p>第 2 步:在 jsx 中引入时使用<code>import './xxx.scss';</code></p> <pre><code class="language-js">import './xxx.scss'; ... <main className="content"> <div className="logo"></div> </main> </code></pre> <blockquote> <p>未开启 CSS-Module 功能,将需要注意避免各组件间的样式冲突,推荐 BEM 命名规范,用法自行搜索。</p> </blockquote> <h5><a id="css-module" class="anchor" aria-hidden="true" href="#css-module"></a>开启 CSS-Module 功能</h5> <p>第 1 步:样式文件命名为 xxx.module.scss;</p> <pre><code class="language-scss">.content { padding: 10px; .logo { width: 40px; } } </code></pre> <p>第 2 步:在 jsx 中引入时使用 <code>import styles from './xxx.module.scss';</code></p> <pre><code class="language-js">... import styles from './xxx.module.scss'; ... <main className={styles.content}> <div className={styles.logo}></div> </main> </code></pre> <blockquote> <p>开启 CSS-Module 功能后,将不在支持直接用引号引入该文件的样式;</p> <p>如果要使用全局样式,请在样式文件中使用 :global,并在引用时,使用字符串而不是变量应用。</p> </blockquote> <p>样式继承:开启 CSS-Module 功能后,样式继承请使用<a href="https://github.com/css-modules/css-modules#dependencies">如下方法</a>。</p> <blockquote> <p>如果由于某种原因需要禁用 Autoprefixer,请 <a href="https://github.com/postcss/autoprefixer#disabling">按照本节进行操作</a> 。</p> <p>默认情况下 禁用了 <a href="https://www.html.cn/archives/8510">CSS Grid(网格) 布局</a> 前缀,但不会删除手动前缀。 如果你想选择加入 CSS Grid(网格) 前缀,请先 <a href="https://github.com/postcss/autoprefixer#does-autoprefixer-polyfill-grid-layout-for-ie">熟悉一下它的局限性</a>。 要启用 CSS Grid(网格) 前缀,请将 <code>/* autoprefixer grid: on */</code> 添加到 CSS 文件的顶部。</p> </blockquote> <h3><a id="" class="anchor" aria-hidden="true" href="#"></a>使用字体图标</h3> <h5><a id="" class="anchor" aria-hidden="true" href="#"></a>引入在线字体图标</h5> <p>推荐使用<a href="http://www.iconfont.cn">阿里巴巴 iconfont</a>库来管理项目的图标。</p> <p>上传好图标后,在网站上生成在线链接(font class),复制该链接,使用它替换掉<code>.env</code>文件中的<code>REACT_APP_ICONFONT_URL</code>字段:</p> <pre><code class="language-plain"># REACT_APP_ICONFONT_URL="//at.alicdn.com/t/font_xxx_xxx.css" </code></pre> <p>然后修改<code>public/index.html</code>即可。</p> <pre><code class="language-html"><!-- <link rel="stylesheet" href="%REACT_APP_ICONFONT_URL%"> --> 变为 <link rel="stylesheet" href="%REACT_APP_ICONFONT_URL%" /> </code></pre> <blockquote> <p>本地引入方式:[仅自建 CDN 的情况下使用]。在<a href="http://www.iconfont.cn">阿里巴巴 iconfont</a>中上传图标,然后在网站上生成在线链接(font class),访问该链接并复制其中的内容。在<code>public</code>目录中新建<code>iconfont.css</code>,将刚复制的内容粘贴到该文件中,然后在<code>public/index.html</code>目录中引入该链接即可。</p> </blockquote> <pre><code class="language-html"><link rel="stylesheet" href="./iconfont.css" /> </code></pre> <blockquote> <p>这种方式需要注意 cdn 缓存问题,建议在 CDN 规则中不缓存该文件的图标。对于频繁更新的情况,可以采用其他手段将其 hash 化。</p> </blockquote> <h5><a id="" class="anchor" aria-hidden="true" href="#"></a>引入本地字体图标文件</h5> <p>对于本地化字体文件,可将该资源放入到<code>src/assets</code>目录中,然后在<code>src/index.scss</code>中引入其样式文件即可。</p> <blockquote> <p>这种情况下,本地字体图标文件,一般会被完整打包到 js 中,也可通过打包手段分离出来。</p> </blockquote> <h5><a id="" class="anchor" aria-hidden="true" href="#"></a>平台型协同方式的字体图标(推荐)</h5> <p>采用平台型协同方式时,可在 fusion 平台统一管理字体图标(同样依赖 iconfont.cn 库)。不用单独引入 iconfont.css。</p> <h3><a id="" class="anchor" aria-hidden="true" href="#"></a>引入图片等资源</h3> <p>为了减小 Http 的请求数目,在打包时 webpack 会将小于 10k 的图片直接转换成 base64 字符串放在 html 中。 <b>目前只支持 bmp,gif,jpg,jpeg,png</b></p> <p>写法如下:</p> <pre><code class="language-js">import React from 'react'; import logo from './logo.png'; // Tell Webpack this JS file uses this image console.log(logo); // /logo.84287d09.png function Header() { // Import result is the URL of your image return <img src={logo} alt="Logo" />; } export default Header; </code></pre> <pre><code class="language-css">.Logo { background-image: url(./logo.png); } </code></pre> <h3><a id="api" class="anchor" aria-hidden="true" href="#api"></a>配置API调用接口</h3> <p>在本地开发时,前端调用的接口都是跨域的,需要进行代理。将相对路径配<code>./src/api/ApiUrl.js</code>中即可。</p> <pre><code>// ./src/api/ApiUrl.js const urls = { ... POST_LOGIN: '/main/login', GET_RESPONSE_CODE: '/resc/list' ... } </code></pre> <p>API接口命名采用全大写字母,下划线拼接,建议以对应的提交方式<code>GET</code>和<code>POST</code>等冠名,以便直观的显示。</p> <h3><a id="" class="anchor" aria-hidden="true" href="#"></a>配置开发环境代理</h3> <p>在<code>src/setupProxy.js</code>中参照一下配置:</p> <pre><code class="language-js">module.exports = function (app) { app.use( '/api', createProxyMiddleware({ target: 'http://localhost', changeOrigin: true, pathRewrite: { '^/api': '', }, }) ); ... }; </code></pre> <blockquote> <p>具体代理规则,请先到接口通用处理逻辑中根据自己接口返回结果的格式情况,进行修改。</p> </blockquote> <p>这样配置后所有带有<code>/api</code>的接口请求都会被代理到<code>http://localhost</code>。具体用法请参考<a href="https://github.com/chimurai/http-proxy-middleware"><code>http-proxy-middleware</code>组件的官方用法</a>。</p> <h3><a id="mobx" class="anchor" aria-hidden="true" href="#mobx"></a>mobx 开发相关</h3> <p>优先使用最新版本的mobx5,该版本采用 Proxy 对象,部分机型不支持。对兼容性有要求的可以降低到mobx3、或mobx4(支持 es5)。详情请参考<a href="https://cn.mobx.js.org/">mobx 开发手册</a>。</p> <h5><a id="mobx" class="anchor" aria-hidden="true" href="#mobx"></a>mobx 开启严格模式</h5> <p>mobx 开启严格模式,必须使用@action 来修改数据</p> <pre><code class="language-js">// mobx5,匹配mobx-react6.x, //https://cn.mobx.js.org/refguide/api.html + https://blog.csdn.net/smk108/article/details/83185745 configure({ enforceActions: 'observed', }); // mobx4,匹配mobx-react5.x configure({ enforceActions: true, }); // mobx3及以下,匹配mobx-react4.x useStrict(true); </code></pre> <blockquote> <p>注意与之搭配的mobx-react库。</p> </blockquote> <h3><a id="sourcemap" class="anchor" aria-hidden="true" href="#sourcemap"></a>开启/关闭 sourcemap</h3> <p>cra 通过 GENERATE_SOURCEMAP 来控制 sourcemap 的开启和关闭,在.env-cmdrc.js 文件中对应的环境下,增加<code>"GENERATE_SOURCEMAP": false</code>, false 为关闭 sourcemap,true 为开启 sourcemap。</p> <pre><code class="language-js">{ "development": { "REACT_APP_HMR": false }, "production": { "GENERATE_SOURCEMAP": false, "BUNDLE_VISUALIZE": true }, "test": { }, "uat": { "PORT": 8080 } } </code></pre> <h3><a id="pwa" class="anchor" aria-hidden="true" href="#pwa"></a>启用 PWA 特性</h3> <p>CRA 支持 workbox,可以一键开启 PWA(Progressive Web App)。在<code>src/index.js</code> 文件中有以下代码:</p> <pre><code class="language-js">serviceWorker.unregister(); </code></pre> <p>如果要使用 CRA 提供的 PWA 特性的话,我们需要将<code>serviceWorker.unregister()</code> 改为<code>serviceWorker.register()</code>。打包项目后,在<code>build</code>文件夹下有以下几个文件:</p> <ul> <li>asset-manifest.json // 存放本次打包后资源的路径及 hash,用于区分版本</li> <li>server-worker.js // 规定了资源缓存策略</li> <li>preche-manifest.xxxxxxxxx.js // 静态资源版本记录</li> <li>manifest.json // Web 应用程序清单,可以配置在系统桌面上的图标等,参考<a href="https://developer.mozilla.org/zh-CN/docs/Web/Manifest">文档</a></li> </ul> <blockquote> <p>在 src 文件目录下有一个 serviceWorker.js 文件,用于检查环境变量是否为“production”,且当前浏览器是否兼容 service worker。</p> </blockquote> <h3><a id="" class="anchor" aria-hidden="true" href="#"></a>代码检查</h3> <p>本工程中采用的检查工具包括:</p> <ul> <li><a href="./doc/ESlint+Prettier配置.md"><b>ESLint</b></a>:用于检查 js 的逻辑错误;</li> <li><a href="./doc/ESlint+Prettier配置.md"><b>Prettier</b></a>:用于格式化 js 的格式;</li> <li><a href="./doc/Stylelint配置.md"><b>Stylelint</b></a>:用于检查css、scss等样式的语法和书写等。</li> </ul> <h5><a id="eslint" class="anchor" aria-hidden="true" href="#eslint"></a>ESLint 禁用检查</h5> <p><a href="http://eslint.cn/docs/user-guide/configuring#disabling-rules-with-inline-comments">http://eslint.cn/docs/user-guide/configuring#disabling-rules-with-inline-comments</a></p> <h5><a id="stylelint" class="anchor" aria-hidden="true" href="#stylelint"></a>Stylelint 禁用检查</h5> <p>跟 eslint 类似,通过 <code>stylelint-disable</code> 注释来局部禁用某一项规则。通过 <code>stylelint-enable</code> 可以把之前忽略的规则重新开启。一定要注意,只 enable 对应的规则,形成呼应:</p> <pre><code class="language-html"><style> .classA { /* stylelint-disable declaration-block-no-duplicate-properties */ transition-property: transform; transition-property: transform, -webkit-transform; /* stylelint-enable declaration-block-no-duplicate-properties */ } </style> </code></pre> <h3><a id="" class="anchor" aria-hidden="true" href="#"></a>低版本浏览器兼容</h3> <p>详情参见<a href="doc/低版本浏览器兼容.md">低版本浏览器兼容</a>。</p> <h2><a id="" class="anchor" aria-hidden="true" href="#"></a>本地调试</h2> <h4><a id="vscode" class="anchor" aria-hidden="true" href="#vscode"></a>使用 VSCode 调试</h4> <p>本工程可以使用 VSCode 进行调试。但需要先安装这个<a href="https://marketplace.visualstudio.com/items?itemName=msjsdiag.debugger-for-chrome">Debugger for Chrome</a></p> <h2><a id="" class="anchor" aria-hidden="true" href="#"></a>测试相关(待更新)</h2> <h3><a id="" class="anchor" aria-hidden="true" href="#"></a>单元测试</h3> <p>测试:<code>yarn test</code> 或者 <code>npm test</code>,详情请参考<a href="https://facebook.github.io/create-react-app/docs/running-tests">create-react-app 官方文档</a>。</p> <blockquote> <p>集成测试/功能测试/性能测试/渲染测试 @testing-library/react 测试React Component的库 @testing-library/react-hooks 测试自己写的的React Hooks的库 @testing-library/jest-dom 提供更多利于dom测试的断言</p> </blockquote> <h2><a id="" class="anchor" aria-hidden="true" href="#"></a>代码提交</h2> <h3><a id="" class="anchor" aria-hidden="true" href="#"></a>提交时自动格式化</h3> <blockquote> <p>只有使用 Git 作为代码服务器时有效</p> </blockquote> <p>使用以下插件 husky lint-staged prettier 实现在提交代码时,自动进行格式化 To format our code whenever we make a commit in git, we need to install the following dependencies:</p> <h3><a id="" class="anchor" aria-hidden="true" href="#"></a>规范提交记录</h3> <p>使用一个规范的提交记录是很有必要的,这不仅让多人开发中的参与者能更好地了解项目的迭代历史和进程,也能在出现问题时快速定位,找到问题代码的提交记录。</p> <p>在提交代码时,应遵守以下规范:</p> <ul> <li><p>修改的文件如果涉及多个板块,应单独先提交。</p> </li> <li><p>规范提交信息格式:<type>(<scope>): <subject> ,具体参考<a href="doc/提交日志规范.md">提交记录规范指南</a>。例如:</p> </li> </ul> <pre><code class="language-plain"> fix(发票信息页面):修改返回字段。 feat(SingleInput组件):扩展xxx功能,增加size属性用于设置输入框高度,默认为md [44px],目前支持lg [54px] chore: 新增scss支持(支持 scss 并兼容css-modules) </code></pre> <h3><a id="" class="anchor" aria-hidden="true" href="#"></a>自动生成更新说明(待更新)</h3> <p>此外,还可以使用工具根据提交记录自动生成更新说明 (CHANGELOG),免去手动更新的痛苦,也方便用户了解每次更新的具体内容。具体参考<a href="doc/分支及版本发布规范.md">更新说明规范指南</a>。</p> <h2><a id="" class="anchor" aria-hidden="true" href="#"></a>构建发布</h2> <ul> <li><p>构建:<code>yarn build</code>或<code>npm run build</code>,App 构建出发布的文件到 <code>build</code> 目录。</p> </li> <li><p>发布:将 build 目录下的文件发布到对应node服务器上即可;该环节推荐通过搭建 CI/CD 平台来自动完成。</p> </li> </ul> <h2><a id="code-review" class="anchor" aria-hidden="true" href="#code-review"></a>Code Review</h2> <p>CodeReview 的目的是提升代码质量,尽早发现潜在缺陷与 BUG,降低修复成本,同时促进团队内部知识共享,帮助更多人更好地理解系统,这也是帮助新人成长最快的方式之一。详情参考<a href="doc/CodeReview规范.md">CodeReview 规范</a>。</p> <p>参考文章:</p> <p><a href="https://www.zhihu.com/question/41089988?sort=created">https://www.zhihu.com/question/41089988?sort=created</a></p> <p><a href="https://blog.csdn.net/uxyheaven/article/details/49773619">https://blog.csdn.net/uxyheaven/article/details/49773619</a></p> <p><a href="http://www.cnblogs.com/cnblogsfans/p/5075073.html">http://www.cnblogs.com/cnblogsfans/p/5075073.html</a></p> <h2><a id="" class="anchor" aria-hidden="true" href="#"></a>进阶配置</h2> <h3><a id="" class="anchor" aria-hidden="true" href="#"></a>国际化</h3> <p>项目的国际化,根据场景主要分为组件国际化、日期国际化、内容国际化。</p> <ul> <li><p><b>组件国际化</b></p> <p>很多 UI 框架或组件自身已提供国际化方案,可以参考使用,如<a href="https://fusion.design/component/doc/107">Fusion Design UI</a>。</p> </li> </ul> <ul> <li><p><b>日期国际化</b></p> <p>对于日期来说,可以借助 <a href="https://github.com/moment/moment">moment</a> 库,其自带国际化相关能力。目前社区比较主流的解决方案有以下两种:</p> <p>方法一:</p> <pre><code class="language-js">const webpack = require('webpack'); module.exports = { // ... plugins: [ // 打包指定需要的语言文件 new webpack.ContextReplacementPlugin(/moment[\/\\]locale$/, /zh-cn|ja/), ], }; </code></pre> <p>方法二:</p> <pre><code class="language-js">const webpack = require('webpack'); module.exports = { // ... plugins: [ // 只打包有过引用的语言文件,应用中需要添加如:`import 'moment/locale/zh-cn';` // new webpack.IgnorePlugin(/^\.\/locale$/, /moment$/) ], }; </code></pre> </li> </ul> <ul> <li><p><b>内容国际化</b></p> <p>主流的内容国际化方案有:</p> <p><a href="https://github.com/nefe/kiwi">kiwi</a> [有配套的 vscode 工具,持续关注]</p> <p><a href="https://github.com/yahoo/react-intl">react-intl</a> [yahoo]</p> <p><a href="https://github.com/alibaba/react-intl-universal">react-intl-universal</a> [alibaba]</p> <p><a href="https://react.i18next.com/">react-i18next</a> [i18next.js]</p> <p><a href="https://github.com/ProtoTeam/i18n-pick">i18n-pick</a> [蚂蚁金服团队]</p> <p><a href="https://juejin.im/post/5c24a09d5188252a9412fabf">react-i18n</a> [腾讯 webnovel 团队,暂未开源]</p> </li> </ul> <h3><a id="webpack" class="anchor" aria-hidden="true" href="#webpack"></a>自定义 webpack 配置</h3> <p>本脚手架采用了 react-script,自定义 webpack 的配置有两种方式:</p> <ul> <li>**eject:**该方式可获得 webpack 的完全控制权,具体用法参见[<a href="http://www.geekjc.com/post/5b74e06ac827d41a704bac62(http://www.geekjc.com/post/5b74e06ac827d41a704bac62)">http://www.geekjc.com/post/5b74e06ac827d41a704bac62(http://www.geekjc.com/post/5b74e06ac827d41a704bac62)</a></li> <li>**不 eject:**推荐方式,引入<code>react-app-rewired</code>和<code>customize-cra</code>插件,具体用法请参见: <a href="https://github.com/timarney/react-app-rewired"><a href="https://github.com/timarney/react-app-rewired">https://github.com/timarney/react-app-rewired</a></a> / <a href="https://github.com/arackaf/customize-cra">https://github.com/arackaf/customize-cra</a></li> </ul> <h3><a id="" class="anchor" aria-hidden="true" href="#"></a>添加自定义的环境变量</h3> <p>你可以在工程设置环境变量,默认的环境变量有 <code>NODE_ENV</code>,它的值有<code>development</code> / <code>production</code> / <code>test</code> 分别对应运行的命令行<code>yarn start</code> / <code>yarn build</code> / <code>yarn test</code>。</p> <blockquote> <p>环境变量的值会在打包阶段被动态的替换掉; 要在 React 的环境下生效,自定义的环境变量必须以 <code>REACT_APP_</code> 开头; 不以 <code>REACT_APP_</code>开头的自定义环境变量,只会在后续执行的 nodejs 脚本中生效,而不会置入到 React 的运营环境中。例如 <code>BUNDLE_VISUALIZE</code>,只能用于开启脚手架中的<code>webpack-bundle-analyzer</code>。</p> </blockquote> <h4><a id="" class="anchor" aria-hidden="true" href="#"></a>设置环境变量</h4> <p>环境变量有以下几种设置方式:</p> <h5><a id="env-cmd-rc" class="anchor" aria-hidden="true" href="#env-cmd-rc"></a>env-cmd 的 rc 文件集中管理(推荐)</h5> <p>使用<a href="https://github.com/toddbluhm/env-cmd">env-cmd</a>工具可以方便的对文件进行管理。</p> <ol> <li><p>安装 env-cmd</p> </li> <li><p>在根目录新建**.env-cmdrc.js**文件,用于自定义不同环境的环境变量,这里配置的变量会覆盖<code>.env.local</code>文件中的对应变量,内容类似:</p> <pre><code class="language-js">{ "development": { }, "test": { }, "production": { "BUNDLE_VISUALIZE": "1" }, "h5": { "PORT": 8080 } } </code></pre> </li> <li><p>在 package.json 中注册脚本命令,根据自己的需要指定环境,多个环境可以共用,用<code>,</code>分隔:</p> <pre><code class="language-js">"scripts": { "start": "env-cmd development,h5 react-app-rewired start", "build": "env-cmd production react-app-rewired build", "test": "env-cmd test react-app-rewired test", ... } </code></pre> </li> </ol> <blockquote> <p>如果需要自定义通用环境变量,可在根目录新建**.env.local**文件,内容类似:</p> </blockquote> <pre><code class="language-plain"># NODE_ENV=development # PORT=3000 # API_SERVER=192.168.0.100 # API_PORT=9000 # 应用名称 REACT_APP_TITLE=toxic # 应用版本 REACT_APP_VERSION=1.0 </code></pre> <h5><a id="" class="anchor" aria-hidden="true" href="#"></a>文件内定义</h5> <p>可以在项目根目录下新建如下的文件(不同命令,会读取不同的文件)</p> <ul> <li><code>.env: 默认使用</code></li> <li><code>.env.local:用于本地变量覆盖,这个文件会在除了test环境的所有环境加载</code></li> <li><code>.env.development,.env.test,.env.production:在对应的环境加载</code></li> <li><code>.env.development.local,.env.test.local,.env.production.local:在对应的环境加载,最高优先级,会覆盖.env.*的配置</code></li> </ul> <p>加载的优先级从高到低,依次为:</p> <ul> <li><code>npm start</code>: <code>.env.development.local</code>, <code>.env.development</code>, <code>.env.local</code>, <code>.env</code></li> <li><code>npm run build</code>: <code>.env.production.local</code>, <code>.env.production</code>, <code>.env.local</code>, <code>.env</code></li> <li><code>npm test</code>: <code>.env.test.local</code>, <code>.env.test</code>, <code>.env</code> (注意没有 <code>.env.local</code>)</li> </ul> <h5><a id="" class="anchor" aria-hidden="true" href="#"></a>命令行直接设置</h5> <p>环境变量还可以在运行命令行的时候直接设置</p> <ul> <li>Windows(cmd.ext): <code>set REACT_APP_SECRET_CODE=123&&npm start</code></li> <li>Mac: <code>REACT_APP_SECRET_CODE=123 npm start</code></li> </ul> <h4><a id="" class="anchor" aria-hidden="true" href="#"></a>使用环境变量</h4> <p>jsx 中使用:</p> <pre><code class="language-jsx">render() { return ( <div> <small>You are running this application in <b>{process.env.NODE_ENV}</b> mode.</small> <form> <input type="hidden" defaultValue={process.env.REACT_APP_SECRET_CODE} /> </form> </div> ); } </code></pre> <p>js 中使用:</p> <pre><code class="language-js">if (process.env.NODE_ENV !== 'production') { analytics.disable(); } </code></pre> <p>html 中使用:</p> <pre><code class="language-html"><title>%REACT_APP_WEBSITE_NAME%</title> </code></pre> <h3><a id="https" class="anchor" aria-hidden="true" href="#https"></a>在开发中使用 https</h3> <h5><a id="" class="anchor" aria-hidden="true" href="#"></a>通过环境变量设置</h5> <pre><code>module.exports = { development: { ... // 在开发环境中使用 HTTPS, 默认未开启 HTTPS: true, }, ... } </code></pre> <h5><a id="windows-cmd.exe" class="anchor" aria-hidden="true" href="#windows-cmd.exe"></a>Windows (cmd.exe)</h5> <pre><code class="language-cmd">set HTTPS=true&&npm start </code></pre> <p>(Note: the lack of whitespace is intentional.)</p> <h5><a id="linux-macos-bash" class="anchor" aria-hidden="true" href="#linux-macos-bash"></a>Linux, macOS (Bash)</h5> <pre><code class="language-bash">HTTPS=true npm start </code></pre> <h3><a id="js" class="anchor" aria-hidden="true" href="#js"></a>应用第三方 JS</h3> <h5><a id="node" class="anchor" aria-hidden="true" href="#node"></a>node 模块引用</h5> <p>使用 npm 安装后,直接在 js 文件中 import 即可。</p> <h5><a id="js" class="anchor" aria-hidden="true" href="#js"></a>单个 JS 文件引用</h5> <p>如果文件符合 AMD/CMD 规范可以直接 import,如果不符合请在 public/index.html 中引入</p> <h3><a id="" class="anchor" aria-hidden="true" href="#"></a>推荐库</h3> <p>详情请见<a href="doc/推荐库.md">推荐库</a>。</p> <h2><a id="" class="anchor" aria-hidden="true" href="#"></a>附录</h2> <h3><a id="" class="anchor" aria-hidden="true" href="#"></a>开发规范</h3> <p>关于工程目录介绍和代码规范等。</p> <p><a href="./doc/前端开发规范.md">前端开发规范</a></p> <h3><a id="bug" class="anchor" aria-hidden="true" href="#bug"></a>bug 记录</h3> <p>记录各种 bug。</p> <p><a href="./doc/bug记录.md">bug 记录</a></p> <h3><a id="" class="anchor" aria-hidden="true" href="#"></a>踩坑日记</h3> <p>存放各种坑及填坑方法。</p> <p><a href="./doc/踩坑日记.md">踩坑日记</a></p> </div></article> <aside><h2 class="svelte-1u3txz5">Details</h2> <dl class="details f-d1 svelte-1u3txz5"><div class="svelte-1u3txz5"><dt class="svelte-1u3txz5">Downloads (weekly)</dt> <dd class="f-mono f-h1"><div class="container svelte-a3j687"><div class="dot svelte-a3j687"></div> <div class="dot svelte-a3j687"></div> <div class="dot svelte-a3j687"></div> </div></dd> </div><div class="svelte-1u3txz5"><dt class="svelte-1u3txz5">Updated</dt> <dd><time class="" datetime="2020-10-09T13:11:55.578Z">October 9, 2020</time></dd> </div><div class="svelte-1u3txz5"><dt class="svelte-1u3txz5">Created</dt> <dd><time class="" datetime="2019-04-04T09:53:43.653Z">April 4, 2019</time></dd> </div><div class="svelte-1u3txz5"><div class="wrapper svelte-qjxoui"><dt class="header svelte-qjxoui"><span class="title svelte-qjxoui">Package score <a class="ml1 f-w400" href="https://docs.skypack.dev/package-authors/package-checks" target="_blank">learn more</a></span> <span class="f-u1"> <div class="container svelte-a3j687"><div class="dot svelte-a3j687"></div> <div class="dot svelte-a3j687"></div> <div class="dot svelte-a3j687"></div> </div></span></dt> <dd class="pt1"><ul class="checks"><li class="checks-check svelte-qjxoui"><span class="status__loading svelte-qjxoui" aria-label="loading"></span>Package Security </li><li class="checks-check svelte-qjxoui"><span class="status__warn svelte-qjxoui" aria-label="not added yet"></span> ES Module Entrypoint <a class="action svelte-qjxoui" href="https://docs.skypack.dev/package-authors/package-checks#esm" target="_blank" rel="noopener noreferrer">Info</a> </li><li class="checks-check svelte-qjxoui"><span class="status__warn svelte-qjxoui" aria-label="not added yet"></span> Export Map <a class="action svelte-qjxoui" href="https://docs.skypack.dev/package-authors/package-checks#export-map" target="_blank" rel="noopener noreferrer">Info</a> </li><li class="checks-check svelte-qjxoui"><svg class="status__check svelte-qjxoui" fill="none" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 13 9"><title>added Keywords

  • added License
  • added README
  • added Repository URL
  • TypeScript Types Info
  • License
    MIT
    Dependencies
    16
    Links
    Keywords
    Collaborators