首页 > 其他分享 >从零到一构建并打包 React + TypeScript + Less组件库教程(一、项目初始化搭建+代码规范集成)

从零到一构建并打包 React + TypeScript + Less组件库教程(一、项目初始化搭建+代码规范集成)

时间:2024-11-14 11:31:02浏览次数:1  
标签:TypeScript stylelint Less React json eslint pnpm true prettier

本系列涉及的内容如下:

  1. 组件库基础搭建,react + ts + less
  2. 项目规范,包括但不限于 prettier、eslint、stylelint、husky、lint-staged、commitlint
  3. pnpm monorepo + turborepo 集成
  4. gulp + webpack 构建 esm、cjs 和 umd
  5. storybook 文档集成

此系列不包含发布 npm 和构建 CI 流程。

本系列目录如下:

  1. 项目初始化搭建+代码规范集成
  2. 组件库多产物编译及文档编写

此系列不是所谓的最佳实践,流行组件库经过迭代都非常完善,不是一人力能完成的,而本系列只是将功能上的核心进行了总结,不足之处依然很多

  • 阅读本系列需要对组件库的构成有一定的了解,不多,一点点即可,纯小白可能会有点难入手。
  • 后续有时间会追加一篇 React Icon 组件库的构建。

本篇的内容可直接查看 commithttps://github.com/json-q/rc-library-templete/commit/edaa1adb6772babf475612a754566f0dbefa52fb

初始化项目

mkdir react-library-templete
cd react-library-templete
pnpm init

package.json 初始化工作

由于是 pnpm monorepo 项目,必须使用 pnpm,可以在 package.json 中做一下限制

  "scripts": {
    "preinstall": "npx only-allow pnpm",
  },
  "packageManager": "[email protected]",
  "engines": {
    "node": ">=20"
  },
  • packageManager 可以不写,主要作用是为了约束开发都是用这个版本,避免包管理工具版本不一致导致的兼容问题
  • engines 指定项目使用的 node 版本

注意: 一旦声明 packageManager,在执行 install 时,会提示你是否替换成指定版本,此替换为全局的版本替换,之前的安装版本将被覆盖

安装基础依赖

使用 TypeScript + Less 编写,肯定要安装 typescript 和 less,如果涉及到 node 相关的,还可以再安装一个 @types/node 类型提示

pnpm i typescript less @types/node -D

项目规范

集成 eslint

需提前安装 ESLint 插件

pnpm dlx @eslint/create-config

image

eslint 基本结构有了,再装一些辅助插件

pnpm i eslint-plugin-react-hooks eslint-plugin-jsx-a11y eslint-plugin-react-refresh -D
  • eslint-plugin-jsx-a11y 是一个无障碍访问的 eslint 检测,可按需安装
  • eslint-plugin-react-refresh 检测 react 组件是否可以安全刷新,可按需安装

eslint.config.mjs 中添加这几个插件

import globals from "globals";
import pluginJs from "@eslint/js";
import tseslint from "typescript-eslint";
import pluginReact from "eslint-plugin-react";
import reactRefresh from 'eslint-plugin-react-refresh';
import jsxA11y from 'eslint-plugin-jsx-a11y';
import reactHooks from 'eslint-plugin-react-hooks';

/** @type {import('eslint').Linter.Config[]} */
export default [
  {files: ["**/*.{js,mjs,cjs,ts,jsx,tsx}"]},
  {languageOptions: { globals: globals.browser}},
  pluginJs.configs.recommended,
  ...tseslint.configs.recommended,
  pluginReact.configs.flat.recommended,
  jsxA11y.flatConfigs.recommended,
  {
    plugins: {
      'react-hooks': reactHooks,
      'react-refresh': reactRefresh,
    },
    rules: {
      ...reactHooks.configs.recommended.rules,
      'react-refresh/only-export-components': ['warn', { allowConstantExport: true }],
    },
  },
  {
    ignores: [
      '**/dist/*',
      '**/es/*',
      '**/lib/*',
      'node_modules',
      '*.woff',
      '.ttf',
      '.vscode',
      '.idea',
      '.husky',
      '.local',
      '/bin',
      '.eslintcache',
      '.stylelintcache',
    ],
  },
];

