盒子
盒子
文章目录
  1. create-react-app使用笔记
    1. 可运行的脚本
    2. 自动格式化代码
    3. 在Visual Studio Code中Debugger
    4. 自定义环境变量
    5. 能否使用修饰器
    6. 开发环境中转发API请求
    7. 启动HTTPS
    8. 在单独的环境中(隔离)开发组件
    9. 默认支持渐进式Web应用
    10. 客户端路由
    11. 打包到相对路径

create-react-app使用笔记

create-react-app使用笔记

官方脚手架功能强大,各个需求点也是考虑到了,是开发react应用的神器。

###如何使用

create-react-app依赖两个包,一个是create-react-app全局命令工具包,用来创建新的项目,就是create-react-app myProject命令;第二个是react-scripts在生成的项目中依赖的包。一般不用升级create-react-app,因为主要的react依赖都是由react-scripts来生成的,而生成的react-scripts会自动下载最新 版,所以你用的react包也是最新版本的。

###create-react-app生成的项目结构

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
.
├── README.md
├── node_modules
├── package.json
├── public
│   ├── favicon.ico
│   ├── index.html
│   └── manifest.json
├── src
│   ├── App.css
│   ├── App.js
│   ├── App.test.js
│   ├── index.css
│   ├── index.js
│   ├── logo.svg
│   └── registerServiceWorker.js
└── yarn.lock

项目中必须存在的文件:

  • public/index.html html模版文件
  • src/index.js react应用的入口文件

可以在src目录下新建N多个子集目录,只有在src下的资源,才能被webpack处理,所以一般都将js和css资源放入src目录下,图片资源也可以放src里面,

官方demo则将svg资源放入了src中。

可运行的脚本

  • npm start运行开发运行,默认会打开http://localhost:3000的浏览界,可以热更新代码
  • npm test运行测试脚本
  • npm run build打包命令,会启用react的生产环境模式,去除类型检查等,压缩代码
  • npm run eject暴露出默认配置文件

###支持最新的JavaScript新功能和Polyfills

该项目支持最新的JavaScript标准的超集。除了es6的语法,create-react-app还支持:

  • 指数运算符
  • Async/await语法(ES2017)
  • 对象的解构赋值
  • 动态import 语法
  • 类静态属性
  • JSX语法和flow语法

另外官方仅仅包含了很少一个部分的ES6 polyfills:

所以当用到一些需要polyfills的功能时,某些polyfills需要手动添加

###改变html的title

找到public/index.html直接修改title即可,如果是单页应用,则在每个component的componentDidMount的生命周期方法中,调用document.title来修改。你也可以参考React Helmet

###导入组件

支持commonjs模块语法,当然最好使用import 和 export 语法

###代码分割

当某些代码片段需要异步加载的时候特别有用,用法如下:

chart.js

