当前位置: 首页 > news >正文

vite+react+antd,封装公共组件并发布npm包

一 概述

        为了公司项目系统风格统一,需要对部分公共组件进行封装。此文便是为了记录自己在探索过程中的步骤和注意点。这个例子主要是根据UI设计的样式封装一个antd中的弹窗组件。

二 了解NPM

        NPM(Node Package Manager)是一个 JavaScript 包管理工具,也是 Node.js 的默认包管理器(是 Node.js 自带的包管理工具,只要安装了 Node.js,NPM 就会自动安装在系统中)。

1. 作用

        用于安装、共享和管理项目依赖的代码库(称为“包”或“模块”)。

2. 核心功能

3. 核心文件:package.json

4.重点要求

        package.json中,除了dependencies、devDependencies,还有一个peerDependencies(开发包时候需要用到)。下面是这三者的区别,如下所示:

具体内容如下:

(1)dependencies(生产依赖)

        作用:项目运行时必须的依赖(如 React、ReactDOM、Redux)。

        安装命令:npm install xxxxxx  或 yarn add  xxxxxx

        特点:会被打包到最终的生产环境代码中(如 build/ 目录);安装时递归安装子依赖。

(2)devDependencies(开发依赖)

        作用:仅在开发阶段需要的工具(如测试库、打包工具、ESLint)。

        安装命令:npm install xxxxxx--save-dev  或 yarn add xxxxxx -D

        特点:不会打包到生产代码中;其他项目安装你的包时不会安装这些依赖

(3)peerDependencies(同伴依赖)

        作用:声明你的包需要宿主环境提供的依赖(避免重复安装/版本冲突),常见于 React 组件库。

        安装命令:npm install your -lib   

        特点:

                用户安装你封装的库时,需手动安装 peerDependencies里面的内容,如果版本不匹配,会抛出警告。

如何定义(写入) :

        npm install react --save-peer 

        或 yarn add react --peer  

        或 手动编辑package.json中的peerDependencies 对象

 三  使用vite进行react项目创建。

运行效果如下:

至此,项目文件结构如下如下所示:

四 安装需要使用的依赖和注意事项

        这里组件开发涉及到了 and、less等依赖包,因此需要进行手动安装。 

注意事项:

        这里将antd、react 和react-dom都需要安装在了开发依赖(npm install xxxxxx --save-dev)中。并且也在peerDependencies中手动新增(手动写上去)这几个依赖,dependencies中的依赖跟peerDependencies中的最低版本的依赖包最好相同,如react 在peerDependencies中为>=18.3.1,那么 dependencies 中版本为18.3.1。

        原因:一般正常情况下,react、antd等依赖是需要安装在dependencies中。但是这个程序主要用于npm包的开发,如果写在dependencies中,那么,使用该组件程序中的 antd、react和react-dom的版本必须要和发布包中的antd、react和react-dom的版本一样,否则会报版本冲突的问题。这样就对使用程序限制了相关依赖版本,不太友好。

        所以,在第二大点的第四小点介绍了peerDependencies的意义,这里就需要用到。然后,这里的依赖包版本也不能写死,需要写一个最低可使用版本即可。

        因此,在代码中,我直接删除了package.json 中 dependencies 内容。将dependencies中的react和react-dom  重新安装到devDependencies 中。手动安装的依赖有:

npm install @ant-design/icons --save-dev
npm install antd --save-dev 
npm install react --save-dev  
npm install react-dom --save-dev
npm install less --save-dev
npm install vite-plugin-dts --save-dev

        我的依赖文件如下所示(devDependencies对象里面没内容,package.json会自动删除,或者手动删除也可 ):

五 组件开发

1. 创建组件文件夹

        在src下面新增一个components文件夹,并在里面创建一个自己的组件文件夹:CommonModal,并开始封装自己的组件。目录如下:

2. 创建组件代码

        在index.tsx 里面开发自己的modal组件(如果想边开发边看效果,那么可以先把index.tsx搭一个框架后,根据下一步骤(步骤3)去预览,看到预览效果后过来继续开发,比较好调试)。我封装的弹窗代码如下:

index.tsx

import * as React from 'react';
import {CloseOutlined} from '@ant-design/icons';
import {Modal} from 'antd';
import styles from './index.module.less'export interface CommonModalProps {visible: boolean;title?: string;content?: React.ReactNode;onCancel?: () => void;width?: number;
}export const CommonModal: React.FC<CommonModalProps> = ({visible,title,content,onCancel,width,}) => {return (<Modalopen={visible}closeIcon={false}onCancel={onCancel}maskClosable={false}width={width}centered={true}className={styles.customModal}footer={null}><div className={styles.modalHeader}><span className={styles.title}>{title}</span><CloseOutlined className={styles.close} onClick={onCancel}/></div><div className={styles.modalBody}>{content}</div></Modal>);
};

注意:封装的组件和组件涉及到的ts类型都需要进行export导出

index.module.less

.customModal {:global {.ant-modal-content {padding: 0;border-radius: 4px;overflow: hidden;}}.modalHeader {display: flex;justify-content: space-between;align-items: center;padding: 20px 24px;background: cornflowerblue;.title {color: white;font-weight: 700;font-size: 20px;}.close {cursor: pointer;color: white;font-size: 20px;}}.modalBody {padding: 20px 24px;}}

3. 组件效果预览

        当组件开发了之后,要进行效果预览。这里就可以修改App.tsx里面的代码。App.css 里面的内容不用的话可以删除。不会影响组件的封装,只会影响本地样式。App.css直接为空也可。

        而在App.tsx中,导出写的组件,直接写用法使用即可。我的App.tsx代码如下:

import {useState} from 'react'
import {CommonModal} from "./components/CommonModal";
import {Button} from "antd";function App() {const [visible, setVisible] = useState(false);return (<div><Button type={'primary'} onClick={() => setVisible(true)}>打开弹窗</Button><CommonModal visible={visible} title={'标题'}onCancel={() => setVisible(false)}content={<div>这是一个只展示的弹窗,不会展示确定按钮</div>}/></div>)
}export default App

程序运行后,效果如下:

至此,组要封装的组件就已经完毕,确定组件没问题后,就可以进行npm包的发布了。

六 发布包准备

        进行NPM包的发布,需要对项目部分文件进行调整。

1. 新增包的入口文件

        在src下面新增一个index.ts文件,并在里面导出封装的组件以及需要导出的样式文件。如:

import 'antd/dist/reset.css';
// 导出所有组件
export {CommonModal} from './components/CommonModal';
export type {CommonModalProps} from './components/CommonModal'

2. 新增vite-env.d.ts的内容

declare module '*.module.less' {const classes: { readonly [key: string]: string };export default classes;
}

3.  配置package.json文件

{// 基础信息配置"name": "my-test-lib", // 要发布的包名"private": false,"version": "1.0.0", // 包的版本号(每发布一次,都要修改,否则会发布失败)"type": "module", // 声明项目使用 ES 模块(import/export 语法),而非 CommonJS。// 下面内容是入口文件配置"main": "./dist/index.es.js", // CommonJS/ESM 通用入口:当用户通过 require() 或 import 加载包时,默认指向此文件"module": "./dist/index.es.js", // ES 模块专用入口:支持 ESM 的打包工具(如 Webpack、Rollup)会优先使用此路径,实现 Tree Shaking 优化"types": "./dist/index.d.ts", // TypeScript 类型声明文件,提供类型支持(由 vite-plugin-dts 生成)"style": "dist/style.css", // 全局样式入口,用户可通过 import 'wxf-component-library/style' 引入全量 CSS。// 下面是发布配置"files": ["dist"], // 发布到 npm 时仅包含 dist 目录(构建后的代码、类型声明和样式),忽略源码和非必要文件。"scripts": {"dev": "vite","build": "vite build","lint": "eslint .","preview": "vite preview","prepublishOnly": "npm run build" // 在npm publish 前自动执行构建,确保发布的是最新产物},"peerDependencies": {"antd": ">=5.24.1","react": ">=18.3.1","react-dom": ">=18.3.1"},"devDependencies": {"@ant-design/icons": "^6.0.0","@eslint/js": "^9.33.0","@types/react": "^19.1.10","@types/react-dom": "^19.1.7","@vitejs/plugin-react": "^5.0.0","antd": "^5.24.1","eslint": "^9.33.0","eslint-plugin-react-hooks": "^5.2.0","eslint-plugin-react-refresh": "^0.4.20","globals": "^16.3.0","less": "^4.4.0","react": "^18.3.1","react-dom": "^18.3.1","typescript": "~5.8.3","typescript-eslint": "^8.39.1","vite": "^7.1.2"}
}