eslint 配置过程中,可以新建一个 ts 文件,写一些不规范代码,时刻查看 eslint 的检测是否会失效,因为由于写法错误也会导致 eslint 的配置失效。

集成 Prettier

需提前安装 Prettier 插件

pnpm i prettier eslint-plugin-prettier eslint-config-prettier -D

新建 .prettierrc.cjs

/** @type {import("prettier").Config} */
module.exports = {
  printWidth: 120,
  useTabs: false,
  singleQuote: true,
  proseWrap: 'never',
};

新建 .prettierignore

**/dist/*
**/es/*
**/lib/*

**/.local
**/node_modules/**

**/*.svg
**/*.sh

.eslintcache
.stylelintcache

此时你可以发现 .prettierrc.cjs 被 eslint 报错了

image

这是由于 module 是 node 环境的全局变量,而 eslint 不识别 node 环境。在 eslint.config.mjs 中的 globals 属性添加 node 全局变量

export default [
  // ...
  {languageOptions: { globals: {...globals.browser,...globals.node}}},
  // ...
];

此时就没问题了

prettier 和 eslint 的集成

前边写过的都省略掉了,只列出更改的部分。该部分让 eslint 和 prettier 做了集成,并添加了一项 eslint 关闭校验的规则 @typescript-eslint/no-explicit-any,即此时是允许使用 any 的(默认禁止使用 any)

// ...
import eslintConfigPrettier from 'eslint-config-prettier';
import prettierRecommended from 'eslint-plugin-prettier/recommended';

/** @type {import('eslint').Linter.Config[]} */
export default [
  // ...
  eslintConfigPrettier,
  prettierRecommended,
  {
    // ...
    rules: {
      // ...
      '@typescript-eslint/no-explicit-any': 'off',
    },
  },
];

不出意外的话,此时就能看到 eslint.config.mjs 中存在大量的 prettier 报错提示。

image

在根目录新建一个 .vscode 文件夹,在文件夹内部新建 settings.json 文件

{
  "search.exclude": {
    "**/node_modules": true,
    "dist": true,
    "es": true,
    "lib": true,
    "storybook-static": true,
    "pnpm-lock.yaml": true
  },
  "editor.codeActionsOnSave": {
    "source.fixAll": "explicit"
  },
  "editor.formatOnSave": true,
  "editor.defaultFormatter": "esbenp.prettier-vscode",
  "stylelint.validate": ["css", "less", "scss", "sass", "html"]
}

其实主要就是自动保存格式化,然后回到 eslint 的文件,保存就会自动格式化,如果格式化后依然报错,可以尝试重启 vscode。

编码问题

在 windows 上默认是 CRLF 编码,而 prettier 认为这是一种错误的编码方式,格式化也不行。

image

  • 安装 EditorConfig for VS Code 插件
  • 根目录新建 .editorconfig,写入内容,再次保存,就可以看到编码已经变成 LF
# http://editorconfig.org
root = true

[*]
indent_style = space
indent_size = 2
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true

[*.md]
trim_trailing_whitespace = false

[Makefile]
indent_style = tab

使用 .gitattributes 解决多环境编码不一致问题

editconfig 只是解决本地开发的编码问题,当你提交到 git 后,再拉取一个全新的,如果是 win 系统,依然是 CRLF。

为了解决这个问题,可以在代码提交时做格式上的统一,在根目录新建 .gitattributes,统一编码为 LF,且文件类的不做处理

* text=auto eol=lf

*.{ico,png,jpg,jpeg,gif,webp,svg,woff,woff2} binary

Stylelint 集成

由于使用 less 开发,所以就额外安装了 less 的解析和校验插件

pnpm i stylelint stylelint-config-recommended stylelint-config-standard-less stylelint-prettier stylelint-order stylelint-config-recess-order postcss-less -D

这几个我就不过多介绍了,其中 stylelint-orderstylelint-config-recess-order 就是 css 排序插件和排序规则,两个结合使用(可选安装)。

根目录新建文件 .stylelintrc.cjs