1
2
3
const initChart = () => { // do something... };
export { initChart };

App.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import React, { Component } from 'react';
class App extends Component {
click = () => {
import('./chart.js')
.then(({ initChart }) => {
// 使用 initChart() ;
})
.catch(err => {
// 错误处理
});
};
render() {
return (
<div>
<button onClick={this.click}>加载图表</button>
</div>
);
}
}
export default App;

也可以使用async/await语法来使用这个特性:

App.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import React, { Component } from 'react';
class App extends Component {
click = async () => {
let { initChart } = await import( './chart' ).catch( e=>console.warn(e) ) ;
initChart() ;
} ;
render() {
return (
<div>
<button onClick={this.click}>加载图表</button>
</div>
);
}
}
export default App;

比用上面的语法简单清晰很多。

###添加样式表

create-react-app已经内置了配置好了的webpack,可以将css当作js资源一样引入到js文件中。

Button.css

1
.Button { color: red ; }

Button.js

1
2
3
4
5
6
7
8
9
import React, { Component } from 'react';
import './Button.css'; // 引入css资源
class Button extends Component {
render() {
// 使用
return <div className="Button" />;
}
}

在开发环境中,修改css文件,可以热更新;生产环境中,则所有css文件会被打包进一个.css文件中,通过link标签注入到public/index.html中。这种方式,增加了迁移到其他打包工具的成本,不过对于打包工具仅仅是webpack来说很方便。

另外create-react-app集成了插件Autoprefixer,可以自动帮你补全浏览器前缀。

###添加图像、字体、文件

引入一个文件,是告诉webpack把,这个文件引入到打包的bundle中,不像import css文件,引入一个文件,webpack会自动转化为一个字符串,如,src的url地址,href的超链接地址。

比如图片的话,如果大小小雨10,000字节,则会返回一个data URI的字符串,如果大于的话,则返回相对于%PUBLIC_URL%的url地址。目前create-react-app支持bmp,gif,jpg,jpeg,png。

1
2
3
4
5
6
7
8
import React from 'react';
import logo from './logo.png'; // 引入logo png资源
console.log(logo); // 字符串"/logo.84287d09.png"
function Header() {
// 设置src等于logo
return <img src={logo} alt="Logo" />;
}
export default Header;

webpack会根据资源的内容动态生成hash,如果以后图片有小修改,就不用加版本号了,清除缓存很方便。

###正确使用public文件夹

public/index.html里面的内容可以随意修改,添加或者删除script标签等。

create-react-app鼓励使用import 语法来引入 样式、图片、字体文件,因为有如下好处:

  • 一起打包可以减少网络请求
  • 编译过程中的错误,可以预防上线出现的404错误
  • 根据内容自动生成hash,可以预防浏览器缓存

如果将静态资源放入public文件夹中,它不会被webpack处理,仅仅打包之后,会被拷贝到build目录中。为了引用到这个资源,你需要使用一个叫PUBLIC_URL的变量。在index.html中,有如下代码:

1
<link rel="shortcut icon" href="%PUBLIC_URL%/favicon.ico">

只有在public中的文件,才可以用%PUBLIC_URL%获取。如果资源在src或者node_modules里面,你需要拷贝到public目录中去使用。

当我们使用yarn build的时候,%PUBLIC_URL%会被绝对路径替换,就是网站的静态资源根目录。

在JavaScript代码中,也可以通过process.env.PUBLIC_URL来访问,不过官方不推荐使用。

1
2
3
render() {
return <img src={process.env.PUBLIC_URL + '/img/logo.png'} />;
}

需要注意的是:

  • public里的文件不会被预处理,和压缩
  • 丢失文件,会导致404
  • 当文件改变时,需要手动重命名,或者手动添加版本号,来处理缓存问题。

什么时候使用public文件夹

  • 需要在构建输出中具有特定名称的文件,比如manifest.webmanifest
  • 有N多图片,动态引入的图片
  • 某个js文件不想引入到bundle中
  • 一些第三方库和webpack不兼容

###如何使用全局变量

当在js代码中引入第三方的全局变量时,linter会提示,没有定义过的变量,怎么解决?

1
const $ = window.$

or

1
$.extend( {} , {a:1} ) ; // eslint-disable-line

不检测当行代码

自动格式化代码

prettier是一个独立的(opinionated)代码格式化工具。用它,可以确保在一个工程里有统一的代码风格。使用方法:

1
npm install --save husky lint-staged prettier

或者( 通过yarn安装有坑,下面会讲解 )

1
yarn add husky lint-staged prettier
  • husky监听hithooks的事件,然后执行自定义的命令
  • lint-staged允许我们在git中已经暂存的文件里,执行脚本命令
  • prettier在commit之前,格式化我们的代码

修改package.json文件:

1
2
3
4
"scripts": {
+ "precommit": "lint-staged",
"start": "react-scripts start",
"build": "react-scripts build",
1
2
3
4
5
6
7
8
9
10
"dependencies": {
// ...
},
+ "lint-staged": {
+ "src/**/*.{js,jsx,json,css}": [
+ "prettier --single-quote --write",
+ "git add"
+ ]
+ },
"scripts": {

现在,当我们git commit -m "..."执行的时候,Prettier会自动格式化已经修改过的文件,然后提交。

当然,我们也可以通过./node_modules/.bin/prettier --single-quote --write "src/**/*.{js,jsx}"来格式化整个工程。

通过yarn安装之后,可能会遇到git commit之后没有任何反应的坑,google之后,发现how to setting up?

情况一样,原来通过yarn安装的husky,默认不会执行husky的安装程序。所以解决方案就是手动执行一下安装程序。

1
node node_modules/husky/bin/install.js

看到done,就说明设置git的钩子成功了

手动执行husky的安装程序

在Visual Studio Code中Debugger

首先需要安装最新的VS Code和 VS Code Chrome Debugger Extension

之后在项目根目录下新建.vscode文件夹,在里面新建launch.json,将如下代码放入其中:

1
2
3
4
5
6
7
8
9
10
11
12
13
{
"version": "0.2.0",
"configurations": [{
"name": "Chrome",
"type": "chrome",
"request": "launch",
"url": "http://localhost:3000",
"webRoot": "${workspaceRoot}/src",
"sourceMapPathOverrides": {
"webpack:///src/*": "${webRoot}/*"
}
}]
}

注意⚠️:如果自定义修改了HOST或者PORT,则需要修改相应的地址

配置好了之后,启动yarn start,在VS Code中按F5或者按绿色的debug按钮进行debug。

自定义环境变量

环境变量,可以很方便的,根据某些条件,展示不同的数据,比如(根据环境,判断是否需要mock数据);或者使用一些不在版本控制力的敏感信息;因为是在构建期间运行,所以webpack可以直接进行一些逻辑的判断,不会出现的代码直接会删除,不会进入打包文件。

在项目工程中,可以使用自定义的环境变量,就像声明在js文件的普通变量一样。默认的,内置了一个NODE_ENV环境变量,其他的环境变量,规定必须要以REACT_APP_开头,以防止和其他环境变量冲突。

环境变量可以只能在构建期间使用,不能在生产环境中动态使用。如果需要动态获取的话,需要服务器端支持。

环境变量是定义在process.env对象上的,比如,定义了一个REACT_APP_SECRET_CODE变量,需要在js文件中使用的话,需要用process.env.REACT_APP_SECRET_CODE来获取。

要获取当前的开发环境,使用:

1
process.env.NODE_ENV
  • npm start 启动的话,这个值永远为development
  • npm test启动的话,这个值永远为test
  • npm run build启动的话,这个值永远为production

NODE_ENV这个环境变量,不允许手动修改,即使修改了也不会生效。

js中使用

1
2
3
if (process.env.NODE_ENV !== 'production') {
analytics.disable();
}

public/index.html中使用:

1
<title>%REACT_APP_WEBSITE_NAME%</title>

注意⚠️:

  • 除了NODE_ENV和PUBLIC_URL连个环境变量,其他环境变量都需要由REACTAPP开头。
  • 环境变量只有在构建期间有效,运行期间无效。

有两种方式定义环境变量:

  1. shell命令

    • windows: set REACT_APP_SECRET_CODE=abcdef&&npm start
    • Linux,maxOs:REACT_APP_SECRET_CODE=abcdef npm start

    这种方式,环境变量只有在shell回话中有效

  2. .env文件

    为了永久的使用环境变量,需要在根目录中新建一个.env文件

    .env:

    1
    REACT_APP_SECRET_CODE=abcdef

    .env文件可以添加进版本控制中( .gitignore中配置.env*.local )。

    还有一些其他的文件:

    • .env:默认
    • .env.local:本地覆盖,这个在除了test构建,其他所有构建中都有效
    • .env.development.env.test.env.production:指定构建环境中有效
    • .env.development.local, .env.test.local, .env.production.local:本地覆盖指定构建环境

    这些定义的优先级( 越靠近左边的,优先级越高 ):

    • npm start: .env.development.local, .env.development, .env.local, .env
    • npm run build: .env.production.local, .env.production, .env.local, .env
    • npm test: .env.test.local, .env.test, .env (注意⚠️:没有 .env.local )

能否使用修饰器

不能。

  • 这是一个试验性的建议,可能会改变。
  • 目前的规格版本没有得到Babel官方的支持。
  • 如果规范发生变化,将无法编写重构件codemod,因为Facebook内部使用它们。

如果需要使用,可以使用npm run eject自己用第三方工具配置

开发环境中转发API请求

一般生产环境的项目都有如下特征:

1
2
3
/ - 静态服务,返回index.ftl
/todos - 静态服务,返回index.ftl
/api/todos - 服务器拦截 /api/* 开头的请求,后端执行业务逻辑后返回

为了告诉开发服务器,如何重定向一个未知的接口请求,需要在package.json中添加proxy字段,比如:

1
"proxy":"http://locahost:8080"

当我们发起请求,比如fetch('/api/todos'),开发服务器首先确认,当前不是一个静态资源,之后会转发这个请求到http://localhost:8080/api/todos,开发服务器只会尝试转发Accept头部不是text/html的请求。

转发请求可以避免跨域请求失败:

Fetch API cannot load http://localhost:8080/api/todos. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:3000' is therefore not allowed access. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.

可以扩展proxy

  • 自定义代理请求

    • 修改package.json

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      {
      // ...
      "proxy": {
      "/api": {
      "target": "<url>",
      "ws": true
      // ...
      }
      }
      // ...
      }

      所有的/api开头的请求都会被代理,包括头部Accepttext/html的请求,和默认的配置proxy不一样。

    • 1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      {
      // ...
      "proxy": {
      // 代理以 /api 开头的请求
      "/api": {
      "target": "<url_1>",
      "ws": true
      // ...
      },
      // 代理以 /foo 开头的请求
      "/foo": {
      "target": "<url_2>",
      "ssl": true,
      "pathRewrite": { // 接口重写
      "^/foo": "/foo/beta"
      }
      // ...
      },
      // 代理 /bar/abc.html 而不是 /bar/sub/def.html
      "/bar/[^/]*[.]html": {
      "target": "<url_3>",
      // ...
      },
      // 代理 /baz/abc.html 和 /baz/sub/def.html
      "/baz/.*/.*[.]html": {
      "target": "<url_4>"
      // ...
      }
      }
      // ...
      }
  • 支持WebSocket的代理

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    {
    // ...
    "proxy": {
    "/socket": {
    // 代理的目标websocket服务器
    "target": "ws://<socket_url>",
    // 标记这是webSocket请求
    "ws": true
    // ...
    }
    }
    // ...
    }

