likes
comments
collection
share

基于Vite从0到1搭建一个Vue3相关的工程化模板项目

作者站长头像
站长
· 阅读数 23

此文的目的是基于Vite从0到1搭建一个Vue3相关的工程化模板项目,其中包括集成Typescript、Vitest、Tsx、Vue Router、Pinia、element-plus、Eslint、Prettier、Husky、Git Message规范、VitePress等。

本文所搭建的模版可在github查看:Vue3生态模版

Vite

首先使用Vite可以快速创建一个基本的Vue项目。

创建项目

首先看下Vite文档,根据文档我们可以通过以下命令创建我们的初始模板:

# npm 6.x
npm create vite@latest my-vue-app --template vue

# npm 7+, extra double-dash is needed:
npm create vite@latest my-vue-app -- --template vue

# yarn
yarn create vite my-vue-app --template vue

# pnpm
pnpm create vite my-vue-app --template vue

Vite提供了很多模板,因为我们使用TS,所以选用vue-ts模板,然后用pnpm来管理我们的npm包。

创建项目:

pnpm create vite my-vue-app --template vue-ts

如果没有安装pnpm,先全局安装pnpm:

npm i pnpm -g

运行项目

项目创建好之后我们安装依赖然后运行项目。

// 安装依赖
pnpm install

// 本地运行
pnpm dev

启动后可以看到下面这个页面:

基于Vite从0到1搭建一个Vue3相关的工程化模板项目

scripts脚本

Vite帮我们创建的项目有以下三个脚本

  "scripts": {
    "dev": "vite",
    "build": "vue-tsc && vite build",
    "preview": "vite preview"
  },

其中dev是运行本地开发环境,build是编译开发环境需要的资源,preview是预览我们build出来的资源。

集成Vitest

Vitest是一个由 Vite 提供支持的极速单元测试框架,与Vite完全兼容,可以和Vite共享配置文件。

首先我们安装Vitest

pnpm install vitest -D

然后我们在根目录下创建一个目录tests,在tests下创建一个文件index.spec.ts,在该文件下编写我们的单元测试,如下:

// index.spec.ts
import { test, expect } from "vitest";

test("First test", () => {
  expect(1 + 1).toBe(2);
});

和jest不同,vitest的test和expect默认不支持全局引用,需要在模块里自己引入,然后我们再在package.json里配置测试脚本:

  "scripts": {
    "test": "vitest"
  },

这时候我们在命令行执行pnpm test就会执行我们的测试用例,Vite会自动找到项目里面以test.ts或者spec.ts结尾的文件作为测试文件,然后执行它们。

比如我们把index.spec.ts文件改名为index.speccc.ts,然后再执行pnpm test,这时候控制台会输出以下错误:

基于Vite从0到1搭建一个Vue3相关的工程化模板项目

告诉我们没找到要测试的文件,并且告诉我们测试文件需要符合对应的命名格式。

Vitest监听模式

Vitest默认是以监听模式启动的,在我们执行pnpm test的时候,测试启动的服务是不会退出的,它会监听我们的代码改变,如果改变了会重新执行测试程序,如果不想以监听的模式启动,只想执行单次测试,那么只需要把"test": "vitest"改为"test": "vitest run",更多配置可查看vite文档

Vitest测试ts模块

在使用jest测试ts文件的时候,我们需要做很多的配置来支持,使用vitest不需要做任何的配置,默认支持ts。

比如我们写了一个sum.ts文件:

// sum.ts
function sum(...numbs: number[]): number {
  const result = numbs.reduce((pre, current) => {
    return pre + current;
  });
  return result;
}

export { sum };

测试文件可以直接引用这个模块进行测试:

// index.spec.ts
import { test, expect } from "vitest";
import { sum } from "../src/utils/sum";

test("First test", () => {
  expect(1 + 1).toBe(2);
});

test("Sum function test", () => {
  expect(sum(1, 2, 3)).toBe(6);
});

执行pnpm test后可以看到测试被正确执行。

