您的位置 首页 > 新农资讯

vue3项目搭建,vue3.3+vite4.x+typecript+idux带你从0到1打造企业级项目

@idux是我们基于vue3开发开发的开源组件库,提供完整的类型定义、灵活的全局配置、深度的主题定制能力、国际语言支持。 相关链接:Github: IDuxFE/idux官方文档: idux.site 有兴趣的朋友请尝试使用,我们会一直维护的~

简介本文向您展示如何基于vue3.3+vite4.x+ts+@idux开发一套符合企业级规范的项目。

包管理模式:pnpm Monorepo 框架:vue3.3 工程:vite4.x + rollup 语言:ts + tsx 组件库:@iduxcss:less+postcss 请求库:axios 状态管理:pinia one-side:vitest 代码规范:eslint + prettier + stylelint 发送规范:husky+lint-staged+commitlint 我们直接开始吧。

准备环境在开始之前,我们建议您使用以下开发环境。

vscodepnpm=8.xnode=12.xchrome 浏览器vue-devtools初始化使用pnpm创建项目

当您输入pnpm create vite 命令时,系统会要求您输入项目的名称。选择vue和ts,项目就创建成功了。

输入您的项目目录并运行pnpm install 以安装依赖项。

输入pnpm run dev 项目:

当你看到这个界面时,你就知道你的项目已经成功初始化了。

对于CSS 工程,请通过删除项目中不必要的代码并仅保留App.vue 来确保您的项目干净。

添加更少的脚本。

此时会报错,这是正常的,因为你还没有安装less。

安装更少的依赖项。

pnpm add less 将再次启动,样式将生效。

我会尝试变量和嵌套样式,没问题。

如果您想引入全局样式文件怎么办?例如,将@color 添加到您的style.less 文件中。

有两种解决方案。

1.如果在style标签内部引入style.less文件,如果是特定Vue组件的特定变量没有问题,但如果是全局变量或样式,则无法使用@一一导入进口。

2. 配置preprocessorOptions Vite 提供了preprocessorOptions 配置,可以让您自动将style.less 文件引入样式标签或.less 文件中。

//vite.config.tsimport {defineConfig,normalizePath} from 'vite'import vue from '@vitejs/plugin-vue'//可以安装@types/node来解决导入路径'path'的类型错误;//使用normalizePath 来解决这个问题。 windows下路径问题const variablePath=NormalizePath(path.resolve('./src/style.less'));//https://vitejs.dev/config/export default DefineConfig({ plugins: [vue()], css: { preprocessorOptions: {less: {AdditionalData: `@import '${variablePath}';` } } }}) 安装@types/node 以解决路径模块中的类型错误

复制pnpm add @types/node -D 代码。 pnpm add @types/node -D Postcss 的使用通常通过postcss.config.js 文件进行配置,但Vite 提供了相关的配置条目。您可以直接在vite.config.ts 中操作它。安装一个名为autoprefixer 的通用插件来解决浏览器兼容性问题。

pnpm add autoprefixer -D 在vite.config.ts 中配置。

//vite.config.tsimport autoprefixer from 'autoprefixer';export default { css: { postcss: { plugins: [ autoprefixer({ //指定目标浏览器overrideBrowserslist: [' 1%', 'last 2 name'] }) ] } }}Let's尝试一些新语法。

.demo { -text { color: @color; text-decoration: dashed line }} 当您运行pnpm run build 时,您将看到产品自动在样式之前添加了前缀。

以上就是CSS工程的内容。

代码规范1.安装Eslint eslint

pnpm add eslint -D 运行npx eslint --init 初始化

在该步骤结束时,系统会询问您是否要立即安装上述依赖项,但我们建议使用pnpm 进行默认安装。

pnpm add @typescript-eslint/eslint-plugin@latest eslint-plugin-vue@latest @typescript-eslint/parser@latest -D 请注意,我理解项目在初始化后自动创建了一个新的.eslintrc.cjs 文件。

//.eslintrc.cjsmodule.exports={ 'env': { '浏览器': true, 'es2021': true }, 'extends': [ 'eslint:推荐', 'plugin:@typescript-eslint/推荐',/vue3- Essential' ], 'overrides': [ { 'env': { 'node': true }, 'files': [ '.eslintrc.{js,cjs}' ], 'parserOptions': { 'sourceType': 'script ' } } ], 'parserOptions': { 'ecmaVersion': '最新', '解析器': '@typescript-eslint/parser', 'sourceType': '模块' }, '插件': [ '@typescript -eslint ', 'vue' ], 'rules': { 'linebreak-style': [ 'error', 'unix' ], 'quotes': [ 'error', 'double' ], 'semi': [ 'error' , '总是'] }}我将解释上面的要点。 parserOptions 表示启用最新的es 语法,sourceType: module 表示使用ES 模块解析器。 /parserESLint 默认使用Espree 进行AST 解析。这个解析器目前是基于Acron实现的,但是由于Acron还不支持TypeScript,所以需要一个处理器来完成解析。 T.S.社区提供了专为TypeScript 解析设计的@typescript-eslint/parser 解决方案。它将TS 代码转换为Espree 理解的格式(即Estree 格式),并通过Espree 进行格式检查以确保兼容性。TypeScript 语法。 plugins插件使用@typescript-eslint/eslint-plugin(可以简写为@typescript-eslint)来扩展TS代码规则,而vue插件则专门针对Vue代码。