启动HTTPS

  • Windows:set HTTPS=true&&npm start
  • Linux,macOS:HTTPS=true npm start

在单独的环境中(隔离)开发组件

通常,在一个应用程序中,你有很多的UI组件,而且每个组件都有很多不同的状态。 例如,一个简单的按钮组件可能具有以下状态:

  • 正常的状态下,仅展示文本标签。
  • 有禁用的模式
  • 有一个loading状态

通常,如果不单独跑各个状态的组件,很难一次性看到这些状态。

create-react-app不包含这些开发工具,需要使用第三方插件,来实现同时查看一个组件的所有状态。工具有:

  • Storybook for React (source)

    首先,全局安装@storybook/cli:

    1
    npm install -g @storybook/cli

    之后,在根目录执行:

    1
    getstorybook

    之后会自动安装以来:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    ➜ testReact git:(master) ✗ getstorybook
    getstorybook - the simplest way to add a storybook to your project.
    • Detecting project type. ✓
    • Adding storybook support to your "Create React App" based project. ✓
    • Preparing to install dependencies. ✓
    yarn install v1.2.1
    [1/4] 🔍 Resolving packages...
    [2/4] 🚚 Fetching packages...
    [3/4] 🔗 Linking dependencies...
    ....
    ✨ Done in 21.32s.
    • Installing dependencies. ✓
    To run your storybook, type:
    yarn run storybook
    For more information visit: https://storybook.js.org

    提示你可以通过yarn run storybook来启动storybook

  • React Styleguidist (source)