Vitest测试vue模块

在tests目录下新建一个hello.spec.ts文件,输入内容如下:

import Hello from "../src/components/HelloWorld.vue";

我们会发现有个报错:

基于Vite从0到1搭建一个Vue3相关的工程化模板项目

这时候我们需要将tests目录下的文件加到ts的检测目录里,需要在tsconfig.json里进行如下配置:

  "include": [
    "src/**/*.ts",
    "src/**/*.d.ts",
    "src/**/*.tsx",
    "src/**/*.vue",
    "tests/**/*.ts" // 这一行是新增加的配置
  ],

我们在hello.spec.ts里输入以下内容:

import Hello from "../src/components/HelloWorld.vue";
import { test, expect } from "vitest";

test("Test Hello.vue", () => {
  console.log(Hello);
});

然后执行pnpm test,是可以正确执行测试的,这说明vitest可以直接支持对Vue单文件的解析,可以实现对Vue文件的解析是因为vitest可以共用vite的配置,我们使用vite创建的项目vite.config.ts如下:

import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'

// https://vitejs.dev/config/
export default defineConfig({
  plugins: [vue()]
})

vitest默认也使用这个配置,而这个配置里有个@vitejs/plugin-vue插件是可以支持对vue文件的解析的,所以vitest默认可以共享vite的配置及其相关功能。

Vitest配置

官方文档vitest配置

如果我们想要对Vitest做一些配置,比如我们想要像Jest一样,支持在全局使用test和expect,也就是说在我们的测试文件里不需要import { test, expect } from "vitest";就可以使用test和expect方法,这个时候可以通过配置来支持这个功能。

简单的方式我们可以直接在vite.config.ts里做配置,配置如下:

/// <reference types="vitest" />
import { defineConfig } from "vite";
import vue from "@vitejs/plugin-vue";

// https://vitejs.dev/config/
export default defineConfig({
  test: {
    globals: true, 
  },
  plugins: [vue()],
});

其中新增的代码是

/// <reference types="vitest" />

  test: {
    globals: true, 
  },

其中第一行三斜线指令是引入vitest相关的类型配置,那么我们在下面新增test属性的时候就不会报错。

Vitest相关的配置需要添加在test属性里,这里我们添加了globals: true表示支持全局使用test、expect等方法。

如果我们不想把Vitest相关的配置写在vite.config.ts里,也可以单独写一个配置文件命名为vitest.config.ts,那么vitest会使用这个文件作为配置文件而忽略vite.config.ts。这个时候需要注意vite相关的配置也需要包含在vitest.config.ts这个文件里,比如plugins: [vue()],因为vitest可能也需要对vue文件进行解析,具体如何配置可以看这个文档

然后这个时候我们去掉测试文件里的import { test, expect } from "vitest";,发现还是报错了,提示找不到test方法:

基于Vite从0到1搭建一个Vue3相关的工程化模板项目

这个时候我们还需要告诉编译器这个test是一个全局方法,可以直接使用,我们需要配置下tsconfig.ts,在tsconfig.ts里增加types选项,输入如下内容:

{
  "compilerOptions": {
    "types": ["vitest/globals"] // 这是新增的内容
  }
}

然后我们看下vitest下有一个global.d.ts文件,里面的内容如下:

declare global {
  const suite: typeof import('vitest')['suite']
  const test: typeof import('vitest')['test']
  const describe: typeof import('vitest')['describe']
  const it: typeof import('vitest')['it']
  const expectTypeOf: typeof import('vitest')['expectTypeOf']
  const assertType: typeof import('vitest')['assertType']
  const expect: typeof import('vitest')['expect']
  const assert: typeof import('vitest')['assert']
  const vitest: typeof import('vitest')['vitest']
  const vi: typeof import('vitest')['vitest']
  const beforeAll: typeof import('vitest')['beforeAll']
  const afterAll: typeof import('vitest')['afterAll']
  const beforeEach: typeof import('vitest')['beforeEach']
  const afterEach: typeof import('vitest')['afterEach']
}
export {}