2. 一旦Prettier 学会了eslint,你就需要安装Prettier 来格式化你的代码,但eslint 的主要好处是它会检查并提示你代码风格。 Eslint + Prettier 组合经常被企业用来限制代码规范并安装Prettier。

pnpm add prettier -D 在根目录下新建.prettierrc.cjs配置文件,输入以下配置内容:

//.prettierrc.cjsmodule.exports={ printWidth: 80, //如果超过该行的字符数则换行。默认为80 tabWidth: 2, //一个tab代表空格数。 is 2 useTabs: false, //是否使用制表符缩进,默认为false,即使用空格收缩singleQuote: true, //字符串是否使用单引号,默认为false semi: true, //行尾加分号,默认为true TrailingComma: 'none ', //是否使用尾随逗号bracketSpacing: true //对象的大括号中是否直接有空格,默认为true,则需要集成Prettier。添加到现有的Eslint 工具并安装这两个软件包。

pnpm i eslint-config-prettier eslint-plugin-prettier -D 其中eslint-config-prettier 用于覆盖ESLint 自己的规则配置,并且eslint-plugin-prettier 继承eslint --fix 到Prettier 用于。修复代码的能力。在.eslintrc.js 配置文件中访问更好的相关工具链。

//.eslintrc.cjsmodule.exports={ 'env': { '浏览器': true, 'es2021': true }, 'extends': [ 'eslint:推荐', 'plugin:@typescript-eslint/推荐',/vue3- Essential', //1. prettier 规则'prettier', 'plugin:prettier/推荐' ], 'overrides': [ { 'env': { 'node': true }, 'files': [ {js,cjs} '], 'parserOptions': { 'sourceType': '脚本' } } ], 'parserOptions': { 'ecmaVersion': '最新', '解析器': '@typescript-eslint/parser', 'sourceType': ' module' }, 'plugins': [ '@typescript-eslint', 'vue', //2. 添加prettier 的eslint 插件'prettier' ], 'rules': { //3. 注意prettier 的表示需要添加此语句启用自动修复功能: 'prettier/prettier': 'error', 'linebreak-style': [ 'error', 'unix' ], 'quotes ': [ 'error', 'double ' ], 'semi': [ 'error', 'always' ] }}在package.json 文件中定义脚本

//package.json{ 'scripts': { //省略现有脚本'lint:script': 'eslint --ext .js,ts,vue --fix --quiet ./src', }}下一步运行尝试命令查看效果

运行pnpm lint: 脚本

根据错误信息,不允许使用单引号。这是因为您在.prettierrc.cjs 中设置了单引号,并在初始化eslint 时选择了双引号。规则需要修正

//.eslintrc.cjs{ 'rules': { 'quotes': [ 'error', 'single' ], }} 再次运行该命令。此时验证成功,没有报错。

有关如何配置规则的信息,请参阅Eslint 规则文档。我这里就不详细说了。 然而,每次都运行这个命令有点乏味。在VSCode中安装ESLint和Prettier这两个插件,并在设置区域中开启Format On Save:

将main.ts 中的单引号更改为双引号。

此时按Ctrl+S保存,代码会自动格式化为单引号。这意味着Vscode 插件会根据.eslintrc.cjs 和.prettierrc 自动格式化您的代码。 cjs。

有同学说Ctrl+S不允许他们自动格式化。您可以将此设置添加到settings.json 配置文件中。第:章第:章第:章

除了安装编辑器插件外,您还可以在开发阶段使用Vite插件进行ESLint扫描,通过命令行查看代码中的规范问题,并直接查找原始文件。

使用pnpm add vite-plugin-eslint -D vite.config.ts 配置

//vite.config.ts从'vite-plugin-eslint'导入viteEslint;{ plugins: [ viteEslint(), ]}

3. StylelintStylelint 专门用于检查样式代码规范并安装相关依赖项。

pnpm add stylelint stylelint-prettier stylelint-config-prettier stylelint-config-recess-order stylelint-config-standard stylelint-config-standard-less -D 在根目录创建.stylelintrc.cjs

