Create React App Tips


根据官网所介绍,这是一个用于学习 React 的舒服的环境,是创建一个新的单页 React 应用最好的方式。

本地调试 PWA

使用 Create React App 创建的项目,根据 create react app 官方文档:

  1. 只有 production 环境开启了 serviceWorker
  2. 如果需要本地测试离线服务,先用 npm run build 构建,然后从构建好的目录下使用标准的 http server 启动页面

实际上,构建之后在终端里可以看到下文:

The build folder is ready to be deployed.
You may serve it with a static server:
  npm install -g serve
  serve -s build

因为目前前端项目的线上自动化构建,对应的目录名是 dist,所以在项目根目录下运行: serve -s dist

这只是一个服务器,不支持hot reload。

todo

使用自定义模板Custom Templates创建新项目.

npx create-react-app my-app --template [template-name]

在 VS code 里安装 Chrome Debugger Extension,可以在代码里打断点,联动浏览器表现,保持连续的开发流程。

支持的语言功能

package.json 文件里的 browserslist 配置,使得开发时适于现代浏览器(开发时使用新语法,提升开发体验),而生产环境则覆盖最广范围的浏览器。

这个配置并不会自动安装 polyfills。因此使用 ES6+ features,需要自己手动安装合适的 polyfill。

学习、巩固js语法新特性

Creating a Toolchain from Scratch

如果你倾向于自己设置 JS 工具链,官方也给了提示,一个 JavaScript toolchain 通常包含:

  • package manager,包管理工具,如 Yarn、 npm。让你方便第安装和更新,以充分利用强大生态系统里的第三方包
  • bundler 打包工具,如 webpack、Parcel。让你写模块化的代码,并打包成小文件,优化加载时间
  • compiler 编译器,如 Babel,让你能够写现代JS代码,而代码也能在旧浏览器里运行

一篇简单讲解如何让 React app 运行起来的文章 Creating a React App… From Scratch.

eject

H5项目里引入mobX使用decorator,需要配置eslint,要么eject,要么官方推荐fork react-scripts。

Pre-rendering HTML

Pre-Rendering into Static HTML Files 官网说如果你的 build 文件放在一个静态托管服务器上,可使用 react-snapshot 或者 react-snap 为每一个 route 、或者你应用里 relative link 生成 HTML 页面。这些页面在js bundle 加载完成时将无缝地变成 active。

这两个工具前者最后一次更新在 17年11月,64个issue,后者在 19年10月,95个issue。感觉有坑。

预渲染的好处是,无论你的js bundle 是否成功下载,你可以通过 HTML 的 payload 获取每个页面的核心内容,这样也增加了搜索引擎选择你应用每个路由的可能性。

预渲染踩坑记录

采用 react-snapshot,自从项目引入 react-app-rewired,预渲染失效了。

🕷   Starting crawling http://localhost:55340/
🔥 'render' from react-snapshot was never called. Did you replace the call to ReactDOM.render()?
🕸   Finished crawling.

网上搜了一圈没找到解决办法。改用 react-snap 在本地运行是ok了。但是,推到测试环境的 Linux 机器上又不行。。。

Error: Failed to launch chrome!
/var/opt/jenkins/workspace/fe_easyboost_login_develop/node_modules/puppeteer/.local-chromium/linux-686378/chrome-linux/chrome: error while loading shared libraries: libX11-xcb.so.1: cannot open shared object file: No such file or directory

TROUBLESHOOTING: https://github.com/GoogleChrome/puppeteer/blob/master/docs/troubleshooting.md

官方 github issue 里找到相同的问题 Failed to launch chrome! (Ubuntu),运维表示解决不了。

以 react-snapshot 为例,将所有公共可获取的页面做一个静态网页快照,剩下需要 auth 的任何东西保持原样,还是 js 驱动的单页应用。

描述,可以指定额外的 path 作为 entry points 用于crawling(爬取)什么意思?可以生成多页?

对于不简单的 case,作者推荐了 Webpack Static Site Generator Plugin

此外,作者说如果你的应用有更加复杂的 stuff,比如需要 login 后预渲染,那就做 server-side react node server

postcss

想引入plugins,官方不支持,尝试不 eject 的方法。antd 推荐了一个 craco,没例子不会用。看了下 Acknowledgements 里有react-app-rewired,start 数挺多了,很多文章也是基于这个。

另外这个工具配套有React App Rewire PostCSS,用起来简单直接。项目里主要是用 postcss-px-to-viewport 这个插件。

// 参考 front-web 项目
require('postcss-px-to-viewport')({
  viewportWidth: 750, // 视窗的宽度,对应的是我们设计稿的宽度,一般是750
  viewportHeight: 1334, // 视窗的高度,根据750设备的宽度来指定,一般指定1334,也可以不配置
  unitPrecision: 3, // 指定`px`转换为视窗单位值的小数位数(很多时候无法整除)
  viewportUnit: 'vw', // 指定需要转换成的视窗单位,建议使用vw
  selectorBlackList: ['.ignore', '.hairlines'], // 指定不转换为视窗单位的类,可以自定义,可以无限添加,建议定义一至两个通用的类名
  minPixelValue: 1, // 小于或等于`1px`不转换为视窗单位,你也可以设置为你想要的值
  mediaQuery: false, // 允许在媒体查询中转换`px`
})

坑死了。selectorBlackList 文档说支持写正则表达式,实际不生效。我们项目自定义 bt 主题,exclude 文件不起作用。单行注释 ignore 也不生效。

烦死了,为了支持 decorator 语法,网上找到方案要么过时,要么建议再安装一个 customize-cra。

好不容易在 create-react-rewire 文档推荐里找到 react-app-rewire-babel-loader,结果作者说他不维护了。

社区没有统一解决方案,不稳定。

好嘛那就不用装饰器的写法,安那个customize-cra,结果报路径找不到,其他的问题。

引入antd

2020.7.8 国外主流都用 sass,且CRA默认支持 sass-loader,antd 官方只支持less,不提供好的适配方法,让自己 google。

针对不同情况的解决办法:

  • 静态单页面(含少量js交互,使用已封装好的第三方组件),选用 sass,bootstrap 按需引入,抽出颜色、字体变量文件,在组件里 override 样式。使用 react-app-rewired、customize-cra。【Easyboost landing】
  • 复杂单页应用(需要 auth,单独 login 页,含路由),eject【Easyboost】

最新版create react app创建项目后,官方加了一个 <React.StrictMode> 于是 antD 的 button 组件报错

https://github.com/ant-design/ant-design/issues/22493
Using <Button> results in "findDOMNode is deprecated in StrictMode" warning

想抽出 Sider 组件,单独侦听数量变化,结果不行,必现放在 layout 组件里,且影响布局。

Input 组件没有校验,必现内嵌在Form组件里。校验规则设置在 Form.Item 组件上,且必须提供 name(相当于提交字段名,默认会设置为组件 id 的属性值),同时在 Form 组件 initialValues 里提供同名属性及输入框初始值。

清空输入框后显示 placeholder,必须设置 value 为 null。

在 Form 组件上设置唯一name,移除console warning(列表循环内有form,会导致输入组件id重名)。表单名称 会作为表单字段 id 前缀使用

Modal组件 mask 的 z-index 默认是1000,当页面上同时有多个modal,最好按层级关系手动设置的 z-index,否则可能因为 modal 渲染的顺序,导致互相遮挡