其中定义了测试文件可以全局使用的函数,包括test、expect等。

测试Vue单文件组件

Vue Test Utils

测试Vue单文件组件需要安装@vue/test-utils,详细信息可查看官方文档。 先执行安装

pnpm install @vue/test-utils -D

然后我们可以使用@vue/test-utils里的相关方法来挂载组件,这里我们还是测试Vite自动生成的HelloWorld.vue组件,HelloWorld.vue代码如下:

<script setup lang="ts">
defineProps<{ msg: string }>()
</script>

<template>
  <h1>{{ msg }}</h1>
</template>

<style scoped></style>

HelloWorld.vue会接收一个prop: msg,然后将对应的内容展示出来,我们可以测试这个过程是否正确执行。

在HelloWorld.vue同级目录编写HelloWorld.spec.ts,代码如下:

import HelloWorld from "./HelloWorld.vue";
import { mount } from "@vue/test-utils";

test("Test HelloWorld Props", () => {
  const wrapper = mount(HelloWorld, {
    props: {
      msg: "111111",
    },
  });

  // Assert the rendered text of the component
  expect(wrapper.text()).toContain("111111");
});

其中mount方法会挂载我们的组件,然后我们判断渲染出的组件里的内容是否包含prop传进去的内容。

这时候我们执行pnpm test会发现报如下错误:

基于Vite从0到1搭建一个Vue3相关的工程化模板项目

错误信息提示document is not defined,我们根据错误提示可以进入到报错的具体文件,发现报错的代码是这行:

var el = document.createElement('div');

设置因为我们执行mount方法的时候会创建dom元素,可是现在是在node环境,没有浏览器相关的API,所以要解决这个问题我们需要模拟浏览器相关的API,目前有两个库可以用来实现这个功能,分别是jsdom和happydom,这里我们使用jsdom。

安装jsdom:

pnpm install jsdom -D

然后配置vite.config.ts新增environment: "jsdom"

/// <reference types="vitest" />
import { defineConfig } from "vite";
import vue from "@vitejs/plugin-vue";

// https://vitejs.dev/config/
export default defineConfig({
  test: {
    globals: true,
    environment: "jsdom",
  },
  plugins: [vue()],
});

这时候我们再执行pnpm test就发现测试通过了。

支持jsx/tsx

如果要支持jsx/tsx,需要安装一个插件@vitejs/plugin-vue-jsx,请查看该文档

首先我们执行安装:

pnpm install @vitejs/plugin-vue-jsx -D

然后配置vite.config.ts文件添加vueJsx插件:

import { defineConfig } from "vite";
import vue from "@vitejs/plugin-vue";
import vueJsx from "@vitejs/plugin-vue-jsx";

// https://vitejs.dev/config/
export default defineConfig({
  plugins: [vueJsx(), vue()],
});

这时候我们可以编写一个HelloTsx.tsx组件看下:

import { defineComponent } from "vue";

export default defineComponent({
  setup() {
    return () => <div>This is tsx</div>;
  },
});

然后在App.vue里引入:

<script setup lang="ts">
import HelloTsx from "./components/HelloTsx";
</script>

<template>
  <HelloTsx />
</template>

<style scoped>
</style>

执行pnpm dev后可以看到组件正常展示。

测试tsx组件

当使用vite测试tsx组件的时候,我们需要添加一个配置transformMode

/// <reference types="vitest" />
import { defineConfig } from "vite";
import vue from "@vitejs/plugin-vue";
import vueJsx from "@vitejs/plugin-vue-jsx";

// https://vitejs.dev/config/
export default defineConfig({
  test: {
    globals: true,
    environment: "jsdom",
    transformMode: {
      web: [/\.tsx$/],
    },
  },
  plugins: [vueJsx(), vue()],
});

因为默认当我们用vitest测试tsx组件的时候,vitest会认为这是服务端,所以使用@vitejs/plugin-vue-jsx转换出来的代码是SSR模式的,我们需要告诉Vitest这些测试文件需要用Web模式进行测试,所以需要添加以下配置:

    transformMode: {
      web: [/\.tsx$/],
    },