//.stylelintrc.jsmodule.exports={ //为stylelint 注册prettier 插件plugins: ['stylelint-prettier'], //继承一组规则集extends: [ //标准规则集'stylelint-config-standard' , //Lower标准规则集的版本'stylelint-config-standard-less', //样式属性顺序规则'stylelint-config-recess-order', //访问Prettier 规则'stylelint-config-prettier', ' stylelint-prettier /推荐'], //设置规则rules: { //启用Prettier自动格式化功能'prettier/prettier': true }} 然后将相应的脚本放入你的package.json文件中添加。

//package.json{ 'scripts': { //集成lint 命令'lint': 'npm run lint:script npm run lint:style', //stylelint 命令'lint:style': 'stylelint --fix \'src/**/*当我运行.{css,less,vue}\'' }}pnpm run lint:style 时,我收到警告提示

这是因为stylelint 默认情况下仅验证.css 文件,但如果您还想验证.vue 文件中的样式代码,则需要安装支持vue 的额外插件。

pnpm 添加stylelint-config-recommended-vue postcss-html postcss-less -D 在.stylelintrc.cjs 中配置

//.stylelintrc.cjs{ extends: [ //忽略其他//vue 规则'stylelint-config-recommended-vue' ], overrides: [ { files: ['**/*.{html,vue}'],customSyntax: 'postcss -html' }, { files: ['**/*.less'],customSyntax: 'postcss-less' } ]}再次运行pnpn run lint:style。目前不会报告更多错误或警告。

与eslint 类似,stylelint 也有相同的vite 插件

pnpm add vite-plugin-stylelint -D 添加到vite.config.ts

//vite.config.tsimport viteStylelint from 'vite-plugin-stylelint';{ plugins: [ //省略其他插件viteStylelint(), ]}

添加到vite.config.ts 的eslint 和prettier 插件可确保开发或构建期间的代码验证。

eslint 和stylelint 都可以添加忽略特定目录或文件验证的忽略文件。在根目录中创建新的.eslintignore 和.stylelintignore 。

//.eslintignorenode_modulesdistpublicpublishpnpm-lock.yaml

//.stylelintignorenode_modulesdistpublicpublishpnpm-lock.yaml 可以根据自己项目的情况填写。 最后输入pnpm run lint 同时验证js和css。这就是代码规范所说的。

通常,Ctrl+S 允许您自动格式化样式代码,但如果这不起作用,您可以将与eslint 相同的操作添加到settings.json 配置文件中。 正确}

好的,这就是代码规范。

提交规范以上代码规范仅用于在开发阶段主动发现问题,并不保证非标准代码上线。因此,代码推送到远端时必须进行验证。如果您提交的内容不符合规范,您的提交内容将不被接受。社区中已经存在相应的工具——Husky 来完成此任务。

1、初始化git仓库首先要初始化git仓库。之前我删除了Vite默认创建的.git目录,所以我手动重新初始化了它。

git初始化

2.使用husky验证提交代码的安装依赖

pnpm add husky -D 初始化npx husky install 并使用husky install 作为项目前启动脚本。

//package.json{ 'scripts': { //安装npm依赖后自动运行'prepare': 'husky install' }}

添加husky hook 并在终端中运行以下命令:

npx husky 添加.husky/pre-commit 'npm run lint'

当您运行git commit 时,首先执行npm run lint 脚本,并在lint 检查通过后正式提交代码记录。然而,这个操作完全发现了整个项目。这意味着即使没有更改,也不会执行lint 验证,并使用lint 暂存来解决上述完整扫描问题。仅对临时存储中存储的文件进行lint 检查的能力**提高了代码提交的效率。

3. 使用lint-staged 扫描暂存区中的代码。运行pnpm add lint-staged -D,然后将以下配置添加到package.json:

//package.json{ 'script': { //其他省略'lint-staged': 'lint-staged' }, 'lint-staged': { '**/*.{vue,js,ts}' : [ 'eslint --fix' ], '**/*.{vue,css,less}': [ 'stylelint --fix ] }} 接下来,在husky 中应用lint-stage 并将其添加到.husky/我需要回去。在预提交脚本中,将原始npm run lint 替换为以下脚本:

npx --no-install -- lint-staged 通过这种方式,您可以在提交代码时实施增量lint 检查。

4.使用commitlint标准化git提交信息在项目内部标准化提交信息也是非常有必要的。标准化的提交信息有利于团队协作、问题定位和安装依赖性。

pnpm add commitlint @commitlint/cli @commitlint/config-conventional -D 在项目根目录下新建commitlint.config.cjs

