如何开发由Create-React-App 引导的应用(二)

此文章是翻译How to develop apps bootstrapped with Create React App 官方文档

系列文章

  1. 如何开发由Create-React-App 引导的应用
  2. 如何开发由Create-React-App 引导的应用(一)
  3. 如何开发由Create-React-App 引导的应用(三)
  4. 如何开发由Create-React-App 引导的应用(四)

Importing a Component

此项目设置支持ES5 模块,多亏了Babel。
虽然你仍然可以使用require()module.exports,我们建议你改用import and export

例如:

Button.js

import React, { Component } from 'react';

class Button extends Component {
  render(){
    //...
  }
}

export default Button; // Don't forget to use export default!

DangerButton.js

import React, { Component } from 'react';
import Button from './Button'; // Import a component from another file

class DangerButton extends Component {
  render(){
    return <Button color="red" />;
  }
}

export default class DangerButton;

注意默认导出和命名导出的区别。这是常见的错误来源。

我们建议你在模块仅导出单个(例如,一个组件)时,坚持使用默认导入和导出。当你使用export default Buttonimport Button from './Button' 时,就会得到你想要的。

命名导出对导出多个功能的实用模块很有用。一个模块最多可能有一个默认的导出和任意数量的命名导出。

了解有关ES 模块的更多内容:

Adding a Stylesheet

此项目设置使用Webpack 管理所有资源。Webpack 提供了一种定制方式,将导入概念扩展“extending”到JavaScript 之外。为了表示一个JavaScript 文件依赖一个CSS 文件,你需要将CSS 导入JavaScript 文件。

Button.css

.Button {
  padding: 20px;
}

Button.js

import React, { Component } from 'react';
import './Button.css'; // Tell Webpack that Button.js uses these styles

class Button extends Component {
  render(){
    // You can use them as regular CSS styles
    return <div className="Button" />
  }
}

对于React 这并不是必需的,但是许多人发现这个特性很方便。你可以在这里阅读这种方法的好处。但是,您应该意识到,这使得你的代码更适合Webpack而不是他构建工具和环境。

在开发中,使用这种方式表达依赖,可以在编辑样式使立即重新加载样式。在生产中,所有的CSS 文件将被连接到构建输出中的一个最小化的.css 文件中。

如果你关系使用Webpack-specific 语法,你可以将你所有的CSS 放到src/index.css。它将从src/index.js 导入,但是如你之后迁移到一个不同的构建工具,你可以移除这个导入。

Post-Processing CSS

此项目设置可以减少你的CSS ,并通过Autoprefixer 自动添加厂商前缀,因此你不需要担心。

例如,它:

.App {
  display: flex;
  flex-direction: row;
  align-items: center;
}

变成这样:

.App {
  display: -webkit-box;
  display: -ms-flexbox;
  display: flex;
  -webkit-box-orient: horizontal;
  -webkit-box-direction: normal;
      -ms-flex-direction: row;
          flex-direction: row;
  -webkit-box-align: center;
      -ms-flex-align: center;
          align-items: center;
}

如果你因为某些原因需要禁用自动添加前缀功能,参考这里

Adding a CSS Preprocessor (Sass, Less etc.)

通常,我们建议你不要在不同的组件直接重复使用相同的CSS 类。例如,我们建议你创建一个具有自己的.Button 样式的<Button> 组件,而不是在<AcceptButton><RejectButton>中使用.Button CSS 类,这样<AcceptButton><RejectButton> 都能渲染(而不是继承)。

遵循这条规则往往使CSS 预处理器不太有用,因为像混合和嵌套之类的功能被组件组合所替代。但是,如果你发现它有价值,你可以集成CSS 预处理器。在这个指导中,我们将使用Sass,但是你也可以使用Less 或其他方式。

首先,安装Sass 命令行接口:

npm install node-sass --save-dev

然后在package.json 中添加如下内容到scripts

  "scripts": {
    "build-css": "node-sass src/ -o src/",
    "watch-css": "npm run build-css && node-sass src/ -o src/ --watch --recursive",
    ...
  }

注意:使用不同的预处理器,需要根据预处理器的文档替换build-csswatch-css 命令。

现在,你可以将src/App.css 重命名为src/App.scss,然后运行npm run watch-css。watcher 将会查找src 子目录下的所有Sass 文件,并且在它旁边创建相应的CSS 文件,我们这里例子会重写src/App.css。由于src/App.js 仍然导入src/App.css,这个样式成为你的应用的一部分。现在你可以编写src/App.scsssrc/App.css 将会被重新生成。