详细配置说明可查看文档

然后我们可以编写一个tsx的测试文件看下:

// HelloTsx.tsx
import { defineComponent } from "vue";

export default defineComponent({
  setup() {
    return () => <div>This is tsx</div>;
  },
});

// HelloTsx.spec.ts
import HelloTsx from "./HelloTsx";
import { mount } from "@vue/test-utils";

test("Test HelloWorld Props", () => {
  const wrapper = mount(HelloTsx, {});

  // Assert the rendered text of the component
  expect(wrapper.text()).toContain("This is tsx");
});

执行pnpm test后测试可以正确执行。

配置Eslint和Prettier

Eslint和Prettier的详细配置和相关的说明可以参考之前写的这篇文章

配置Eslint

1、首先如果没安装Vscode插件的话,安装一下Vscode的ESlint插件。

2、安装eslint

pnpm install eslint -D

3、使用eslint初始化.eslintrc.cjs配置文件

pnpm eslint --init

然后根据提示选择配置完成文件的生成,我这边选择的配置如下:

基于Vite从0到1搭建一个Vue3相关的工程化模板项目

这时候生成的.eslintrc.cjs文件是这样的:

module.exports = {
  env: {
    browser: true,
    es2021: true,
    node: true,
  },
  extends: [
    "eslint:recommended",
    "plugin:vue/vue3-essential",
    "plugin:@typescript-eslint/recommended",
  ],
  overrides: [],
  parser: "@typescript-eslint/parser",
  parserOptions: {
    ecmaVersion: "latest",
    sourceType: "module",
  },
  plugins: ["vue", "@typescript-eslint"],
  rules: {},
};

现在解析vue文件会有问题,会报错,我们需要一个vue文件的parser。

使用vue-eslint-parser,我们把parser: "@typescript-eslint/parser"移到parserOptions里,然后添加parser: "vue-eslint-parser"

基于Vite从0到1搭建一个Vue3相关的工程化模板项目

修改完成后的.eslintrc.cjs是这样的:

module.exports = {
  env: {
    browser: true,
    es2021: true,
    node: true,
  },
  extends: [
    "eslint:recommended",
    "plugin:vue/vue3-essential",
    "plugin:@typescript-eslint/recommended",
  ],
  overrides: [],
  parser: "vue-eslint-parser",
  parserOptions: {
    ecmaVersion: "latest",
    sourceType: "module",
    parser: "@typescript-eslint/parser",
  },
  plugins: ["vue", "@typescript-eslint"],
  rules: {},
};

然后我们新建一个.eslintignore用来设置不需要使用eslint进行检测的文件,内容如下:

node_modules
dist

然后如果我们还需要做一些保存代码的时候自动使用eslint进行格式化相关的操作,可以查看这篇文章了解如何配置。

Prettier配置

Eslint的主要职责是用来检测代码里的语法错误,而Prettier主要是负责格式化相关的检测,也就是代码格式是否好看。这两个插件是相互配合各有侧重点的,当然也有一些重叠的地方,比如Eslint也会做一些格式化代码的工作,Prettier也会检查一些语法。所以需要做一些配置避免两个插件规则的冲突,比如一个设置了代码里使用双引号,一个设置了使用单引号,这时候需要合并规则。

1、第一步如果Vscode没有安装Prettier插件,先安装插件

2、创建.prettierrc.cjs文件,内容设置如下:

module.exports = {
  singleQuote: true,
};

表明我们想要代码里的风格是单引号,然后在.eslintrc.cjs里添加如下规则:

  rules: {
    quotes: [1, 'double'],
  },

表明需要的是双引号,这个时候我们保存的时候,格式化后的代码是单引号,以Prettier为准,可是Eslint检测会报错,所以我们需要做兼容。

3、安装eslint-plugin-prettier 和 eslint-config-prettier