4. 修改 tsconfig.json 文件

{"compilerOptions": {"allowImportingTsExtensions": true, // 允许在导入语句中使用 TypeScript 特有的扩展名(如 .ts, .tsx)"noEmit": true,"declaration": true, // 生成 .d.ts 类型声明文件(即使 noEmit=true 也生效)、使组件库支持 TypeScript 类型提示"declarationMap": true, // 为声明文件生成 Source Maps(.d.ts.map)、允许用户 "跳转到定义" 时直接查看源码而非声明文件
//    "outDir": "./dist", // 输出目录(当有文件生成时)
//    "declarationDir": "./dist", // 声明文件的专用输出目录"jsx": "react-jsx", // 使用 React 17+ 的新 JSX 转换"jsxImportSource": "react", // 指定 JSX 函数的导入来源为 react"esModuleInterop": true, // 改进 ES 模块与 CommonJS 的互操作性,允许 import React from 'react' 代替 import * as React from 'react'"skipLibCheck": true, // 跳过声明文件(.d.ts)的类型检查"moduleResolution": "node" // 使用 Node.js 风格的模块解析策略},"include": ["src/**/*"], // 仅编译 src 目录下的所有文件"exclude": ["node_modules", "dist"] // 排除 node_modules 和 dist 目录
}

5. 修改vite.config.ts文件

import {defineConfig} from 'vite'
import react from '@vitejs/plugin-react'
import {resolve} from 'path'
import dts from "vite-plugin-dts";export default defineConfig({plugins: [react(),dts({outDir: './dist',insertTypesEntry: true, // 生成类型入口include: ['src/**/*'],// 包含所有源文件// 添加路径解析配置compilerOptions: {allowImportingTsExtensions: true}})],resolve: {// 确保 Vite 能解析 .tsx 文件extensions: ['.tsx', '.ts', '.js', '.jsx']},build: {lib: {entry: resolve('./src/index.ts'), // 组件库入口name: 'MyTestLib', // 全局变量名fileName: (format) => `index.${format}.js`},rollupOptions: {// 外部化依赖,避免打包进库external: ['react', 'react-dom', 'antd', '@ant-design/icons', 'react/jsx-runtime'],output: {globals: {react: 'React','react-dom': 'ReactDOM',antd: 'antd','@ant-design/icons': 'icons','react/jsx-runtime': 'jsxRuntime'},preserveModules: false}},cssCodeSplit: true,// sourcemap: true,sourcemap: process.env.NODE_ENV !== 'production',minify: false},css: {preprocessorOptions: {less: {javascriptEnabled: true}}}
})

6. 文件结构如下

7. 发布打包测试

        这里先进行发布前的打包测试。运行npm run build 。如果成功了,可以出现一个dist文件夹,里面有相关内容如下:

8. README.md

        对于要发布的包,可以完善 README.md 文件,使用户可以更好的了解该组件以及其使用方式。示例如下:

七 开始发布

        如果上面dist文件准确,则就可以进行npm发布了。步骤如下:

1. npm账号登录

        发布包需要先登录npm账号,如果没有登录,会报403错误(报错后,点击提示信息中的登录网址也可以进行登录)。

(1)输入 npm login ,控制台会提示在浏览器进行登录,并赋予登录链接。

(2)点击链接,跳转浏览器登录

如果有账号,直接从邮箱里面获取一次性密码登录即可。如果没有,需要注册再登录。

如果登录成功,浏览器会显示:

并且控制台也会显示已登录字样

2. 开始发布

        账号登录后,在该项目目录下运行npm publish 命令。

       我这里首次发布报错 403,原因是:npm库已经有 my-test-lib 这个包了。所以继续发布是有问题的。因此需要改一下package.json和vite.config.ts 中的name,使包名唯一(无论该包是否被废弃还是有效)

        所以,我把包名改为了 teach-test-lib ,继续进行发布。就发布成功了。

发布成功后,在网页上登录自己的npm,会在上面看到已经发布的包。

3. 使用

        发布包的使用方式跟npm上其他包的使用方式相同。直接使用npm或yarn安装即可。

        注意:这里需要手动引入包的css样式。例子如下:

import { useState} from 'react';
import {Button} from 'antd'
import {CommonModal} from "teach-test-lib"; // 导入包
import "teach-test-lib/dist/index.css"; // 手动引入CSS样式export default function Login() {const [visible, setVisible] = useState(false);return (<div  ><Button type={"primary"} onClick={() => setVisible(true)}>打开弹窗</Button><CommonModal visible={visible} title={"标题"}onCancel={() => setVisible(false)}content={<div>这是引入的测试内容</div>}/></div>);
}

4. npm 包相关的其他命令

5. 发布403问题及解决方法

(1) 未登录:点击提示信息中的登录地址登录;

(2) 邮箱未验证:登录 npm 官网验证邮箱 ;

(3)包名已被占用 :用 npm view <包名> 检查,修改 package.json 中的 name;

(4)镜像源非官方(可能是自己的私服):切换回官方源:npm config set registry https://registry.npmjs.org;

(5) 版本号冲突:报错You cannot publish over previously published versions,去修改版本号(不可重复)即可。

http://www.dtcms.com/a/336786.html

相关文章:

  • Zookeeper 在 Kafka 中扮演了什么角色?
  • 密码管理中随机数安全修复方案
  • ELF 动态链接安全:揭秘 RUNPATH 与 RPATH 的库劫持风险
  • AI重塑商业格局:从多模态生成到智能应用的2025行业变革与机遇
  • 【完整源码+数据集+部署教程】无人机目标检测系统源码和数据集:改进yolo11-efficientViT
  • 云原生:重塑软件世界的技术浪潮与编程语言选择
  • redis-集成prometheus监控(k8s)
  • GORM入门:事务管理全解析(二)
  • 机器学习的多种算法
  • 网络间的通用语言TCP/IP-网络中的通用规则2
  • 视觉语言导航(14)——VLN ON ROBOTIC 4.4
  • 力扣32:最长有效括号
  • 飞算JavaAI家庭记账系统:从收支记录到财务分析的全流程管理方案
  • 可编辑150页PPT | 某制造集团产业数字化转型规划方案
  • RH134 管理网络安全知识点
  • 多台服务器批量发布arcgisserver服务并缓存切片
  • JVM 内存管理与垃圾回收机制
  • SQL语法大全指南
  • Unity引擎播放HLS自适应码率流媒体视频
  • 实战测试:多模态AI在文档解析、图表分析中的准确率对比
  • 特征工程学习笔记
  • HTML应用指南:利用POST请求获取上海黄金交易所金价数据
  • PYTHON让繁琐的工作自动化-猜数字游戏
  • 万字长文深度解析HTTPS协议
  • 新手向:Java方向讲解
  • 问答社区运营优化:cpolar 提升 Answer 平台远程访问速度方案
  • 【前端面试题】JavaScript 核心知识点解析(第三十一题到第六十一题)
  • 智能汽车领域研发,复用云原生开发范式?
  • 迅速掌握Git通用指令
  • linux 常用代码