在Sass 文件中共享变量,你可以使用Sass 导入功能。例如,src/App.scss 和其他组件样式文件可以包括@import "./shared.scss"中的变量定义。

此时你可能想移除源文件控制中所有的CSS 文件,添加src/**/*.css 到你的.gitignore 文件中。 保留构建产品在源代码控制之外是一个很好的做法。

最后,你可能发现在运行npm start 时自动运行watch-css,并将build-css 作为npm run build 的一部分是非常方便的。你可以使用&& 操作符去顺序地执行这两个脚本。但是,没有跨平台地并行运行两个脚本,所以我们需要为此安装一个包:

npm install --save-dev npm-run-all

然后我们在startbuild 两个脚本包含CSS 预处理命令:

 "scripts": {
   "start-js": "react-script start",
   "start": "npm-run-all -p watch-css start.js",
   "build": "npm run build-css && react-scripts build"
 }

现在运行npm startnpm run build 也会构建Sass 文件。注意node-sass 似乎有一个issue recognizing newely created files on some systems,所以你可能需要重启watcher,当你新建一个文件,直到这个问题被解决。

Adding Images, Fonts, and Files

使用Webpack,使用静态资源像图像和字体的方式同CSS 类似

你可以在JavaScript 文件中直接import文件。这告诉Webpack 在包中包括该文件。不像CSS 导入,导入一个文件给你一个字符串值。这个值是你在代码中可以引用的最终路径,例如:作为一个图片的src 属性或一个链接到PDF 的href

为了减少请求服务器的次数,导入的图像如果小于10,000 byte 会返回一个data URI 而不是一个路径。这适用于以下文件扩展名:bmp、gif、jpg、jpeg 和png。由于#1153 SVG 文件除外。

这有一个例子:

import React from 'react';
import logo from './logo.png'; // Tell Webpack this JS file uses this image

console.log(logo); // logo.84288709.png

function Header(){
  // Import result is the URL of your image
  return <img src={logo} alt="logo" />;
}

export default Header;

这确保当项目构建后,Webpack 将正确的移动图像到build 文件夹,并且提供会一个正确的路径。

在CSS 中也是一样的:

.Logo {
  background-image: url(./logo.png)
}

Webpack 在CSS 中查找所有相对的模块引用(它们以./ 开始)然后使用已编译包中的最终路径来替换它们。如果你输入错误或意外删除一个重要文件,则会出现编译错误,就像当你引入一个不存在的JavaScript 模块那样。编译包中最终文件名由Webpack 根据内容哈希生成。如果将来文件内容发生变化,Webpack 将在生产中给出不同的名称,因此你不必担心资源的长期缓存。

请注意,这也是Webpack 自定义功能。

React 并不需要它,但是很多人喜欢它(React Native 使用类似的图片机制)。
下一节将会介绍处理静态资源的另一种方法。

Using the public Folder

注意:这个特性需要react-scripts@0.5.0 版本以上。

Changing the HTML

public 文件夹包括HTML 文件,所以你可以调整它,例如,设置页面标题。在构建过程中,编译好的代码的<script> 标签会被自动添加。

Adding Assets Outside of Module System

你可以在public 文件夹中添加其他资源。

注意我们通常鼓励你在JavaScript 中import 资源。例如,查看添加样式添加图片和字体 章节内容。这个机制有许多好处:

  • 脚本和样式表被压缩并打包在一起,以避免额外的网络请求。
  • 缺少文件导致编译错误,而不是用户的404 错误
  • 结果文件名包括内容哈希,因此你不必担心浏览器会缓存旧版本。

但是,你可以使用一个在模块系统之外添加资源的逃生门

如果你将文件放到public 文件夹,它将不会被Webpack 处理。并且它将不被修改的复制到构建文件夹。为了引用public 文件夹中的资源,你需要使用PUBLIC_URL 这个变量。

index.html 中,你可以这样使用:

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

只有位于public 文件夹中的文件可以通过%PUBLIC_URL% 前缀访问。如果你需要使用来自srcnode_modules 中的文件,你必须将其复制到明确指定此文件作为构建的一部分的意图。