其中eslint-config-prettier会把Eslint里和Prettier有冲突的规则关掉,eslint-plugin-prettier会将Prettier里的规则设置到Eslint里面,通过这两个插件的配合,就完成了Eslint和Prettier规则的合并,其中冲突的规则以Prettier里的规则为准。

首先安装这两个插件:

pnpm install eslint-plugin-prettier eslint-config-prettier prettier -D

然后我们在.eslintrc.cjs的extends里添加plugin:prettier/recommended插件,要添加在最后,这个时候规则就已经合并了。

4、创建.prettierignore文件用于设置不想要使用Prettier进行格式化的文件,内容如下:

dist
node_modules

代码提交检查

以上的配置让我们可以在编译器里检测出不符合规范的代码,但是还是可以提交的,为了保证所有人都遵守规范,我们需要在提交代码的时候进行检查,如果不符合规范不让提交。

具体的说明还是查看这篇文章,一些细节重复的东西这里不再赘述,这里只讲解配置步骤。

1、安装husky

pnpm install husky -D

2、然后在package.json中添加prepare钩子,执行命令如下:

npm pkg set scripts.prepare="husky install"
pnpm prepare

执行以上步骤会在package.json里生成以下代码:

  "scripts": {
    "prepare": "husky install"
  },

然后我们手动执行一下pnpm prepare会生成.husky文件夹

3、设置pre-commit钩子,执行如下命令:

pnpm husky add .husky/pre-commit "pnpm lint-staged"

执行该命令会在.husky文件夹下生成pre-commit文件,内容如下:

#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"

pnpm lint-staged

我们执行git commit的时候会先触发pre-commit的钩子,然后会执行这个钩子里的pnpm lint-staged脚本,这个脚本是用来做eslint检查的,只有检查通过才会执行后面的提交工作。

4、为了让pnpm lint-staged可以正常工作,我们需要安装lint-staged

pnpm install lint-staged -D

我们使用lint-staged来检查代码的原因是不想要每次执行eslint代码都检查所有代码,因为有些代码我们没有改动过,如果用eslint检查出来有问题,我们是改还是不改呢,所以使用lint-staged来检查,只检查在暂存区的代码,也就是git add过的代码。

5、然后我们设置lint-staged的检测规则,在package.json里添加如下代码:

  "lint-staged": {
    "*.{js,jsx,ts,tsx}": [
      "eslint --fix"
    ],
    "*.vue": [
      "eslint --fix"
    ],
    "*.{html,vue,vss,sass,less}": [
      "prettier --write"
    ],
    "package.json": [
      "prettier --write"
    ],
    "*.md": [
      "prettier --write"
    ]
  },

这时候当我们执行git commit的时候就会触发pre-commit钩子,然后执行钩子函数pnpm lint-staged,这时候lint-staged会调用package.json里配置的规则进行校验。

校验git commit message

Commit message目前比较知名和受认可的是Angular团队的规范,校验提交规范需要用到这三个工具: commitizen commitlint husky

1、其中commitizen是一个命令行交互工具,用来帮助我们书写正确的Message格式。

2、commitlint用来对message做校验。

3、husky用来让我们设置在commit-msg这个git钩子里触发commitlint校验。

更详细的介绍还是看这篇文章

husky我们已经安装过了,现在我们安装另外两个。

首先我们安装commitizen

pnpm install commitizen -D

然后安装cz-conventional-changelog:

pnpm add cz-conventional-changelog -D

在package.json中增加如下配置:

  "config": {
    "commitizen": {
      "path": "./node_modules/cz-conventional-changelog"
    }
  },

这时候我们可以使用pnpm cz命令代替git commit命令,pnpm cz会用命令行交互的方式指引我们写出符合规范的commit message。

Commitlint

当然我们也可以不用pnpm cz,我们自己写message也可以,自己写出来的可能是不规范的,所以需要用commitlint来做校验。

安装Commitlint

# For mac
pnpm install --save-dev @commitlint/{config-conventional,cli}

# For windows
pnpm install --save-dev @commitlint/config-conventional @commitlint/cli