这些工具可以单独部署,这样子团队中的其他人就可以直接查看组件的各个状态,而不需要启动服务器。

默认支持渐进式Web应用

create-react-app创建的项目默认就会支持 [渐进式web应用(PWA)] ,会使用 service workers 实现 缓存优先策略 来优化用户再次访问应用的速度。什么是service workers?

service-worker

from serviceWorker

当然,你也可以通过设置默认不开启这个特性,但是如果你在开发新的应用,推荐使用,特别在移动端Android设备上,能加速Web App的启动。

已缓存的项目,如果想禁用service-worker,可以直接调用unregister

1
import { unregister } from './registerServiceWorker';

客户端路由

如果客户端使用的是HTML5的pushState history API,许多静态资源文件请求将会失败。比如,请求页面/todos/42,开发服务器会运行很好,但是生产环境将会失败。因为后台程序并没有配置/todos/42这个路由,会返回404。

NODE的解决方案:

1
2
3
4
// app.get( '/api/*' , ()=>{ // .... } )
app.get('/*', function (req, res) {
res.sendFile(path.join(__dirname, 'build', 'index.html'));
});

打包到相对路径

默认的create-react-app会讲打包的默认路径设置为服务器的根目录/

要覆盖默认的设置,需要在package.json中,设置homepage

1
"homepage": "http://kf.netease.com/index",

设置之后,create-react-app就知道了项目的根目录是:/index

之后生成的html文件:

1
2
3
<link rel="shortcut icon" href="/index/favicon.ico">
<link href="/index/static/css/main.6cfcf8f6.css" rel="stylesheet">
<script src="/index/static/js/main.4dc8f75a.js"></script>
支持一下
扫一扫,支持lcoder