当你运行npm run build ,Create React App 将使用正确的绝对路径来替换%PUBLIC_URL%,这样即使你使用客户端路径或将其托管到非艮URL,你的项目也可以正常工作。

在JavScript 代码中,你可以使用process.env.PUBLIC_URL 进行类似的操作:

render() {
  // Note: this is an escape hatch and should be used sparingly!
  // Normally we recommend using `import` for getting asset URLs
  // as described in “Adding Images and Fonts” above this section.
  return <img src={process.env.PUBLIC_URL + '/img/logo.png'} />;
}

记住这种方式的缺点:

  • public 文件夹中中的文件都不能进行后处理或压缩。
  • 在编译时,缺少的文件不会被调用,会对用户产生404 错误。
  • 结果文件名中不会包含内容哈希,因此在每次改动时,你需要添加查询参数或重命名它们。

When to Use the public Folder

通常我们建议从JavaScript导入样式表图像和字体public 文件夹作为一些不太常见的情况的解决方法是有用的:

  • 你需要在构建输出中具有特定名称的文件,如manifest.webmanifest
  • 你有成千上万的图像,需要动态引用他们的路径。
  • 你希望在打包代码之外加入一个像pace.js一样的脚本。
  • 某些库可能与Webpack不兼容,你没有其他选项,除了将其作为<script>标签。

请注意,如果添加声明全局变量的<script>,则还需要阅读下一节使用它们。

Using Global Variables

当你在HTML文件中的脚本中包含一个全局声明的变量,并尝试在代码中使用这些变量时,linter会抱怨,因为它看不到这些变量的定义。

你可以明确地从window 对象中读取全局变量来避免这个问题,例如:

const $ = window.$;

你正在有意使用一个全局变量,而不是因为书写错误。
或者,你可以通过添加// eslint-disable-line 强制linter 忽略任意一行。

Adding Bootstrap

你不必与React一起使用React Bootstrap,但它是将Bootstrap与React应用程序集成的流行库。 如果需要,可以通过以下步骤将其与Create React App集成:

从npm安装React Bootstrap和Bootstrap。 React Bootstrap不包括Bootstrap CSS,因此还需要安装它们:

npm install react-bootstrap --save
npm install bootstrap@3 --save

src/index.js 开头导入Bootstrap CSS 和可选的Bootstrap theme CSS:

import 'bootstrap/dist/css/bootstrap.css';
import 'bootstrap/dist/css/bootstrap-theme.css';
// Put any other imports below so that CSS from your
// components takes precedence over default styles.

src/App.js 中导入需要的React Bootstrap 组件或者你自定义的组件:

import { Navbar, Jumbotron, Button } from 'react-bootstrap';

现在你可以在这些导入了React Bootstrap 组件的组件的渲染方法中使用。这有一个使用React Bootstrap 的例子App.js

Using a Custom Theme

有时你可能需要调整Bootstrap(或其他类似包)的视觉样式。
我们建议按照下面方法:

  • 创建一个依赖于你要自定义的包的新包,例如 Bootstrap。
  • 添加必要的构建步骤来调整主题,并在npm发布你的包。
  • 安装你自己的主题npm软件包作为你的应用程序的依赖。

这是按照这些步骤添加一个自定义的Bootstrap的示例。

Adding Flow

Flow是一种静态类型的检查器,可以帮助你编写更少错误的代码。 如果你是这个概念的新手,请参阅JavaScript中使用静态类型的介绍

Flow的最新版本在Create React App项目中是开箱即用。

要将Flow添加到Create React App项目,请按照下列步骤操作:

  1. 运行npm install --save-dev flow-bin(或yarn add --dev flow-bin)。
  2. "flow": "flow"添加到你的的package.jsonscripts部分。
  3. 运行npm run flow-init(或yarn flow -- init)在根目录中创建一个.flowconfig文件
  4. // @flow添加到你想要进行类型检查的文件中(例如,到src/App.js)。

现在,你可以运行npm run flow(或yarn flow)来检查文件的类型错误。 你可以选择使用像Nuclide这样的IDE来获得更好的集成体验。 未来我们计划将更加紧密地将其整合到Create React App中。

要了解有关Flow的更多信息,请查看其文档

Adding Custom Environment Variables

注意:这个特性需要react-scripts@0.2.3 版本以上。

你的项目可以在你的环境中使用声明的变量,就像它们在JS文件中本地声明一样。 默认情况下,您将为你定义的NODE_ENV,和以REACT_APP_开头的任何其他环境变量。