然后配置config:

echo "module.exports = {extends: ['@commitlint/config-conventional']}" > commitlint.config.cjs

这会生成一个commitlint.config.cjs文件,内容如下:

module.exports = { extends: ['@commitlint/config-conventional'] };

然后我们配置git钩子函数,在终端执行如下命令:

pnpm husky add .husky/commit-msg  'npx --no -- commitlint --edit ${1}'

这会在.husky目录下生成一个commit-msg文件,内容如下:

#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"

npx --no -- commitlint --edit ${1}

这时候我们再执行git commit,输入不符合规范的message会提示错误:

基于Vite从0到1搭建一个Vue3相关的工程化模板项目

配置别名alias

我们在开发中会使用@/component之类的路径来简写我们的相对路径,为了实现可以使用别名,我们需要进行对应的配置。

vite.config.ts配置alias

我们在vite.config.ts中增加如下配置:

/// <reference types="vitest" />
import { defineConfig } from 'vite';
import { join } from 'path';

// https://vitejs.dev/config/
export default defineConfig({
  resolve: {
    alias: [
      {
        find: '@/',
        replacement: join(__dirname, 'src/'),
      },
    ],
  },
});

这个配置告诉vite解析到@/开头的路径的时候,需要替换为src目录的路径。

tsconfig.json配置alias

在vite.config.ts中配置好别名后,vite就可以正确解析路径了,项目也可以正常运行,可是我们在编辑器输入@/相关的路径的时候却不会有提示,还会有报错显示找不到对应的文件,这是因为vite.config.ts里的配置是给vite用的,Vscode并不会读取这里面的配置,要让Vscode也能正确解析@/路径,需要在tsconfig.json里进行相关的配置。

我们在tsconfig.json里增加如下配置:

  "compilerOptions": {
    "baseUrl": ".",
    "paths": {
      "@/*": ["src/*"]
    }
  },

这个配置告诉Vscode,以tsconfig.json所在的当前目录作为根目录,遇到@/路径的时候,实际是指baseUrl加上src/,这样Vscode也能正确解析路径别名了。

编译脚本

我们可以在vite.config.ts里对如何构建生产版本做一些配置,具体可看配置文档,我们这边设置编译的版本为es2015,这是vite支持的最低版本。

  build: {
    target: 'es2015', // 构建出来的产物支持的环境
  },

集成Vue Router

首先安装Vue Router

pnpm install vue-router@4

然后我们在src目录下创建两个目录,一个views,一个router,这时候src下router相关的目录结构如下所示:

├─src
|  ├─App.vue
|  ├─main.ts
|  ├─views
|  |   ├─AboutView.vue
|  |   └HomeView.vue
|  ├─router
|  |   ├─index.ts
|  |   ├─modules
|  |   |    └base.ts
|  ├─components
|  |     ├─HelloTsx.tsx
|  |     └HelloWorld.vue

其中views用来保存页面组件

这里我们创建两个简单的页面组件:

// HomeView.vue
<template>
  <div>This is Home Page</div>
  <HelloTsx />
  <HelloWorld msg="Vite + Vue" />
</template>

<script setup lang="ts">
import HelloWorld from '@/components/HelloWorld.vue';
import HelloTsx from '@/components/HelloTsx';
</script>

<style scoped></style>
// AboutView.vue
<template>
  <div>This is About Page</div>
</template>

<script setup lang="ts"></script>

<style scoped></style>

componnets目录用来保存公共组件

这里我们保留之前创建的组件做演示。

router目录用来保存路由相关配置

同时router下有一个index.ts文件和modules目录,modules用来保存路由模块,路由可以根据功能或者不同的页面拆分到不同的modules中,然后在index.ts里进行整合,统一导出,这样当项目变复杂的时候可以保持路由的清晰并且多人合作可以尽量避免git合并冲突。

我们在modules目录下新建一个base.ts来设置我们的基本路由,如下:

// router/modules.base.ts
export default [
  {
    path: '/',
    name: 'home',
    component: () => import('@/views/HomeView.vue'),
  },
  {
    path: '/about',
    name: 'about',
    component: () => import('@/views/AboutView.vue'),
  },
];

router/index.ts负责整合和导出路由,代码如下:

import { createRouter, createWebHistory } from 'vue-router';

import baseRouters from './modules/base';

const routes = [...baseRouters];

const router = createRouter({
  history: createWebHistory(import.meta.env.BASE_URL),
  routes,
});

export default router;

这里我们使用的路由模式是webHistory,createWebHistory需要传我们项目的根路径进去,import.meta.env.BASE_URL默认是/,即index.html所在的目录。BASE_URL更详细的信息可以查看这里

App.vue是我们的根组件

App.vue加上路由后的简化代码如下所示:

<script setup lang="ts">
</script>

<template>
  <router-link to="/">Go to Home</router-link>
  <router-link to="/about">Go to About</router-link>
  <RouterView />
</template>

<style scoped>

</style>

main.ts使用路由

最后我们在main.ts里引入router并且use就可以了

// main.ts
import { createApp } from 'vue';
import './style.css';
import App from './App.vue';
import router from './router';

createApp(App).use(router).mount('#app');

集成Pinia

Pinia是Vue3官方推荐的全局状态管理工具。

首先安装Pinia

pnpm install pinia

创建src/store目录,其中具体的store都放在modules下,可以根据功能划分文件,index.ts文件负责创建和导出store实例以及modules下的方法。

src
├─store
|   ├─index.ts // store配置文件
|   ├─modules // store模块
|   |    └counter.ts // 负责存储counter的store

编写counter相关的store,src/store/modules/counter.ts,这里使用的是composition api的写法,也可以使用options api的写法,具体可看这个文档

import { defineStore } from 'pinia';
import { ref } from 'vue';

export const useCounterStore = defineStore('counter', () => {
  const count = ref(0);
  function increment() {
    count.value++;
  }

  return { count, increment };
});

在store/index.ts创建store示例,并且导出modules里的所有模块

import { createPinia } from 'pinia';

const store = createPinia();

export default store;

export * from './modules/counter';

在main.ts使用store插件

// main.ts
import { createApp } from 'vue';
import './style.css';
import App from './App.vue';
import router from './router';
import store from './store';

createApp(App).use(router).use(store).mount('#app');

然后我们就可以在我们的组件里使用store了,我们在刚才创建的views/AboutView.vue组件里添加上store的逻辑如下:

<template>
  <div>This is About Page</div>
  <button @click="increment">counter from store {{ count }}</button>
</template>

<script setup lang="ts">
import { useCounterStore } from '@/store';
import { storeToRefs } from 'pinia';
const counterStore = useCounterStore();
const { count } = storeToRefs(counterStore);
const { increment } = counterStore;
</script>

<style scoped></style>

在views/AboutView.vue里也添加上使用counterStore的逻辑:

<template>
  <div>This is Home Page</div>
  <button @click="increment">counter from store {{ count }}</button>
  <HelloTsx />
  <HelloWorld msg="Vite + Vue" />
</template>

<script setup lang="ts">
import HelloWorld from '@/components/HelloWorld.vue';
import HelloTsx from '@/components/HelloTsx';
import { useCounterStore } from '@/store';
import { storeToRefs } from 'pinia';
const counterStore = useCounterStore();
const { count } = storeToRefs(counterStore);
const { increment } = counterStore;
</script>

<style scoped></style>

基于Vite从0到1搭建一个Vue3相关的工程化模板项目

现在About和Home组件都可以使用和更改store里的counter,它们引用和更新的是同一个全局的状态。

集成element-plus

集成element-plus分为全量引入和按需引入,全量引入配置简单,按需引入不需要打包没使用的组件代码,我们当然是使用按需引入,相关文档可查看这里

首先我们需要安装element-plus

pnpm install element-plus

自动导入

然后我们需要安装两个插件