/** @type {import("stylelint").Config} */
module.exports = {
  plugins: ['stylelint-order'],
  customSyntax: 'postcss-less',
  extends: [
    'stylelint-config-recommended',
    'stylelint-prettier/recommended',
    'stylelint-config-recess-order',
    'stylelint-config-standard-less',
  ],
  rules: {
     // 规则自定义即可
    'color-function-notation': null,
    'less/no-duplicate-variables': null,
  },
  ignoreFiles: ['**/.js', '/*.jsx', '/.tsx', '**/.ts', '**/dist/**', '**/es/**', '**/lib/**', '**/node_modules/**'],
};

完毕之后可以随便建一个测试的 less 文件,写一些内容来测试插件是否生效

image

由此可见,排序插件是生效了,此时保存代码就可以自动修复排序规则,那这个 stylelint 的配置应该也没什么问题。

如果没有生效,尝试重启 vscode,且每次更改 stylelint 的配置后,都建议重启验证

scripts 添加 fix 命令(可忽略)

package.json 添加 script 命令

  "scripts": {
    "preinstall": "npx only-allow pnpm",
    "lint:eslint": "eslint . --fix --cache",
    "lint:stylelint": "stylelint \"**/*.{less,css}\" --fix --cache"
  },

monorepo 基本结构搭建

这里不介绍 monorepo 单体仓库的作用,能看到该文章的应该都对其有一定的了解。

该项目的多包仓库思路是:

  • packages 文件夹作为组件开发的核心模块
    • 多个子包都需要 tsconfig 的配置,那就可以把这个配置抽离出来
    • icon 组件库作为一个单独的包
    • 其它广泛使用的组件为组件库核心包(常用 util hook 什么的也可以抽离,这里不再做更细致划分)
  • storybook 文档作为单独的模块
  • site 组件库网站作为单独模块(可选)

此时结构目录应该是

- packages
    - components
    - icons
    - tsconfig
- site
- storybook

目录新建完毕后,根目录新建 pnpm-workspace.yaml

packages:
  - packages/*
  - site
  - storybook

此时 monorepo 的基本目录结构就已经搭建好了

初始化 packages 目录的子包

其中 sitestorybook 先设为 TODO(待办),优先整理 packages 下的子包

packages 下的包统一初始化执行 pnpm init 命令

tsconfig

进入 tsconfig 目录,将 package.json 中的 name 修改为你喜欢的包名,后续都是以 name 字段的名字安装依赖,由于项目内使用,设置成 private 即可,我设置的 rclt 就是 react-component-library-templete 的简写。

{
  "name": "rclt-tsconfig",
  "version": "0.0.1",
  "description": "",
  "keywords": [],
  "author": "",
}

json 内容仅供参考

新建 base.json 文件

{
  "$schema": "https://json.schemastore.org/tsconfig",
  "compilerOptions": {
    "strict": true,
    "composite": false,
    "declaration": true,
    "esModuleInterop": true,
    "forceConsistentCasingInFileNames": true,
    "allowSyntheticDefaultImports": true,
    "allowImportingTsExtensions": true,
    "allowJs": true,
    "inlineSources": false,
    "isolatedModules": true,
    "module": "ES2020",
    "moduleResolution": "Bundler",
    "noUnusedLocals": true,
    "noUnusedParameters": true,
    "preserveWatchOutput": true,
    "skipLibCheck": true,
    "strictNullChecks": true
  },
  "exclude": ["dist", "build", "es", "lib", "node_modules"]
}

新建 react-library.json 文件

{
  "$schema": "https://json.schemastore.org/tsconfig",
  "extends": "./base.json",
  "compilerOptions": {
    "module": "ES6",
    "target": "ES5",
    "jsx": "react",
    "lib": ["DOM", "ES2015"]
  }
}

此时就可以在根目录添加 rclt-tsconfig 依赖

  "devDependencies": {
    "rclt-tsconfig": "workspace:*",
  }

执行 pnpm i 安装,新建一个 tsconfig.json 来使用这个包

{
  "extends": "rclt-tsconfig/base.json",
  "compilerOptions": {
    "noEmit": true
  },
  "include": ["packages/**/*.tsx", "packages/**/*.ts"]
}

