React、Vite 和 TypeScript:2 分钟内即可上手
说实话,如果你必须交付代码,处理工具并不是一件令人愉快的事情。它应该只是工作,而不是妨碍工作。所以,让我们探索如何在 2 分钟内使用 Vite 启动你的下一个 React 项目,而无需担心设置。
目录
1.如何创建新的项目设置?
2.运行、构建和测试应用程序
3.构建应用程序
4.测试应用程序
5.使用 Cypress 运行集成测试
6.代码检查
7.自定义 Vite 和 Vitest
8.隐藏的精华:缓存
9.隐藏的精华:轻松模块化您的应用程序
10.隐藏的精华:可视化您的架构
11.隐藏的精华:守护您的边界
12.隐藏的精华:只运行更改的内容
13.隐藏的精华:专用的编辑器扩展
14.隐藏的精华:自动升级
15.使用 CRA?自动迁移到 Vite + Nx
16.结论
17.了解更多
传统上,你可能倾向于使用Create-React-App (CRA)来实现这一点。但如果我告诉你还有更好的选择,那就是提供
- 不仅仅是初始设置的脚手架,还可以帮助您生成组件、路由等
- 自动为你设置用于端到端测试、单元测试、代码格式化和 linting 的最佳实践工具
- 内置对 Vite 和 Vitest 的支持(或者 Webpack 和 Jest)
- 缓存脚本以加快速度
- 帮助您模块化您的应用程序
- 配备自动升级功能,让您的工具保持常青
我指的是Nx。Nx附带一组插件,这些插件具有代码生成功能,并有助于抽象一些底层工具的设置。这对于我们今天要处理的用例来说可能非常有趣。
读者: “等一下,我听说过 Nx。那不是 Monorepos 吗?”
我: “是的,你说得对。但在 15.3 版本中,他们引入了一种叫做‘独立应用’的功能。”
读者: “独立应用?”
我: “是啊,一个很花哨的术语,指的是设置单个应用,允许进行一些很酷的模块化。这里有一个介绍这个功能的视频:https://youtu.be/qEaVzh-oBBc ”
读者: “哈哈,有意思🤔”
那么让我们开始设置我们的React + Vite + TypeScript 项目。
如何创建新的项目设置?
要建立一个新项目,只需调用以下命令:
npx create-nx-workspace@latest awesomereactapp --preset=react-standalone
注意:awesomereactapp
这是正在创建的应用程序和文件夹的名称,它--preset=react-standalone
告诉 Nx 在构建初始设置时要使用哪个模板。您也可以像这样调用它:
npx create-nx-workspace@latest awesomereactapp
然后在终端提示中选择您喜欢的选项:
最后,您将获得以下结构:
运行、构建和测试应用程序
首先,让我们运行我们新的、闪亮的应用程序。只需调用
npm start
只需几毫秒,您的应用程序就会在http://localhost:4200/上提供服务。
npm start
仅调用以下定义的脚本package.json
:
// package.json
{
"name": "awesomereactapp",
...
"scripts": {
"start": "nx serve",
"build": "nx build",
"test": "nx test"
}
...
}
在内部,它委托给nx serve
,其中Nxserve
是要调用的目标project.json
。您可以在 中找到它们:
// project.json
{
"name": "awesomereactapp",
"$schema": "node_modules/nx/schemas/project-schema.json",
"sourceRoot": "./src",
"projectType": "application",
"targets": {
"build": {...},
"serve": {
"executor": "@nrwl/vite:dev-server",
"defaultConfiguration": "development",
"options": {
"buildTarget": "awesomereactapp:build"
},
"configurations": {
"development": {
"buildTarget": "awesomereactapp:build:development",
"hmr": true
},
"production": {
"buildTarget": "awesomereactapp:build:production",
"hmr": false
}
}
},
"test": {...},
"lint": {...}
},
"tags": []
}
在这里,您可以查看特定项目的所有可用目标,并可以添加您自己的目标!简而言之,Nx 目标包含
executor
dev-server
-插件(此处)公开的函数(此处@nrwl/vite
),用于运行当前任务。可以将其视为常用 Npm 脚本的包装器。options
- 您可以在此处将选项传递给executor
configurations
- 允许您创建不同版本的options
。您可以通过将标志传递--configuration=production
给命令来控制使用哪个配置。另请注意defaultConfiguration
。
如果您愿意,可以更深入地了解Nx 文档。
构建应用程序
就像服务我们的 Web 应用程序一样,我们可以使用
npx nx build
这会将输出放入dist
文件夹中。既然我们已经了解了project.json
目标,您可能已经猜到可以直接在这些设置中自定义该输出文件夹。
测试应用程序
此设置还附带使用Vitest进行测试。您可能已经猜到了,您可以按如下方式运行测试:
npx nx test
使用 Cypress 运行集成测试
你可能注意到了这个文件夹。里面是Cypresse2e
的完整设置,可用于进行集成级甚至完整的端到端测试。
这非常好,因为你根本不需要配置任何东西。不需要
- Cypress 配置为使用 Vite(而不是 Webpack)
- 为 e2e 项目设置 linting(是的,编写高质量的测试代码同样重要)
- 首先手动启动我们的开发服务器,为我们的 React 应用程序提供服务,以便我们可以将其加载到我们的 Cypress 测试环境中
我们需要做的就是使用
npx nx e2e e2e
这乍一看可能很奇怪,但基本上,我们在项目上运行e2e
目标(参见e2e/project.json
)e2e
。
// e2e/project.json
{
"name": "e2e",
"$schema": "../node_modules/nx/schemas/project-schema.json",
"sourceRoot": "e2e/src",
"projectType": "application",
"targets": {
"e2e": {
"executor": "@nrwl/cypress:cypress",
"options": {
"cypressConfig": "e2e/cypress.config.ts",
"devServerTarget": "awesomereactapp:serve:development",
"testingType": "e2e"
},
"configurations": {
"production": {
"devServerTarget": "awesomereactapp:serve:production"
}
}
},
...
}
}
默认情况下,这些测试以无头模式运行,但您可以--watch
通过 Cypress 测试运行器以交互方式运行它,以便在我们更改源时重新执行测试。
想要测试 Cypress 组件?Nx 生成器可以帮助您完成设置。查看文档:https://nx.dev/packages/react/generators/cypress-component-configuration
代码检查
类似地,可以通过运行以下命令来触发 linting:
npx nx lint
.eslintrc.json
工作区的根目录中已经有一个文件,其中包含一些最佳实践规则。
定制 Vite 和 Vitest
项目设置方式让您可以轻松自定义Vite和Vitest 的设置。只需打开工作区根目录下的预生成文件vite.config.ts
,添加自定义 Vite 插件或微调 Vitest 即可。
/// <reference types="vitest" />
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
import viteTsConfigPaths from 'vite-tsconfig-paths';
export default defineConfig({
server: {
port: 4200,
host: 'localhost',
},
plugins: [
react(),
viteTsConfigPaths({
root: './',
}),
],
// vitest config
test: {
globals: true,
cache: {
dir: './node_modules/.vitest',
},
environment: 'jsdom',
include: ['src/**/*.{test,spec}.{js,mjs,cjs,ts,mts,cts,jsx,tsx}'],
},
});
隐藏的宝石:缓存
Nx 以其缓存功能而闻名,这有助于优化 Monorepos 的速度。缓存功能接收输入(命令、源文件、环境变量……)并计算哈希值。
每次运行时,Nx 都会将该哈希值与本地缓存文件夹进行比较。如果哈希值存在,Nx 会恢复上次运行产生的命令行输出和潜在文件(JS、CSS 等)。这有助于加快计算速度,因为如果不需要,您可以不运行它。
有关详细信息,请参阅 Nx 文档:https://nx.dev/concepts/how-caching-works
虽然这在 monorepo 中显然很有意义,但它也可以帮助加快单项目工作区的速度。大多数项目都有多个目标,例如build
、、test
。lint
这些都可以缓存!想象一下,您有一个 PR,*.spec.ts
因为您添加了测试或修复了某些文件而更改了某些文件。您的 CI 脚本可能一直运行所有目标(build
、、)。它完全应该这样做。但您可以避免这一步test
,因为您的 spec 文件不应该影响该结果。因此,它可以从缓存中恢复。需要运行,并且如果您对 spec 文件运行 linting,也可能需要运行。lint
build
test
lint
您可以微调每个命令的缓存内容。更多信息请参阅 Nx 文档
隐藏的宝石:轻松模块化您的应用程序
想象一下一个店面应用程序。你可能会有如下域名区域:
- 产品列表——可以列出所有当前可用的产品、其评级、用户评论等。
- 订单 - 用于查看您当前未结订单或浏览过往订单。例如,下单或触发已购商品的退款。
- 付款 - 用于处理付款流程、索取信用卡、触发付款以及在付款成功后启动订单流程
- 身份验证 - 处理整个注册/登录流程并为应用程序中的其他域区域提供低级实用程序,例如获取当前用户的访问权限。
- 用户资料 - 管理所有与用户相关的内容。当你访问亚马逊并进入你的账户时,可以想象一下它。例如管理你的地址
- ...
我们只是触及了皮毛。它很快就会变得庞大。使用当前工具(包括 CRA)管理此类结构的唯一方法是将这些域组织到文件夹中。因此,在 CRA 设置中,您将看到类似以下内容:
cra-app
├─ public/
├─ src/
│ ├─ authentication/
│ │ ├─ current-user/
│ │ │ ├─ ...
│ │ │ └─ index.ts
│ │ ├─ login/
│ │ └─ signup/
│ ├─ orders/
│ │ ├─ checkout/
│ │ ├─ place-order/
│ │ ├─ refund/
│ │ └─ order-list/
│ ├─ payments/
│ ├─ products/
│ ├─ user-profile/
│ │ ├─ addresses/
│ │ └─ credit-cards/
│ ├─ App.css
│ ├─ App.tsx
│ ...
├─ package-lock.json
├─ package.json
└─ README.md
大多数开发者工具(包括 CRA)都会强制你使用单体架构,将功能划分到不同的文件夹中。然而,文件夹的隔离性有限;随着应用程序的增长,这种架构很快就会失控。
我们可以通过将这些领域提取到专用库或模块中,使用 Nx 构建一个不同的、更强大的结构。这些库或模块与您的应用程序并存。假设我们有一个名为“domains”的文件夹,其中包含这些领域区域。然后,您可以使用以下命令轻松生成一个新的库:
npx nx g @nrwl/react:lib checkout --directory=domains/orders/checkout --bundler=none
上述命令会在domains/orders/
文件夹中创建一个新的“checkout”库。它如下所示:
awesomereactapp
├─ public
│ └─ favicon.ico
├─ src
│ ├─ app
│ ├─ ...
├─ domains
│ └─ orders
│ └─ checkout
│ ├─ src
│ │ ├─ index.ts
│ │ └─ lib
│ │ ├─ domains-orders-checkout.module.css
│ │ ├─ domains-orders-checkout.spec.tsx
│ │ └─ domains-orders-checkout.tsx
│ ├─ tsconfig.json
│ ├─ tsconfig.lib.json
│ ├─ tsconfig.spec.json
│ └─ vite.config.ts
├─ ...
├─ index.html
├─ package-lock.json
├─ package.json
├─ ...
├─ tsconfig.app.json
├─ tsconfig.base.json
├─ tsconfig.json
├─ tsconfig.spec.json
└─ vite.config.ts
请注意domains/orders/checkout/src/index.ts
:这是库的公共 API checkout
,您可以决定哪些内容需要导出,哪些内容需要在库内保持私有。这种有意识地选择哪些内容需要公开、哪些内容需要隐藏的过程,比单纯的文件夹结构更能实现更强的封装性。随着应用规模的增长,它还能极大地提升可维护性。
生成库时,会在根级别自动创建 TypeScript 路径映射tsconfig.base.json
:
{
"compileOnSave": false,
"compilerOptions": {
...
"paths": {
"@awesomereactapp/domains/orders/checkout": [
"domains/orders/checkout/src/index.ts"
]
}
},
"exclude": ["node_modules", "tmp"]
}
通过这种方式,从库中导出的任何东西都checkout
可以被使用,就像
import { SomeComponent } from '@awesomereactapp/domains/orders/checkout';
您还可以针对这些新库单独运行 linting 或测试:
npx nx test domains-orders-checkout
显然,缓存(如前所述)也适用于这些新库。
注意,是项目的唯一名称,由其文件结构组成。您可以根据需要
domains-orders-checkout
更改名称。domains/orders/checkout/project.json
隐藏的宝石:可视化你的架构
将代码库拆分成库的另一个好处是,代码结构和架构会清晰可见。Nx 内置了一个graph
命令,你甚至可以将其可视化:
npx nx graph
如果您选中“按文件夹分组”复选框,事情就会变得更加有趣,因为此时域就会变得可见:
请注意,这是一个假设的应用程序,用于演示 Nx 图形可视化的一些功能。其中一些关联可能难以理解。
隐藏的宝石:守护你的界限
软件产品的扩展不仅仅是最初的结构化和模块化。它包含一个持续不断的过程,确保模块保持良好状态,并且不包含任何不必要的交叉引用或循环依赖。您可以利用 Nx 图来直观地验证这一点,但这无法扩展。
为了解决这个问题,Nx 内置了模块边界 lint 规则。可以为项目分配“标签”,例如,,,和type:domain
,,type:utils
。这些标签可以在 中分配,例如type:shared
domain:products
domain:orders
domain:auth
project.json
//
{
// ... more project configuration here
"tags": ["domain:products", "type:domain"]
}
注意,
type:domain
或domain:products
实际上只是字符串。你可以随意定义它们。
然后,您可以在 中.eslintrc.base.json
定义规则。例如,我们在这里规定 的库type:utils
只能依赖于其他实用程序库,而type:domain
可以同时依赖于其他领域库和实用程序库。
// .eslintrc.base.json
{
"overrides": [
{
"rules": {
"@nrwl/nx/enforce-module-boundaries": [
"error",
{
"depConstraints": [
{
"sourceTag": "type:utils",
"onlyDependOnLibsWithTags": ["type:utils"]
},
{
"sourceTag": "type:domain",
"onlyDependOnLibsWithTags": ["type: domain", "type:utils"]
},
{
"sourceTag": "domain:products",
"onlyDependOnLibsWithTags": ["domain:products", "domain:orders"]
}
]
}
]
}
}
]
}
如果需要遵循其中一些 lint 规则,您的编辑器将在您的代码中正确显示它,并且您还可以在 CI 上为每个 PR 运行 lint 检查。
如果您感兴趣,可以在这里阅读更多内容:https://blog.nrwl.io/mastering-the-project-boundaries-in-nx-f095852f5bf4
隐藏的宝石:只需运行更改的内容
在这种模块化结构(如上所示)中,您的代码被组织成更小的模块/库,团队成员通常只在单个领域内工作。因此,PR 通常只涉及整个库集的一个子集。Nx 附带一个内置命令,允许您在 CI 中使用所谓的“受影响的命令”来利用此功能。
假设我们对product-detail
应用程序的库进行了更改。这将影响所有依赖该库的其他库。您也可以通过运行以下命令来可视化它:
npx nx affected:graph
要仅为受影响的区域运行任务,请使用:
npx nx affected:<target>
举一个具体的例子,只针对这些项目运行测试:
npx nx affected:test
隐藏的宝石:专用的编辑器扩展
如果您不是“命令行界面类型”的开发人员,并且更喜欢在 IDE 中集成某些功能,那么有个好消息。Nx 核心团队还发布了一个专用的 VSCode 扩展:Nx Console。
它在 VSCode 中有一个专用视图来触发常用命令、浏览工作区结构甚至内联渲染图形。
它还带有上下文菜单,可以快速访问大多数常用功能:
以下演示视频展示了 Nx Console 的一些强大功能:
隐藏的宝石:自动升级
为了保持工作空间的常青,Nx 配备了自动代码迁移功能,
- 升级你的
package.json
软件包到下一个版本 - 如果需要可以自动更新您的配置文件
- 必要时可以自动更新源文件(如果 API 发生重大变化)
即使发生重大变更,也能实现平稳过渡。只需运行
npx nx migrate latest
Nx 会收集当前安装的软件包并将其更新到最新版本。如果软件包附带 Nx 迁移脚本,Nx 会将它们收集到一个migrations.json
文件中。您可以检查并运行这些脚本。这极大地有助于保持项目工具的更新。
阅读文档以了解有关Nx 迁移如何工作的更多信息。
使用 CRA?自动迁移至 Vite + Nx
如果您当前使用的是CRA设置,则可以通过在 CRA 项目中运行以下命令轻松迁移到基于 Nx + React + Vite 的设置:
npx nx init
阅读更多 Nx 文档:https://nx.dev/recipes/adopting-nx/migration-cra
如果由于某种原因您暂时无法迁移到 Vite,您可以
--vite=false
暂时保留基于 Webpack 的设置。
结论
准备好了吗?尝试一下:
npx create-nx-workspace mycoolapp --preset=react-standalone
让我们知道您的想法:)
了解更多
- 🧠 Nx 文档
- 👩💻Nx GitHub
- 💬 Nrwl 社区 Slack
- 📹 Nrwl YouTube频道
- 🥚免费 Egghead 课程
- 🧐需要 Angular、React、Monorepos、Lerna 或 Nx 方面的帮助?欢迎联系我们 😃
此外,如果您喜欢这个,请单击❤️并确保在 Twitter 上关注Juri和Nx以获取更多信息!