vite4+react+antd需要注意的地方,本地svg单独引用

本文主要介绍了在Vite4+React+Antd环境中遇到的less、css、sass不生效的问题及解决方案,以及如何实现本地SVG的动态组件引用。针对less中rgb颜色比例问题和SVG图标引用进行了详细说明。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、less、css、sass不生效问题。

方案1

less或者css,sass需要用到模块化的话,后缀名全部要加上《module》如*.module.less。否则不会生效

js复制代码import styles from './index.module.less';
<div className={styles.oneApp}>生效。

vite.config.ts添加css和less

css: {
    //* css模块化
    modules: {
            // css模块化 文件以.module.[css|less|scss]结尾 
        generateScopedName:'[name]__[local]___[hash:base64:5]',hashPrefix:'prefix',
	 },
	// 预处理器配置项
			preprocessorOptions: {
				less: {
					math: 'always',
					javascriptEnabled: true,
				},
			},
		},

方案2

npm install vite-plugin-style-modules

jsx复制代码import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
import viteCssModule from 'vite-plugin-style-modules';
// 支持ESM和CommonJS两种方式引入
// const viteCssModule = require('vite-plugin-style-modules')

export default defineConfig({
  plugins: [react(), viteCssModule()],
});

二、本地动态svg。

vite-plugin-svgr

安装依赖 "vite-plugin-svgr": "^3.2.0", vite.config.ts添加svgr()

js复制代码import svgr from 'vite-plugin-svgr';
plugins: [react(), svgr()]

tsconfig.json的compilerOptions加入属性