不要问我为什么不使用命令安装,问就是没找到根目录安装子包的命令(不会)

components

rclt-tsconfig 链接到 components 包下,以下命令的意思就是从本地找 rclt-tsconfig 安装到 rclt-components

  • rclt-components 是 components 包 package.json 中的 name
  • -workspace 是从本地查找
  • 暴力一点的话直接在 package.json 中写入包依赖,比如 "rclt-tsconfig": "workspace:*",再执行 pnpm install 即可。
pnpm --filter rclt-components add rclt-tsconfig -D -workspace

新建 tsconfig.json

{
  "extends": "rclt-tsconfig/react-library.json",
  "compilerOptions": { "emitDeclarationOnly": true }, // 只生成声明文件
  "include": ["src"]
}

没问题的话,点 extends 的路径链接是可以跳到 json 文件的

提交规范

这些依赖的集成都是在根目录进行的,记得安装的时候带上 -w 来指定在根工作区安装。

husky + lint-staged 集成

安装依赖之前的准备工作

在此之前,先把我们的项目 git 初始化一下,执行 git init 命令,最好再建一个 git 仓库,关联本地代码,这部分我就不赘述了,大家应该都会。

根目录新建 .gitignore,以下是我的文件内容,大家可自行修改忽略文件(我个人习惯不上传 lock 依赖,除非特殊情况需要锁定版本)

# Dependencies
node_modules
.pnp
.pnp.js

# Local env files
.env
.env.local
.env.development.local
.env.test.local
.env.production.local

# Testing
coverage

# Turbo
.turbo

# Vercel
.vercel

# Build Outputs
.next/
out/
build
dist
es
lib


# Debug
npm-debug.log*
yarn-debug.log*
yarn-error.log*

# Misc
.DS_Store
*.pem

# cache
.eslintcache
.stylelintcache

# lock
pnpm-lock.yaml

集成依赖

安装并初始化 husky

pnpm i husky lint-staged -D -w
# 初始化 husky
npx husky init

执行完毕 script 中会添加一个 husky 命令,根目录会生成 .husky 文件,其中有一个 pre-commit 脚本文件,写入以下内容

npx lint-staged

这件事就是在代码 commit 之前,执行 lint-staged 做一些事情,比如检测代码规范,格式化代码等,接下来就干这个事。

根目录新建 .lintstagedrc

{
  "packages/**/*.{js,jsx,ts,tsx}": ["eslint --fix --cache", "prettier --write"],
  "packages/**/package.json": ["prettier --write"],
  "packages/**/*.{css,less}": ["stylelint --fix --cache", "prettier --write"],
  "**/*.md": ["prettier --write"]
}

内容应该都能看得懂,就是匹配到的文件执行相应的命令

commitlint 集成

pnpm i @commitlint/cli @commitlint/config-conventional -D -w

根目录新建 commitlint.config.js

module.exports = {
  ignores: [(commit) => commit.includes('init')],
  extends: ['@commitlint/config-conventional'],
};

.husky 文件夹下新建 commit-msg

npx --no-install commitlint --edit $1

测试集成是否正常工作

我们把 lint-staged 和 commitlint 准备工作都完成了,如何测试呢?

首先测试 lint-staged,即写一段被 eslint 警告的代码进行提交:

// pakcgaes/components/src/index.ts

const a = 1; // 'a' is assigned a value but never used.

然后执行 commit(初次执行代码校验时间可能较长)

image

上图可以看到,lint 校验没通过,无法 commit,此时再把 const a = 1; 删除掉,消除 eslint 的报错,再次执行 commit

image

上图可知,这次代码的校验已经通过,但是 commitlint 抛出了错误,提示 commit 信息不规范,此时修改一下再提交

image

此时提交就可以正常通过了,接下来推送到远程仓库即可。

标签:TypeScript,stylelint,Less,React,json,eslint,pnpm,true,prettier
From: https://www.cnblogs.com/jsonq/p/18538403