//commitlint.config.cjsmodule.exports={ extends: ['@commitlint/config-conventional']};@commitlint/config-conventional 指定提交信息通常由两部分组成:type 和subject To do。

//type指提交类型//subject指提交摘要信息: 常用的type值包括:

feat: 添加新功能。 fix: 修复错误。 Chore: 一些不影响功能的更改。 docs: 特指文档更改。 perf: 性能优化。 refactor: 代码重构。 test: 添加测试代码等将commitlint 功能集成到Husky hooks 中

npx husky add .husky/commit-msg 如果运行“npx --no-install commitlint --edit $1”,您将在.husky 目录中看到一个额外的commit-msg 文件。

让我们提交一个文件并输入不符合commitlint 规范的信息。将出现一条消息,告诉您需要根据您的规格输入。

您必须输入正确的提交才能成功提交。

您还可以使用commitizen 发送git 提交信息。这里我们不做详细介绍,您可以根据项目的需要进行选择。

好的,这就是提交规范的全部内容。

本节介绍静态资源。

要介绍如何在项目引入静态资源,例如图片、视频等。拿图片来说在模板中引入 在style中引入 .logo-img { background: url('./assets/imgs/vite.svg') no-repeat;}以上相对路径的方式,我们更多是通过配置别名,这样不仅可以在script中作为资源引入,更方便了我们的书写,不然你会看到很多地狱路径 background: url('../../../../../assets/imgs/vite.svg') 1、在vite中配置别名// vite.config.tsimport path from 'path';{ resolve: { // 别名配置 alias: { '@assets': path.join(__dirname, './src/assets') } }}在script中引入 // App.vue hello idux 在style中同样使用别名,注意这里就不能继续用img标签了 // App.vue hello idux 效果是一样的,这里就不放图了 2、SVG组件方式加载上面案例用到了svg,业界有很多关于svg的最佳实践,这里介绍一种,把svg作为组件的方式引入。社区中已经有了对应的插件支持Vue3 项目中可以引入 vite-svg-loader pnpm add vite-svg-loader -D在vite中添加插件 // vite.config.tsimport svgLoader from 'vite-svg-loader';{ plugins: [ // 其它插件省略 svgLoader() ]}直接作为组件引入 hello idux 可以看到,目前组件渲染出来的就是一个svg标签 3、生产环境处理在前面的内容中,我们围绕着如何加载静态资源这个问题,在 vite 中进行具体的编码实践,相信对于 vite 中各种静态资源的使用你已经比较熟悉了。但另一方面,在生产环境下,我们又面临着一些新的问题。 部署域名怎么配置?资源打包成单文件还是作为 Base64 格式内联 图片太大了怎么压缩?3.1、自定义部署域名一般在我们访问线上的站点时,站点里面一些静态资源的地址都包含了相应域名的前缀,如: 您的浏览器不支持 video 标签。以上面这个地址例子,https://idux-cdn.sangfor.com.cn是 CDN 地址前缀,/medias/home-banner.mp4则是我们开发阶段使用的路径。那么,我们是不是需要在上线前把图片先上传到 CDN,然后将代码中的地址手动替换成线上地址呢?这样就太麻烦了!在 Vite 中我们可以有更加自动化的方式来实现地址的替换,只需要在配置文件中指定base参数即可: // vite.config.ts// 是否为生产环境,在生产环境一般会注入 NODE_ENV 这个环境变量,见下面的环境变量文件配置const isProduction = process.env.NODE_ENV === 'production';// 填入项目的 CDN 域名地址const CDN_URL = 'https://idux-cdn.sangfor.com.cn';{ base: isProduction CDN_URL : '/'}根目录下新增.env.development和.env.production // .env.developmentNODE_ENV=development// .env.productionNODE_ENV=production顾名思义,即分别在开发环境和生产环境注入一些环境变量,这里为了区分不同环境我们加上了NODE_ENV,你也可以根据需要添加别的环境变量。 打包的时候 vite 会自动将这些环境变量替换为相应的字符串。 在项目中引入资源 hello idux 您的浏览器不支持 video 标签。 可以正常展示 我们执行pnpm run build,可以看到产物中已经自动加上了CDN地址前缀了 当然,HTML 中的一些 JS、CSS 资源链接也一起加上了 CDN 地址前缀 除了CDN之外,有时候可能项目中的某些图片需要存放到另外的存储服务,一种直接的方案是将完整地址写死到 src属性 中,如: 这样做显然是不太优雅的,我们可以通过定义环境变量的方式来解决这个问题,在项目根目录新增.env文件: // .envVITE_IMG_BASE_URL=https://idux.site 开发环境优先级: .env.development > .env生产环境优先级: .env.production > .env 然后进入 src/vite-env.d.ts增加类型声明: /// interface ImportMetaEnv { // 自定义的环境变量 readonly VITE_IMG_BASE_URL: string;}interface ImportMeta { readonly env: ImportMetaEnv;} 如果某个环境变量要在 vite 中通过 import.meta.env 访问,那么它必须以VITE_开头,如VITE_IMG_BASE_URL 我们在项目中增加一个img hello idux 您的浏览器不支持 video 标签。 可以看到,img路径已经成功被替换成env中的路径 至此,我们就解决了生成环境下域名替换的问题。 3.2、单文件or内联vite 中内置的优化方案是下面这样的: 如果静态资源体积 >= 4KB,则提取成单独的文件如果静态资源体积 < 4KB,则作为 base64 格式的字符串内联上述的4 KB即为提取成单文件的临界值,当然,这个临界值你可以通过build.assetsInlineLimit自行配置,如下代码所示: // vite.config.ts{ build: { // 8 KB assetsInlineLimit: 8 * 1024 }} svg 格式的文件不受这个临时值的影响,始终会打包成单独的文件 3.3、图片压缩社区中已经有了成熟的图片压缩方案:vite-plugin-imagemin安装依赖 pnpm add vite-plugin-imagemin -D 如果安装不上可以参考这篇文章:blog.csdn.net/qq_43806604… 然后在vite.config.ts中配置 //vite.config.tsimport viteImagemin from 'vite-plugin-imagemin';{ plugins: [ // 忽略前面的插件 viteImagemin({ // 无损压缩配置,无损压缩下图片质量不会变差 optipng: { optimizationLevel: 7 }, // 有损压缩配置,有损压缩下图片质量可能会变差 pngquant: { quality: [0.8, 0.9], }, // svg 优化 svgo: { plugins: [ { name: 'removeViewBox' }, { name: 'removeEmptyAttrs', active: false } ] } }) ]}为了测试我特意找了张.png格式的图片 这张图片大小是10.4KB,按照之前配置的应该会打包成单文件使用之前vite-plugin-imagemin进行压缩之前: 使用之前vite-plugin-imagemin进行压缩之后: 可以看到效果非常明显,这对我们的性能有很大提升OK,我们处理静态资源的内容就讲到这。 TSX写过组件库的都知道,tsx在语法上会比较有优势,我们把它接入进来安装依赖 pnpm add @vitejs/plugin-vue-jsx -D使用插件 // vite.config.tsimport vueJsx from '@vitejs/plugin-vue-jsx';{ "plugins": [ //其他配置 vueJsx() ]}补充lint命令支持后缀 { "script": { "lint:script": "eslint --ext .js,.ts,.tsx,.vue --fix --quiet ./src", }}编写组件需要以.tsx结尾 // src/componens/Demo.tsximport { defineComponent } from 'vue';export default defineComponent({ setup() { return () => hello idux ; }}); OK, 这里可以顺利执行。 Pinia状态管理大型项目中一般有状态管理的需求,我们首当其冲的使用:pinia安装依赖 pnpm add pinia pinia-plugin-persist 插件pinia-plugin-persist支持数据持久化(将store的数据缓存到storage中) 创建别名 // vite.config.ts{ resolve: { alias: { // 其他配置 '@store/*': path.resolve(__dirname, './src/store') } }}配置tsconfig.json防止类型报错 { "compilerOptions": { // 其他配置 "types": [ "pinia-plugin-persist" ], "baseUrl": ".", "paths": { "@store/*": ["./src/store/*"] }, "strict": false, }}创建store实例 // src/store/index.tsimport { createPinia } from 'pinia';import { App } from 'vue';import piniaPersist from 'pinia-plugin-persist'; //数据持久化const store = createPinia();const install = (app: App): void => { store.use(piniaPersist); app.use(store);};export default { install };注册store // src/main.tsimport { createApp } from 'vue';import store from './store';import App from './App.vue';createApp(App).use(store).mount('#app');创建useCountStore // src/store/use_count_store.tsimport { defineStore } from 'pinia';import { ref } from 'vue';export const useCountStore = defineStore('count', () => { const count = ref(0); const increment = () => { count.value++; }; return { count, increment };});在src/components文件夹下创建Demo.vue并在App.vue中引入,用来测试状态是否共享 // App.vue hello idux 您的浏览器不支持 video 标签。 App Count: {{ count }} 新增 // Demo.vue Demo Count: {{ count }} 新增可以看到Demo.vue组件会有一个报错:组件文件名必须驼峰命名,解决方案: 修改组件名为驼峰格式,例如:DemoComponent.vue或者配置name: DemoComponent配置eslint规则,增加:vue/multi-word-component-names: off的规则执行项目,可以看到状态已经同步,配合vue-devtools效果更佳 pinia持久化的配置这里就不过多介绍了,网上已经有很多详细的介绍方案。OK,pinia的内容就讲到这。 Vue-Router接下来,我们要接入router路由安装依赖 pnpm add vue-router@latest复制代码pnpm add vue-router@latest创建路由实例 // src/router/index.tsimport type { App } from 'vue';import { createRouter, createWebHashHistory } from 'vue-router';import routes from './routes'const router = createRouter({ routes, history: createWebHashHistory()});const install = (app: App): void => { app.use(router);};export default { install };创建路由,这里我们随意创建个首页和登录页的路由作为案例 // src/router/routes.tsimport type { RouteRecordRaw } from 'vue-router';const routes: RouteRecordRaw[] = [ { path: '/', redirect: '/home' }, { path: '/home', component: () => import('@views/Home/Index.vue'), //在vite.config.ts中配置@views别名 meta: { title: '首页' } }, { path: '/login', component: () => import('@views/Login/Index.vue'), meta: { title: '登录' } }];export default routes;创建Home和Login组件 // src/components/Home/Index.vue 首页 // src/components/Login/Index.vue 登录页 注册路由 // src/main.tsimport { createApp } from 'vue';import store from './store';import router from './router';import App from './App.vue';createApp(App).use(store).use(router).mount('#app');修改tsconfig.json防止类型报错 { "compilerOptions": { // 其他配置 "moduleResolution": "node" }}在App.vue添加组件,并添加跳转按钮测试 hello idux 您的浏览器不支持 video 标签。 App Count: {{ count }} 新增 测试路由 去首页 去登录页 运行项目看一下效果,可以看到已经可以实现路由的跳转了 OK, 关于路由的介绍就到这里。 Idux组件库前期基础工作都准备的差不多了,我们可以开始接入组件库了 1、初始化Idux安装依赖 pnpm add @idux/cdk @idux/components @idux/pro引入idux // src/plugins/idux.tsimport type { App } from 'vue';import "@idux/components/default.full.css"; import "@idux/pro/default.css";// 如果不需要 reset 全局样式和滚动条样式,移除下面 2 行代码import '@idux/components/style/core/reset.default.css';import '@idux/components/style/core/reset-scroll.default.css';import IduxCdk from '@idux/cdk';import IduxComponents from '@idux/components';import IduxPro from '@idux/pro';import { createGlobalConfig } from '@idux/components/config';// 动态加载图标:不会被打包,可以减小包体积,需要加载的时候时候 http 请求加载const loadIconDynamically = (iconName: string) => { return fetch(`/idux-icons/${iconName}.svg`).then((res) => res.text());};const globalConfig = createGlobalConfig({ // 默认为中文,可以打开注释设置为其他语言 // locale: enUS, icon: { loadIconDynamically }});const install = (app: App): void => { app.use(IduxCdk).use(IduxComponents).use(IduxPro).use(globalConfig);};export default { install };动态加载图标,需要安装vite-plugin-static-copy pnpm add vite-plugin-static-copy -D使用插件 // vite.config.tsimport { viteStaticCopy } from 'vite-plugin-static-copy';{ "plugins": [ //其他配置 viteStaticCopy({ targets: [ {src: './node_modules/@idux/components/icon/assets/*.svg',dest: 'idux-icons' } ] }) ]}这样打包的时候,svg就作为单独的资源文件放在idux-icons目录,而不是打包进js文件中 导出idux // src/plugins/index.tsimport idux from './idux';export { idux };注册idux // src/main.tsimport { createApp } from 'vue';import store from './store';import { idux } from './plugins';import router from './router';import App from './App.vue';createApp(App).use(store).use(router).use(idux).mount('#app');处理组件类型,创建types目录并新建idux.d.ts,同时把原来的vite-env.d.ts移动到该目录下 // idux.d.ts/// /// /// 2、创建IduxProvider组件和utilsIduxProvider方便我们全局注入provider,可以使用idux提供的hooks函数 // src/components/idux-provider/IduxProvider.vue 因为上面的useDrawer等hooks需要在setup中才能使用,所以我们可以把实例存在全局的变量中,这样在ts文件也可以使用 // src/utils/iduxProviders.tsimport { DrawerProviderRef } from '@idux/components/drawer';import { NotificationProviderRef } from '@idux/components/notification';import { ModalProviderRef } from '@idux/components/modal';import { MessageProviderRef } from '@idux/components/message';let Drawer: DrawerProviderRef | undefined;let Notification: NotificationProviderRef | undefined;let Modal: ModalProviderRef | undefined;let Message: MessageProviderRef | undefined;// 方便在 ts 中直接调用export function registerProviders(option: { drawer: DrawerProviderRef; notification: NotificationProviderRef; modal: ModalProviderRef; message: MessageProviderRef;}): void { Drawer = option.drawer; Notification = option.notification; Modal = option.modal; Message = option.message;}export { Drawer, Notification, Modal, Message };导出组件和utils // src/components/idux-provider/index.tsimport IduxProvider from './IduxProvider.vue';export { IduxProvider }; // src/utils/index.tsexport * from './iduxProviders';在App.vue中引入 我们把之前的测试代码全都删掉,保持项目的干净,并引入IduxProvider组件 我们去Home组件中引入idux组件,试一下效果 // src/components/Home/Index.vue 首页 Hello Idux 可以看到已经可以引入组件了,我们再试试useMessage等hooks的使用 // src/components/Home/Index.vue 首页 Hello Idux 可以成功使用了,我们在试试直接在ts文件中使用 // src/components/Home/hooks.tsimport { Message } from '@utils';const useIduxMessage = (): void => { Message .success('hello, idux');};export { useIduxMessage };在Home组件引入 首页 Hello Idux 看一下效果,也是可以提示的 在setup中可以使用useMessage等hooks函数,因为这是依赖于provider/inject的注入,这就是IduxProvider组件的作用,而在ts文件中使用的话会报错,所以我们通过挂载全局变量的方式使用,达到同样的效果 3、通过unplugin-vue-components按需加载在上面例子中,我们可以看到组件是通过手动引入的方式 import { IxButton } from '@idux/components/button';如果使用的组件一多,那需要写特别多的import。而且我们前面注册idux时,直接use了整个组件库,为了降低打包的文件体积,我们使用按需加载的方式使用组件安装依赖 pnpm add unplugin-vue-components -D添加插件 // vite.config.tsimport { IduxResolver } from 'unplugin-vue-components/resolvers';import Components from 'unplugin-vue-components/vite';{ "plugins": [ //其他配置 Components({ resolvers: [ // 可以通过指定 `importStyle` 来按需加载 css 或 less 代码, 也支持不同的主题 IduxResolver({ importStyle: 'css', importStyleTheme: 'default' }) ], dts: false //不生成d.ts文件 }) ]}移除注册代码 // src/plugins/idux.ts// 移除- import "@idux/components/default.full.css"; - import "@idux/pro/default.css";// 新增+ import '@idux/cdk/index.css'// 移除- import IduxCdk from "@idux/cdk"; - import IduxComponents from "@idux/components"; - import IduxPro from "@idux/pro";const install = (app: App): void => { // 移除 - app.use(IduxCdk).use(IduxComponents).use(IduxPro).use(globalConfig); // 新增 + app.use(globalConfig) };完整代码如下 // src/plugins/idux.tsimport type { App } from 'vue';import '@idux/cdk/index.css';// 如果不需要 reset 全局样式和滚动条样式,移除下面 2 行代码import '@idux/components/style/core/reset.default.css';import '@idux/components/style/core/reset-scroll.default.css';import { createGlobalConfig } from '@idux/components/config';import { IDUX_ICON_DEPENDENCIES, addIconDefinitions} from '@idux/components/icon';// import { enUS } from "@idux/components/locales";// 静态加载: `IDUX_ICON_DEPENDENCIES` 是 `@idux` 的部分组件默认所使用到图标,建议在此时静态引入。addIconDefinitions(IDUX_ICON_DEPENDENCIES);// 动态加载:不会被打包,可以减小包体积,需要加载的时候时候 http 请求加载// 注意:请确认图标的 svg 资源被正确放入到 `public/idux-icons` 目录中const loadIconDynamically = (iconName: string) => { return fetch(`/idux-icons/${iconName}.svg`).then((res) => res.text());};const globalConfig = createGlobalConfig({ // 默认为中文,可以打开注释设置为其他语言 // locale: enUS, icon: { loadIconDynamically }});const install = (app: App): void => { app.use(globalConfig);};export default { install };首页组件也移除import的相关代码 首页 Hello Idux 可以看到,已经可以成功实现按需加载了OK,idux组件库的内容就讲到这。 Axios接下来,我们准备接入axios,用来发请求 安装依赖 pnpm add axios业界有很多二次封装axios的案例,这里就不费尽口舌了,仅介绍一些整体框架和思路添加VITE_BASE_API_URL环境变量 // .envVITE_IMG_BASE_URL=https://idux.siteVITE_BASE_API_URL=http://xxxxx //填写你要请求的url地址添加到类型中 // src/types/vite.env.d.ts/// interface ImportMetaEnv { // 自定义的环境变量 readonly VITE_IMG_BASE_URL: string; readonly VITE_BASE_API_URL: string;}interface ImportMeta { readonly env: ImportMetaEnv;}添加showErrorMessage方法,当请求错误时用来提示 // src/utils/requeset.ts// 请求错误时消息提示import type { AxiosError } from 'axios';import { Message } from './iduxProviders';const showErrorMessgae = (error: AxiosError): void => { const { response } = error; if (!response) { return; } const { status } = response; switch (status) { case 401: Message .warning('账号没有权限,无法访问资源'); break; case 403: Message .warning('请求的资源无法访问'); break; case 404: Message .error('请求的资源不存在'); break; case 500: Message .error('网络错误,请重试'); break; default: Message .error('网络错误,请重试'); break; }};export { showErrorMessgae };创建axios实例 // src/request/index.tsimport axios, { type AxiosRequestConfig, type AxiosError, type AxiosResponse} from 'axios';import { requestInterceptors, responseiInterceptors } from './interceptors';const request = axios.create({ baseURL: import.meta.env.VITE_BASE_API_URL, timeout: 1000 * 10 //10s超时});// 请求拦截器requestInterceptors .forEach((interceptors) => { request.interceptors.request.use( (config: AxiosRequestConfig) => { return interceptors .resolve(config); }, (error: AxiosError) => { return interceptors .reject(error); } );});// 响应拦截器responseiInterceptors .forEach((interceptors) => { request.interceptors.response.use( (response: AxiosResponse) => { return interceptors .resolve(response); }, (error: AxiosError) => { return interceptors .reject(error); } );});export default request;创建errorStatus拦截器,专门处理错误状态码的 // src/request/interceptors/response/errorStatus.ts// 专门处理失败状态码的拦截器import type { AxiosError } from 'axios';import { showErrorMessgae } from '@utils';const errorStatusReject = (error: AxiosError): Promise => { showErrorMessgae(error); return Promise.reject(error);};export default errorStatusReject;整体层级结构 创建mock // src/components/Home/mock.json{ "data": { "list": [ { "key": 1, "name": "张三", "age": 18 }, { "key": 2, "name": "李四", "age": 30 } ] }, "success": true}在首页组件中发请求 // src/components/Home/Index.vue 首页 Hello Idux 可以看到,已经可以成功提示错误消息了,但是为什么会404呢?我们需要设置代理等,社区有成熟的mock方案,那就是vite-plugin-mock安装依赖 pnpm add vite-plugin-mock@2.9.8 mockjs -D vite-plugin-mock已经升级到3.0版本,但是好像会报错,所以建议安装2.9.8 根目录下创建mock文件夹和demo.js // mock/demo.jsexport default [ { url: '/api/demo', method: 'get', response: () => { return { data: { 'list|0-10': [ {key: '@id',name: '@cname',age: '@integer(18, 60)' } ], total: '@integer(0, 100)' }, success: true }; } }];使用插件 // vite.config.tsimport { viteMockServe } from 'vite-plugin-mock';{ "plugins": [ //其他配置 viteMockServe({ mockPath: 'mock', localEnabled: !isProduction, //生产环境下不启用 watchFiles: true }), ]}修改请求路径 // src/components/Home/Index.vue 首页 Hello Idux 可以看到,已经可以成功请求mock了模拟403,也可以正确提示 但是,这里还有个小问题,我们每次请求都去引入一次request import request from '@/request';那这样每次都会重复去创建一次实例 const request = axios.create()export default request这个过程似乎是没有必要的,提供个思路,我们同样可以放在全局变量上,只初始化一次,每次引入request的全局变量即可 // src/request/index.tsimport type { AxiosInstance } from 'axios';let request: AxiosInstance;const initAxios = (curRequest: AxiosInstance) => { request = curRequest;};export { request, initAxios };在main.ts中注入 // src/main.tsimport { createApp } from 'vue';import store from './store';import { idux } from './plugins';import router from './router';import request from './request/create'; //修改原来的request.ts变为create.tsimport { initAxios } from './request';import App from './App.vue';initAxios(request);createApp(App).use(store).use(router).use(idux).mount('#app');请求时直接引入即可,避免多次创建 import { request } from '@/request';OK, axios相关的内容就讲到这。 使用Vitest进行测试安装依赖 pnpm add vitest -D我们直接使用官方的案例 添加命令 // package.json{ "script": { //其他配置 "test": "vitest" }}运行pnpm run test 看到输出结果说明已经成功接入vitest 总结经过上面的流程,我们已经把整个架构都搭好了,可以根据自己需求继续完善即可。 作者:前端小东链接:https://juejin.cn/post/7273875079657062439

本站涵盖的内容、图片、视频等数据,部分未能与原作者取得联系。若涉及版权问题,请及时通知我们并提供相关证明材料,我们将及时予以删除!谢谢大家的理解与支持!

Copyright © 2023