React
Parcel 非常适合构建单页或多页 React 应用程序。它包含一流的开发体验,包括快速刷新,并开箱即用地支持 JSX、TypeScript、Flow 和许多样式方法。
入门
#首先,将 react
和 react-dom
安装到您的项目中
yarn add react react-dom
大多数 Parcel 应用程序都从一个 HTML 文件开始。Parcel 从那里跟踪依赖项(例如 <script>
标签)来构建您的应用程序。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>My Parcel App</title>
</head>
<body>
<div id="app"></div>
<script type="module" src="index.js"></script>
</body>
</html>
import { createRoot } from "react-dom/client";
import { App } from "./App";
const container = document.getElementById("app");
const root = createRoot(container)
root.render(<App />);
export function App() {
return <h1>Hello world!</h1>;
}
如您所见,我们在 HTML 文件中的 <script>
元素中引用了 index.js
。它导入了 react-dom
并使用它将我们的 App
组件渲染到页面中的 <div id="app">
元素中。
有关使用 Parcel 启动新项目的更多详细信息,请参阅 使用 Parcel 构建 Web 应用程序。
JSX
#当 Parcel 检测到您正在使用 React 时,它会自动支持 JSX。如果您使用的是 React 17 或更高版本,它还会自动启用 现代 JSX 转换,这意味着您甚至不需要导入 React 就可以使 JSX 工作,如上面示例中的 App.js
所示。
要了解有关 JSX 的更多信息,请参阅 React 文档中的 介绍 JSX 和 深入了解 JSX,以及 Parcel 的 JavaScript 文档中的 JSX 部分,了解有关如何配置一些处理细节的详细信息。
快速刷新
#Parcel 对 React 快速刷新 提供一流的支持,它在您编辑代码时提供快速反馈,而无需重新加载页面。在大多数情况下,它可以保留组件状态,即使您在编辑代码时出错。有关其工作原理的详细信息,请参阅 热重载 文档。
提示
#- 避免使用类组件 - 快速刷新仅适用于函数组件(和 Hooks)。
- 仅导出 React 组件 - 如果一个文件导出混合了 React 组件和其他类型的值,则其状态将在每次更改时重置。为了保留状态,仅导出 React 组件,如果可能,将其他导出移动到另一个文件。
- 避免使用未命名的默认导出 - 使用默认导出的箭头函数声明组件会导致其状态在更改时重置。使用命名函数,或者将箭头函数分配给变量。
- 将入口组件保留在它们自己的文件中 - 入口组件应该与调用
createRoot
的文件分开,否则它们将在每次更改时重新挂载。
有关更多提示,请参阅官方 React 快速刷新文档。
TypeScript
#TypeScript 开箱即用地受支持。您可以从 HTML 页面中引用 .ts
或 .tsx
文件,Parcel 将按预期编译它。
要为 React 添加 TypeScript 定义,请将以下包安装到您的项目中
yarn add @types/react @types/react-dom --dev
有关使用 Parcel 的 TypeScript 的更多详细信息,请参阅 TypeScript 文档。
Flow
#Flow 在安装后会自动得到支持。要将其添加到现有项目中,首先将 flow-bin
作为依赖项安装
yarn add flow-bin --dev
然后,在您要类型检查的文件顶部使用 // @flow
指令。这也会向 Parcel 信号哪些文件可以包含 Flow 类型,这些类型在编译到浏览器时应该被剥离。
有关使用 Parcel 的 Flow 的更多详细信息,请参阅 Flow 文档。
样式
#Parcel 支持许多不同的方法来为使用 React 编写的应用程序设置样式。
CSS
#您可以将 CSS 文件导入 JavaScript 或 TypeScript 文件,以将其与组件一起加载。
import './Button.css';
export function Button({ children }) {
return (
<button className="button">
{children}
</button>
);
}
.button {
background: hotpink;
}
您也可以使用 HTML 文件中的标准 <link rel="stylesheet">
元素加载 CSS,但是从组件中引用 CSS 有助于清楚地表明哪些组件依赖于哪些 CSS。这也有助于代码分割,因为只有您渲染的组件所需的 CSS 才会被加载。
Parcel 还支持 SASS、Less 和 Stylus 等 CSS 语言。有关 Parcel 如何处理 CSS 的更多详细信息,请参阅 CSS。
CSS 模块
#默认情况下,从 JavaScript 导入的 CSS 是全局的。如果两个 CSS 文件定义了相同的类名,它们可能会发生冲突并相互覆盖。为了解决这个问题,Parcel 支持 CSS 模块。
CSS 模块将每个文件中定义的类视为唯一的。每个类名都会被重命名以包含一个唯一的哈希值,并且会将一个映射导出到 JavaScript,以允许引用这些重命名的类名。
要使用 CSS 模块,请创建一个扩展名为 .module.css
的文件,并使用 命名空间导入 从 JavaScript 文件中导入它。然后,您可以在 JSX 中渲染元素时使用 CSS 模块的导出。
import * as classes from './Button.module.css';
export function Button({ children }) {
return (
<button className={classes.button}>
{children}
</button>
);
}
.button {
background: hotpink;
}
有关 Parcel 如何处理 CSS 模块的更多信息,请参阅 CSS 模块。
CSS-in-JS
#Parcel 与 Styled Components、Emotion 等许多 CSS-in-JS 库配合得很好。有些可能需要构建配置,例如 Babel 插件。要启用它,请在您的项目中创建一个 Babel 配置,Parcel 会自动获取它。
例如,要使用 Emotion,请安装 Babel 插件并在您的项目中创建一个 .babelrc
yarn add @emotion/babel-plugin --dev
yarn add @emotion/react
{
"plugins": ["@emotion/babel-plugin"]
}
您还需要在 tsconfig.json
或 jsconfig.json
中设置 jsxImportSource
选项,以便使用 Emotion 的 JSX 标记而不是默认标记。这将使 css
属性能够工作。
{
"compilerOptions": {
"jsxImportSource": "@emotion/react"
}
}
现在,您可以使用 CSS-in-JS 渲染元素
import { css } from "@emotion/react";
export function Button({ children }) {
return (
<button
css={css`
background: hotpink;
&:hover {
background: purple;
}
`}
>
{children}
</button>
);
}
Tailwind CSS
#Tailwind CSS 是一个流行的实用优先 CSS 框架。它使用 PostCSS 来构建一个 CSS 文件,其中只包含您在代码中使用的类。
要使用它,首先安装必要的依赖项
yarn add tailwindcss postcss autoprefixer --dev
接下来,创建 PostCSS 和 Tailwind 所需的配置文件。此示例将使用 Tailwind 的 JIT 模式 来通过仅编译您使用的类来加快构建速度。确保修改传递给 content
选项的 glob,使其匹配您将使用 Tailwind 类的所有源文件。
{
"plugins": {
"tailwindcss": {}
}
}
module.exports = {
content: ["./src/*.{html,js}"],
theme: {
extend: {},
},
variants: {},
plugins: [],
};
最后,您可以从与 tailwind.config.js
中列出的 content
glob 匹配的任何文件中引用 Tailwind 类。
export function Button({ children }) {
return (
<button className="p-2 rounded bg-blue-500 hover:bg-blue-600 transition">
{children}
</button>
);
}
图片
#您可以使用 URL
构造函数从 JSX 中引用外部图片。Parcel 还支持使用 查询参数 来调整图片大小并将其转换为不同的格式。它还处理图片优化,并在输出文件名中包含 内容哈希,以便进行长期浏览器缓存。
const logo = new URL('logo.svg', import.meta.url);
export function Logo() {
return <img src={logo} alt="logo" />;
}
有关此语法的更多详细信息,请参阅 JavaScript 文档中的 URL 依赖项,有关 Parcel 如何处理图片的更多信息,请参阅 图片 文档。
SVG
#可以像上面描述的那样引用外部 SVG 文件。您还可以将 SVG 导入为 React 组件,这些组件可以直接在 JSX 中渲染。
首先,安装 @parcel/transformer-svg-react
插件并将其添加到您的 .parcelrc
中
yarn add @parcel/transformer-svg-react --dev
{
"extends": "@parcel/config-default",
"transformers": {
"*.svg": ["...", "@parcel/transformer-svg-react"]
}
}
现在,您可以从组件文件中导入 SVG 并像任何其他组件一样渲染它们。
import AddIcon from "./AddIcon.svg";
export function AddButton() {
return (
<button aria-label="Add">
<AddIcon />
</button>
);
}
上面的示例展示了如何将每个 SVG 文件转换为 JSX,但在某些情况下您可能希望更具选择性。有关更多详细信息,请参阅 SVG 文档中的 导入为 React 组件。
有关 Parcel 如何转换和优化 SVG 文件的更多信息,请参阅 SVG 文档。
代码分割
#代码分割通过延迟加载应用程序的各个部分来帮助减少初始页面加载大小。这可以通过使用动态 import()
语法以及 React.lazy
来实现。
此示例在用户单击按钮时延迟加载 Profile
组件。当它看到动态 import()
时,Parcel 将 Profile
组件移动到与 Home
组件分开的包中,并按需加载它。React.lazy
处理将其转换为组件,Suspense
处理在加载时渲染一个回退。
import React, {Suspense} from 'react';
const Profile = React.lazy(() => import('./Profile'));
export function Home() {
let [showProfile, setShowProfile] = React.useState(false);
return (
<main>
<h1>Home</h1>
<button onClick={() => setShowProfile(true)}>
Show Profile
</button>
{showProfile &&
<Suspense fallback={<div>Loading...</div>}>
<Profile />
</Suspense>
}
</main>
);
}
export default function Profile() {
return <h2>Profile</h2>;
}
有关 Parcel 中代码分割的更多详细信息,请参阅 代码分割 文档,有关 Suspense
和 React.lazy
的更多信息,请参阅 React 文档中的 代码分割。