相关文章

  • 【React Router】基于 react-router-dom 的路由配置与导航详解
    文章目录一、ReactRouter组件概述1.ReactRouter的作用2.主要组件介绍二、ReactRouter的基本使用1.安装与配置2.配置基础路由3.路由重定向三、嵌套路由与布局1.嵌套路由2.带参路由四、路由守卫与重定向1.路由守卫2.路由重定向五、总结React是现......
  • Node.js v22.6.0新特性:支持 TypeScript 直接运行!
    Node.jsv22.6.0版本已经发布,并且带来了一个开发者们期待已久的新特性——直接运行TypeScript(TS)文件的能力!版本更新亮点Node.jsv22.6.0版本通过--experimental-strip-types标志,实现了对TypeScript的实验性支持。这意味着开发者们现在可以在Node.js环境中直接执行......
  • 浅响应式数据(Shallow Reactive 和 Shallow Ref)
    在Vue3中,shallowReactive和shallowRef是用于创建浅响应式数据的工具。它们与普通的reactive和ref不同,只对对象的第一层属性进行响应式处理,而不会递归地使嵌套对象的属性也变成响应式的。shallowReactive问题:当你有一个嵌套较深的对象,并且你只关心对象的第一层属......
  • 如何将下载的mp4视频嵌入react应用程序?
    将下载的mp4视频嵌入React应用程序可以通过以下步骤实现:将下载的mp4视频文件放置在React应用程序的合适位置,例如在public文件夹下创建一个videos文件夹,并将视频文件放置其中。在React组件中引入视频文件,可以使用<video>标签来嵌入视频。在组件的render方法中,可以使用以下代码来......
  • ❤React-JSX语法认识和使用
    1、JSX基本使用​JSX是React的核心JSX是ES的扩展jsx语法->普通的JavaScript代码->babelReact可以使用JSX的前提和原因:React生态系统支持: 脚手架通常用于构建React应用程序,而JSX是React框架的核心语法之一。因此,脚手架默认支持JSX语法,以便更轻松地编写和管理React组件......
  • Serverless GPU:助力 AI 推理加速
    本文整理自2024云栖大会,阿里云智能集团高级技术专家聂大鹏、NVIDIA解决方案架构师金国强演讲议题《ServerlessGPU:助力AI推理加速》近年来,AI技术发展迅猛,企业纷纷寻求将AI能力转化为商业价值,然而,在部署AI模型推理服务时,却遭遇成本高昂、弹性不足及运维复杂等挑战。本文......
  • 无插件H5播放器EasyPlayer.js网页web无插件播放器vue和react详细介绍
    EasyPlayer.jsH5播放器,是一款能够同时支持HTTP、HTTP-FLV、HLS(m3u8)、WS、WEBRTC、FMP4视频直播与视频点播等多种协议,支持H.264、H.265、AAC、G711A、Mp3等多种音视频编码格式,支持MSE、WASM、WebCodec等多种解码方式支持Windows、Linux、Android、iOS全平台终端的H5播放器,使用简单......
  • 构建交互式聊天界面:react-chat-element 实战小计
    react聊天组件库:react-chat-elements需求场景:用户可以通过多元的用户交互方式,如文件、图片、声音以及文字等输入相关信息,AI给出对应的回答react-chat-element介绍react-chat-elements是一个专为React开发者设计的聊天组件库,旨在简化聊天界面的开发过程,适用于构建社交应用、客......
  • 代码整洁之道:在 React 项目中使用 ESLint 的最佳实践
    前言在现代前端开发过程中,保持代码的质量和一致性至关重要。作为一个强大的静态代码分析工具,ESLint能够帮助开发者发现和修复代码中的问题,从而确保代码的可维护性和稳定性。在本文中,我们将探讨在React项目中使用ESLint的最佳实践,涵盖安装、配置、自定义规则以及与其......
  • ReactPress:功能全面的开源发布平台
    ReactPressGithub项目地址:https://github.com/fecommunity/reactpress欢迎Star。此项目是用于构建博客网站的,包含前台展示、管理后台和后端。此项目是基于React+antd+NestJS+NextJS+MySQL的,项目已经开源,项目地址在github上,喜欢的,欢迎给个star。项目地......