pnpm install -D unplugin-vue-components unplugin-auto-import

在vite.config.ts里使用这两个插件:

// vite.config.ts
import { defineConfig } from 'vite'
import AutoImport from 'unplugin-auto-import/vite'
import Components from 'unplugin-vue-components/vite'
import { ElementPlusResolver } from 'unplugin-vue-components/resolvers'

export default defineConfig({
  // ...
  plugins: [
    // ...
    AutoImport({
      resolvers: [ElementPlusResolver()],
    }),
    Components({
      resolvers: [ElementPlusResolver()],
    }),
  ],
})

使用这两个插件后,当我们在Vue模板里使用某个组件的时候

 <ElMessage />

会自动帮我们引入这个组件相关的代码,这个功能是在编译的时候由插件完成的。

import 'element-plus/es/components/message/style/css'
import { ElMessage } from 'element-plus'

Volar支持

使用Vue3,Vscode需要安装了Volar插件(相当于Vue2的Vetur),为了在我们开发的过程中有更好的element类型提示,我们需要设置对应的type,我们可以在tsconfig.json 中通过 compilerOptions.type 指定全局组件类型。

// tsconfig.json
{
  "compilerOptions": {
    // ...
    "types": ["element-plus/global"]
  }
}

这样当我们写组件的时候就会有很好的类型提示:

基于Vite从0到1搭建一个Vue3相关的工程化模板项目

集成Icon

Element Plus提供了很多Icon,我们也可以进行配置支持自动导入,官方文档看这里

首先安装下插件:

pnpm install unplugin-icons -D

然后按照官方推荐进行配置:

/// <reference types="vitest" />
import { defineConfig } from 'vite';
import Icons from 'unplugin-icons/vite';
import IconsResolver from 'unplugin-icons/resolver';
import AutoImport from 'unplugin-auto-import/vite';
import Components from 'unplugin-vue-components/vite';
import { ElementPlusResolver } from 'unplugin-vue-components/resolvers';

// https://vitejs.dev/config/
export default defineConfig({
  plugins: [
    AutoImport({
      resolvers: [
        ElementPlusResolver(),

        // Auto import icon components
        // 自动导入图标组件
        IconsResolver({
          prefix: 'Icon',
        }),
      ],
    }),
    Components({
      resolvers: [
        // Auto register icon components
        // 自动注册图标组件
        IconsResolver({
          enabledCollections: ['ep'],
        }),

        ElementPlusResolver(),
      ],
    }),
    Icons({
      autoInstall: true,
    }),
  ],
});

配置好后就可以直接使用Icon了,我们在Element Icon页面点击一个图标会复制得到以下的组件:

<el-icon><Coffee /></el-icon>

我们需要在Icon前面加上IEp,也就是改成这样:

<el-icon><IEpCoffee /></el-icon>

然后就可以使用了,这个原理是编译的时候插件会对IEp开头的组件做处理,自动导入相关组件。

全局样式

在src目录下创建styles目录,并创建index.scss用来放置全局样式。

支持Sass

直接安装Sass就可以了,Vite内部已经配置好了对Sass文件的解析规则。

pnpm install sass -D

支持Element API组件样式

我们在Element自动导入组件的地方发现有这么一段警告: 基于Vite从0到1搭建一个Vue3相关的工程化模板项目

这意思是如果我们使用的组件只当作API用,不当做组件用,也就是只使用ElMessage({})这种方式,不使用<ElMessage />这种方式,那么自动导入插件是不会帮我们自动导入样式的,原理应该是自动导入插件只会检查模板里面的Element组件。

所以我们对使用的这种插件,统一在styles下导入样式,创建styles/elementCom.ts文件,输入如下内容:

import 'element-plus/es/components/message/style/css';

如果有新增的API组件,我们也把样式放到这个文件就好了。

然后我们在main.ts里引入两个样式:

import '@/styles/index.scss';
import '@/styles/elementCom';

集成Axios


持续更新中...

转载自:https://juejin.cn/post/7174643560594014245
评论
请登录