环境变量在构建时嵌入。 由于Create React App生成了一个静态的HTML/CSS/JS包,所以在运行时无法读取它们。 要在运行时读取它们,你需要将HTML加载到服务器的内存中,并在运行时替换占位符,就像这里所述。 或者,你可以在任何时候更改,在服务器端时重新构建应用程序。

注意:你必须创建以REACT_APP_开头的自定义环境变量。除了NODE_ENV之外的任何其他变量将被忽略,以避免意外暴露可能具有相同名称的机器上的私钥。 如果运行时,更改任何环境变量将需要重新启动开发服务器。

这些环境变量将会被定义在process.env 上。你可以通过process.env.NODE_ENV 读取。当你运行npm start,它总是等于'development',当你运行npm test时,它总是等于'test',当你运行npm run build 是去生成一个生产包,它总是等于'production'你不能手动覆盖NODE_ENV。这样可以防止开发人员将缓慢的开发构建部署到生产环境中。

这些环境变量对于有条件地显示信息有用,基于项目的部署位置或者消耗存在与版本控制之外的敏感数据。

首先,你需要定义环境变量。 例如,假设你想要使用<form>中的环境中定义的敏感数据:

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>
  );
}

在构建中,process.env.REACT_APP_SECRET_CODE 将会被当前REACT_APP_SECRET_CODE 环境变量中的值替换。记住NODE_ENV 变量将会为你自动设置。

当你在浏览器中加载这个应用去查看<input>,你可以看到它的值设置为abcdef,加粗的字体将会显示运行npm start 时的环境。

<div>
  <small>You are running this application in <b>development</b> mode.</small>
  <form>
    <input type="hidden" value="abcdef" />
  </form>
</div>

上面的表单正在从环境中寻找一个名为REACT_APP_SECRET_CODE的变量。 为了消耗这个值,我们需要在环境中定义它。 这可以通过两种方式完成:在shell或.env文件中。 这两种方法将在接下来的几节中进行描述。

访问NODE_ENV对于有条件地执行操作是有用的:

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

当你使用npm run build 编译这个应用时,压缩操作在这个条件之外,所以这个最终的包会更小。

Referencing Environment Variables in the HTML

注意:这个特性需要react-scripts@0.9.0 版本以上。

你也可以在public/index.html 中访问以REACT_APP_ 开头的环境变量。例如:

<title>%REACT_APP_WEBSITE_NAME%</title>

请注意,上述部分的注意事项适用:

  • 除了几个内容的变量(NODE_ENVPUBLIC_URL),变量名字必须以REACT_APP_ 才工作。
  • 环境变量在构建时被注入。如果你需要在运行时注入它们,需要按照这里的步骤

Adding Temporary Environment Variables In Your Shell

定义环境变量可能会因操作系统而异。知道这种方式对于shell会话的生命周期是暂时的也很重要。

Windows(cmd.exe)

set REACT_APP_SECRET_CODE=abcdef&&npm start

(注意:空格的缺失是有意的)

Linux, macOS(Bash)

REACT_APP_SECRET_CODE=abcdef npm start

Adding Developement Environment Variables In .env

注意:这个特性需要react-scripts@0.5.0 版本以上。

在你的项目的根目录中创建一个.env 文件,去定义永久性的环境变量

REACT_APP_SECRET_CODE=abcdef

如果机器没有明确设置它们,这些变量将作为默认值。
有关详细信息,请参阅dotenv文档

注意:如果要定义用于开发的环境变量,则您的CI和/或托管平台也有可能需要这些定义。请参考他们的文档如何做到这一点。例如,请参阅Travis CIHeroku的文档。

Can I Use Decorators?

许多受欢迎的库在其文档中使用装饰器。
目前,Create React App不支持装饰器语法,因为:

  • 这是一个实验性提案,可能会改变。
  • 目前的规范版本没有被Babel正式支持。
  • 如果规范发生变化,我们将无法编写一个codemod,因为我们不在Facebook内部使用它们。

但是,在许多情况下,您可以重新编写基于装饰器的代码,而不需要装饰器就可以了。
请参考这两个线程以供参考:

当规范进展到稳定的阶段时,Create React App将添加装饰器支持。

posted @ 2018-01-25 16:52  JobbyM  阅读(803)  评论(0编辑  收藏  举报