js复制代码"compilerOptions": {
		"types": ["vite-plugin-svgr/client"],

渲染组件

jsx复制代码// 动态渲染图标
const IconRender: React.FC<{
	icon: string;
	className?: string;
}> = ({ icon, ...restIconProps }) => {
	if (typeof icon !== 'string') return null; // 图标名称类型必定为string
	const allIcons: any = import.meta.glob('/plugins/icons/svg/*/*.svg', { eager: true });
	const Icon = allIcons[`/plugins/icons/svg/filled/${icon}.svg`].ReactComponent || null;
	return <Icon {...restIconProps} />;
};
jsx复制代码<IconRender
icon={item.icon}
className={cn(styles.oneItemIcon, styles.menuIcon)}/>

其中,menuIcon的样式,注意:menuIcon里面一定要有fill:currentColor,颜色才会生效

less复制代码.oneItemIcon {
			font-size: 16px;
			vertical-align: top;
		}
		.menuIcon {
			display: inline-block;
			fill: currentColor;
			color: inherit;
			font-style: normal;
			line-height: 0;
			text-align: center;
			text-transform: none;
			vertical-align: -0.125em;
			text-rendering: optimizeLegibility;
			-webkit-font-smoothing: antialiased;
			width: 1em;
			height: 1em;
		}

SVG动态组件引用,vite每个本地svg可单独引用。

之前umi系统里面的用法:

javascript复制代码import {
  CaretDownOutlined,
  LeftOutlined,
  QaWenjianquanxiankongzhiOutlined,
  QaXiazairizhiOutlined
} from "@@/plugin-icons";

按照上面的动态svg的步骤完成后。执行如下步骤 1、在更目录建一个plugins文件夹,里面再建个icons文件夹,如下

image.png

 

createIndex.js是脚本文件,用来执行js脚本。 index.source.tsx就是导出svg的js原参考代码。 index.tsx是通过执行脚本createIndex.js生成的文件。 createIndex.js如下

ini复制代码// 引入核心模块(fs)
import fs from 'fs';
import path from 'path';
// API
let fileContent = `//本文件采用命令生成,不要手动修改,具体查看createIndex.js,执行命令:yarn buildLocalIcons
const allIcons: any = import.meta.glob('/plugins/icons/svg/*/*.svg', { eager: true });
// 匹配到的首字母或斜杠字母转为大写
const toUpperCase = (match: string) => match?.replace('-', '').toUpperCase();
const iconList: any = {};
Object.keys(allIcons).forEach((key) => {
	const arr = key.split('/');
	const name = arr[arr.length - 1].split('.')[0];
	// 用正则匹配转化单词,转化后加上风格
	const suffix = key.indexOf('/filled/') > -1 ? 'Filled' : 'Outlined';
	const iconKey = name.replace(/(^[a-z]|\-[a-z])/g, (match) => toUpperCase(match)) + suffix;
	const Icon = allIcons[key].ReactComponent || null;
	iconList[iconKey] = Icon;
});
export default iconList;
`
// 匹配到的首字母或斜杠字母转为大写
const toUpperCase = (match) => match?.replace('-', '').toUpperCase();
function walkSync (currentDirPath, callback) {
	fs.readdirSync(currentDirPath, { withFileTypes: true }).forEach(function (dirent) {
		var filePath = path.join(currentDirPath, dirent.name);
		if (dirent.isFile()) {
			callback(filePath, dirent);
		} else if (dirent.isDirectory()) {
			walkSync(filePath, callback);
		}
	});
}

const files = []
walkSync('./plugins/icons/svg/', function (filePath, stat) {
	files.push(filePath)
});
const iconNames = []
files.forEach((key) => {
	if (key.indexOf('.svg') > -1) {
		const arr = key.split('/');
		const name = arr[arr.length - 1].split('.')[0];
		// 用正则匹配转化单词,转化后加上风格
		const suffix = key.indexOf('/filled/') > -1 ? 'Filled' : 'Outlined';
		const iconKey = name.replace(/(^[a-z]|\-[a-z])/g, (match) => toUpperCase(match)) + suffix;
		iconNames.push(iconKey)
	}
})
iconNames.forEach((key) => {
	fileContent += `export const ${key} = iconList['${key}'];\n`
})

fs.writeFile('./plugins/icons/index.tsx', fileContent, (error) => {
	// 创建失败
	if (error) {
		console.log('\x1B[31m%s\x1B[0m', `创建失败:${error}`);
	}
	// 创建成功
	console.log('\x1B[36m%s\x1B[0m', '创建本地Icons成功!');
});



index.tsx如下,index.source.tsx的内和下面一样,就是少了export default iconList;后面的代码。

ini复制代码//本文件采用命令生成,不要手动修改,具体查看createIndex.js,执行命令:yarn buildLocalIcons
const allIcons: any = import.meta.glob('/plugins/icons/svg/*/*.svg', { eager: true });
// 匹配到的首字母或斜杠字母转为大写
const toUpperCase = (match: string) => match?.replace('-', '').toUpperCase();
const iconList: any = {};
Object.keys(allIcons).forEach((key) => {
	const arr = key.split('/');
	const name = arr[arr.length - 1].split('.')[0];
	// 用正则匹配转化单词,转化后加上风格
	const suffix = key.indexOf('/filled/') > -1 ? 'Filled' : 'Outlined';
	const iconKey = name.replace(/(^[a-z]|-[a-z])/g, (match) => toUpperCase(match)) + suffix;
	const Icon = allIcons[key].ReactComponent || null;
	iconList[iconKey] = Icon;
});
export default iconList;
export const AntShopFilled = iconList['AntShopFilled'];
export const BasicFilled = iconList['BasicFilled'];
export const CallFilled = iconList['CallFilled'];
export const CardFilled = iconList['CardFilled'];
export const CloseFilled = iconList['CloseFilled'];
export const CmsFilled = iconList['CmsFilled'];
export const DashboardFilled = iconList['DashboardFilled'];
export const DownloadFilled = iconList['DownloadFilled'];
export const DsFilled = iconList['DsFilled'];
export const EmailFilled = iconList['EmailFilled'];
export const MenuFilled = iconList['MenuFilled'];
export const NsShopguideFillFilled = iconList['NsShopguideFillFilled'];
export const QaBiaoqianxinxiFilled = iconList['QaBiaoqianxinxiFilled'];
export const QaCuxiaohuodongFilled = iconList['QaCuxiaohuodongFilled'];
export const QaDingdanxinxiFilled = iconList['QaDingdanxinxiFilled'];
export const QaJifentixiFilled = iconList['QaJifentixiFilled'];
export const QaShangpinshezhiFilled = iconList['QaShangpinshezhiFilled'];
export const QaShangpinshujuFilled = iconList['QaShangpinshujuFilled'];
export const QaViptixiFilled = iconList['QaViptixiFilled'];
export const QaYonghuxinxiFilled = iconList['QaYonghuxinxiFilled'];
export const SendFilled = iconList['SendFilled'];
export const ShoujiguanliyuanFilled = iconList['ShoujiguanliyuanFilled'];
export const SmsFilled = iconList['SmsFilled'];
export const VmsFilled = iconList['VmsFilled'];
export const XiadanguanhuaiFilled = iconList['XiadanguanhuaiFilled'];
export const YsFilled = iconList['YsFilled'];
export const AntShopOutlined = iconList['AntShopOutlined'];
export const ApiOutlined = iconList['ApiOutlined'];
export const CaretDownOutlined = iconList['CaretDownOutlined'];
export const CloseOutlined = iconList['CloseOutlined'];
export const DangerSelectOutlined = iconList['DangerSelectOutlined'];
export const DashboardOutlined = iconList['DashboardOutlined'];
export const DateSelectOutlined = iconList['DateSelectOutlined'];
export const DateSetOutlined = iconList['DateSetOutlined'];
export const DateOutlined = iconList['DateOutlined'];
export const DeleteOutlined = iconList['DeleteOutlined'];
export const DeletesOutlined = iconList['DeletesOutlined'];
export const DetailgegevensOutlined = iconList['DetailgegevensOutlined'];
export const DownOutlined = iconList['DownOutlined'];
export const DragOutlined = iconList['DragOutlined'];
export const DsOutlined = iconList['DsOutlined'];
export const EditOutlined = iconList['EditOutlined'];
export const FieldOutlined = iconList['FieldOutlined'];
export const FiltersOutlined = iconList['FiltersOutlined'];
export const FundOutlined = iconList['FundOutlined'];
export const GroupingOutlined = iconList['GroupingOutlined'];
export const HomeOutlined = iconList['HomeOutlined'];
export const LeftOutlined = iconList['LeftOutlined'];
export const MenuOutlined = iconList['MenuOutlined'];
export const NsArrowDoubledownOutlined = iconList['NsArrowDoubledownOutlined'];
export const NsArrowDoubleleftOutlined = iconList['NsArrowDoubleleftOutlined'];
export const NsArrowDoublerightOutlined = iconList['NsArrowDoublerightOutlined'];
export const NsArrowDoubleupOutlined = iconList['NsArrowDoubleupOutlined'];
export const NsFileExcelnumberOutlined = iconList['NsFileExcelnumberOutlined'];
export const NsFilePictureOutlined = iconList['NsFilePictureOutlined'];
export const NsFileWorddefaultOutlined = iconList['NsFileWorddefaultOutlined'];
export const NsHelpOutlined = iconList['NsHelpOutlined'];
export const NsMoneyOutlined = iconList['NsMoneyOutlined'];
export const NsPeopleOutlined = iconList['NsPeopleOutlined'];
export const NsPicDefeatedOutlined = iconList['NsPicDefeatedOutlined'];
export const NsServiceOutlined = iconList['NsServiceOutlined'];
export const NsTimeOutlined = iconList['NsTimeOutlined'];
export const NumberOutlined = iconList['NumberOutlined'];
export const ProjectOutlined = iconList['ProjectOutlined'];
export const QaBackOutlined = iconList['QaBackOutlined'];
export const QaBrandArrowOutlined = iconList['QaBrandArrowOutlined'];
export const QaCaidanOutlined = iconList['QaCaidanOutlined'];
export const QaMoreOutlined = iconList['QaMoreOutlined'];
export const QaSettingOutlined = iconList['QaSettingOutlined'];
export const QitaOutlined = iconList['QitaOutlined'];
export const RightOutlined = iconList['RightOutlined'];
export const SaveOutlined = iconList['SaveOutlined'];
export const SettingOutlined = iconList['SettingOutlined'];
export const ShezhiOutlined = iconList['ShezhiOutlined'];
export const TextOutlined = iconList['TextOutlined'];
export const UpOutlined = iconList['UpOutlined'];
export const VolcanoBackOutlined = iconList['VolcanoBackOutlined'];
export const VolcanoCaretDownOutlined = iconList['VolcanoCaretDownOutlined'];

执行项目前先把本地的icon生成下,svg新增变动都要重新执行命令

json复制代码"dev": " yarn buildLocalIcons && vite --force --mode development",
"build": "yarn buildLocalIcons && vite build --mode production",
"buildLocalIcons": "node ./plugins/icons/createIndex.js",

less相关,rgb(0 0 0 / 25%)问题

vite.config.ts

css复制代码css:{
    devSourcemap: true,
    preprocessorOptions:{
        less: {
            // math: 'always',//如果开启always会把less里面的rgb(0 0 0 / 25%)变黑色
            javascriptEnabled: true,
        },
    }
}
    ```

 

{ "name": "@labelu/frontend", "version": "5.8.11", "private": true, "dependencies": { "@ant-design/icons": "^4.6.2", "@labelu/i18n": "1.0.6", "@labelu/audio-annotator-react": "1.8.6", "@labelu/components-react": "1.7.11", "@labelu/image": "1.4.0", "@labelu/formatter": "1.0.2", "@labelu/image-annotator-react": "2.4.6", "@labelu/interface": "1.3.1", "@labelu/video-annotator-react": "1.4.12", "@labelu/video-react": "1.5.3", "@tanstack/react-query": "^5.0.0", "antd": "5.10.1", "axios": "^1.3.4", "classnames": "^2.3.2", "history": "^5.0.0", "iframe-message-bridge": "1.1.1", "lodash": "^4.17.21", "lodash-es": "^4.17.21", "mockjs": "^1.1.0", "react": "^18.2.0", "react-document-title": "^2.0.3", "react-dom": "^18.2.0", "react-hotkeys-hook": "^4.4.1", "react-i18next": "^11.18.6", "react-intl": "^5.24.7", "react-intl-universal": "^2.6.11", "react-monaco-editor": "^0.50.1", "react-responsive": "^9.0.2", "react-router": "^6.8.2", "react-router-dom": "^6.8.2", "styled-components": "^5.3.6", "uuid": "^9.0.0" }, "scripts": { "postinstall": "node ./scripts/generate_css_variables_from_antd_theme_token.js", "start": "vite --port 3004", "preview": "vite preview --port 3007", "build": "cross-env CI=false npm --filter=./packages/* --filter=. run build", "package:dist": "cross-env DIST=true vite", "release": "semantic-release", "type-check": "tsc --noEmit", "openapi": "ts-node openapi.config.ts" }, "author": "wuhui", "keywords": [ "annotation", "canvas", "react" ], "homepage": "/", "bugs": { "url": "https://github.com/opendatalab/labelU.git", "email": "751569801@qq.com" }, "browserslist": { "production": [ ">0.2%", "not dead", "not op_mini all" ], "development": [ "last 1 chrome version", "last 1 firefox version", "last 1 safari version" ] }, "devDependencies": { "@octokit/rest": "^19.0.7", "@semantic-release/commit-analyzer": "^9.0.2", "@semantic-release/exec": "^6.0.3", "@semantic-release/git": "^10.0.1", "@semantic-release/github": "^8.0.7", "@semantic-release/release-notes-generator": "^10.0.3", "@testing-library/jest-dom": "^5.11.4", "@testing-library/react": "^11.1.0", "@testing-library/user-event": "^12.1.10", "@types/http-proxy-middleware": "^0.19.3", "@types/jest": "^26.0.15", "@types/lodash": "^4.14.191", "@types/lodash-es": "^4.17.6", "@types/mockjs": "^1.0.2", "@types/node": "^12.20.55", "@types/react": "^18.0.28", "@types/react-document-title": "^2.0.5", "@types/react-dom": "^18.0.11", "@types/recharts": "^1.8.13", "@types/rx": "^4.1.2", "@types/styled-components": "^5.1.26", "@types/uuid": "^9.0.0", "@vitejs/plugin-react": "^3.1.0", "analyze-wiz": "^1.2.0-beta.2", "cross-env": "^7.0.3", "json-schema-library": "^9.1.2", "minimist": "^1.2.7", "prettier": "^2.0.1", "sass": "^1.56.1", "semantic-release": "^19.0.3", "semantic-release-github-pullrequest": "^1.3.0", "shelljs": "^0.8.5", "simple-progress-webpack-plugin": "^2.0.0", "terser-webpack-plugin": "^4.2.3", "typescript": "4.8.4", "vite": "^4.1.1", "vite-plugin-ejs": "^1.6.4", "vite-plugin-imp": "^2.3.1", "vite-plugin-svg-icons": "^2.0.1", "vite-plugin-svgr": "^2.4.0", "vite-plugin-ts-mono-alias": "^1.1.8" } } 我想把@labelu开头的依赖都都通过packages里面的包安装
05-21
### 解决方案:仅安装以 `@labelu` 开头的依赖项并从本地 `packages` 文件夹解析 为了实现这一目标,可以通过以下方式配置项目环境,确保 `npm install` 只处理指定前缀的依赖项,并优先从本地路径加载模块。 #### 方法一:利用 `overrides` 配置限定范围 自 NPM v8.3.0 起引入了 `overrides` 功能,允许开发者覆盖默认的依赖解析逻辑。可以在 `package.json` 中定义规则,使得所有以 `@labelu` 开头的包指向本地目录下的对应位置: ```json { "dependencies": { "@labelu/core": "^1.0.0", "@labelu/plugin-a": "^2.0.0" }, "overrides": { "@labelu/*": "./packages/@labelu/*" } } ``` 这里的关键在于 `"@labelu/*"` 这种通配符形式,它表示匹配任意带有该命名空间的包名,并将其映射到相对路径下的具体实现[^4]。 随后只需正常执行标准流程即可生效: ```bash npm install ``` 注意这种方式不会改变全局行为,仅仅作用于当前上下文中声明的内容。 #### 方法二:借助工作区特性(Workspaces) 如果整个工程已经采用了 monorepo 架构设计,则更推荐启用内置的工作区支持机制。通过预先设定好共享布局结构后,能够简化跨子模块间的相互引用过程。 编辑根级别的 `package.json` 添加如下字段: ```json { "workspaces": [ "packages/*" ] } ``` 接着调整各个独立组件对应的描述文件,保持原有的依赖声明不变。最后一步也是简单调用通用命令完成初始化动作: ```bash npm install ``` 此时系统会自动识别属于同一顶层集合成员的身份标签,进而按照预设好的关联关系建立起正确的链接连接[^5]。 另外值得注意的是,当采用这种方法时,默认只会拉取必要的部分而非全部内容,正好满足题目里提出的条件限制。 --- ### 示例代码片段展示最终形态 假设存在这样一个简单的例子用于验证效果: **目录结构** ``` my-monorepo/ ├── packages/ │ ├── @labelu/core/ │ │ └── package.json {"name":"@labelu/core","version":"1.0.0"} │ └── @labelu/plugin-a/ │ └── package.json {"name":"@labelu/plugin-a","version":"2.0.0"} └── app/ └── package.json { "name": "app", "version": "1.0.0", "dependencies": { "@labelu/core": "*", "@labelu/plugin-a": "*" } } ``` 运行结果应该是成功找到两个局部定义的服务单元作为组成部分加入进来。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值