Skip to content

Vue3+Vite+Ts 项目搭建

这次的项目搭建将会在项目中集成一下功能:

  • eslint 代码规范
  • alias 开发路径别名
  • unplugin-auto-import 按需导入 API
  • unplugin-vue-components 自动导入组件
  • unocss 样式库
  • 代码 commit 规范
  • unplugin-vue-macros

相较于之前的 simple-vite-template-v2 项目模板,本次的项目搭建移除了以下功能:

  • markdown 转换为 vue 组件的功能
  • @unocss/preset-icons 使用

如果需要使用以上功能,可以参考 simple-vite-template-v2

项目初始化

bash
# 创建项目
pnpm create vite vite-vue3-ts-template --template vue-ts
# 进入项目
cd vite-vue3-ts-template

配置 pnmp

创建 .npmrc

bash
touch .npmrc

pnpm 可以从 .npmrc 获取配置

ini
shamefully-hoist=true
strict-peer-dependencies=false
shell-emulator=true
fetch-retries=5
fetch-retry-mintimeout=200000
fetch-retry-maxtimeout=1200000
fetch-timeout=1800000
registry=https://registry.npm.taobao.org

很多时候网络原因包下载不下来,这里的 fetch-retries、fetch-retry-maxtimeout、fetch-timeout、registry 可以根据自己的网络情况决定是否配置。

bash
# 安装依赖
pnpm install
# 启动项目
pnpm run dev

配置 eslint

安装依赖

bash
pnpm add -D eslint @antfu/eslint-config

配置 eslint

在项目下创建 .eslintrc 文件

bash
touch .eslintrc

.eslintrc 内容如下

json
{
  "extends": "@antfu"
}

package.json 加入如下 script

json
{
  "scripts": {
    "lint": "eslint .",
    "lint:fix": "eslint . --fix"
  }
}

配置 vscode

安装 eslint 扩展

添加如下配置到项目根目录下的 .vscode/settings.json 文件

json
{
  "prettier.enable": false,
  "editor.formatOnSave": false,
  "editor.codeActionsOnSave": {
    "source.fixAll.eslint": true,
    "source.organizeImports": false
  },

  // The following is optional.
  // It's better to put under project setting `.vscode/settings.json`
  // to avoid conflicts with working with different eslint configs
  // that does not support all formats.
  "eslint.validate": [
    "javascript",
    "javascriptreact",
    "typescript",
    "typescriptreact",
    "vue",
    "html",
    "markdown",
    "json",
    "jsonc",
    "yaml"
  ]
}

配置 alias

vite.config.ts 中配置 alias,添加如下代码

js
import path from 'node:path'
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'

// https://vitejs.dev/config/
export default defineConfig({
  base: './',  
  plugins: [vue()],
  resolve: {  
    alias: {  
      '@': path.resolve(__dirname, './src'),  
    },  
  },  
})

配置如上代码后会发现找不到模块“node:path”或其相应的类型声明和找不到名称“__dirname”。这是因为 vite 是基于 esm 的,所以需要安装 @types/node,添加如下代码

bash
pnpm add -D @types/node

然后关闭页面重写打开,就可以正常了。(如果还是不行,可以尝试重启编辑器)

配置 unplugin-auto-import

详细配置请参考 unplugin-auto-import

unplugin-auto-import 可以为 vite 按需导入 API,一般情况下代码如下:

js
import { computed, ref } from 'vue'

const count = ref(0)
const doubled = computed(() => count.value * 2)

使用 unplugin-auto-import 后,可以这样写:

js
const count = ref(0)
const doubled = computed(() => count.value * 2)

安装依赖

bash
pnpm add -D unplugin-auto-import

vite.config.ts 中配置 unplugin-auto-import,添加如下代码

js
import path from 'node:path'
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import AutoImport from 'unplugin-auto-import/vite'

// https://vitejs.dev/config/
export default defineConfig({
  base: './',
  plugins: [
    vue(),
    // https://github.com/unplugin/unplugin-auto-import
    AutoImport({
      imports: [
        // 预设
        'vue',
        // 'vue-router',
        // 'vuex',

        // 自定义
        {
          '@vueuse/core': [
            'useMouse', // import { useMouse } from '@vueuse/core',
            // alias
            ['useFetch', 'useMyFetch'], // import { useFetch as useMyFetch } from '@vueuse/core',
          ],
        },
      ],
      dts: 'types/auto-imports.d.ts',
      // 自动导入目录下的模块导出
      // 默认情况下,它只会扫描目录下的一个级别的模块
      dirs: [
        // './hooks',
        // './composables' // 只有根模块
        // './composables/**', // 所有嵌套模块
        // ...
      ],
    }),
  ],
  resolve: {
    alias: {
      '@': path.resolve(__dirname, './src'),
    },
  },
})

这是你如果在 vue 文件中测试如下代码

vue
<script setup lang="ts">
const msg = ref(666)
</script>

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

你会发现报了找不到名称“ref”的错误,这时候需要在 tsconfig.json 加入如下代码

json
{
  "include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.vue", "types/**/*.d.ts"]
}

这时候你会发现报了找不到名称“ref”的错误没有了~

配置 unplugin-vue-components

详细配置请参考 unplugin-vue-components

安装依赖

bash
pnpm add -D unplugin-vue-components

vite.config.ts 中配置 unplugin-vue-components,添加如下代码

js
import path from 'node:path'
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import AutoImport from 'unplugin-auto-import/vite'
import Components from 'unplugin-vue-components/vite'

// https://vitejs.dev/config/
export default defineConfig({
  base: './',
  plugins: [
    vue(),
    // https://github.com/unplugin/unplugin-auto-import
    AutoImport({
      imports: [
        // 预设
        'vue',
        // 'vue-router',
        // 'vuex',

        // 自定义
        {
          '@vueuse/core': [
            'useMouse', // import { useMouse } from '@vueuse/core',
            // alias
            ['useFetch', 'useMyFetch'], // import { useFetch as useMyFetch } from '@vueuse/core',
          ],
        },
      ],
      dts: 'types/auto-imports.d.ts',
      // 自动导入目录下的模块导出
      // 默认情况下,它只会扫描目录下的一个级别的模块
      dirs: [
        // './hooks',
        // './composables' // 只有根模块
        // './composables/**', // 所有嵌套模块
        // ...
      ],
    }),
    // https://github.com/unplugin/unplugin-vue-components
    Components({
      // 允许自动导入
      include: [/\.vue$/, /\.vue\?vue/],
      dts: 'types/components.d.ts',
    }),
  ],
  resolve: {
    alias: {
      '@': path.resolve(__dirname, './src'),
    },
  },
})

这时候如果删除 App.vue 中引入的组件,会发现在未引入组件的情况下,组件也可以正常使用,这是因为 unplugin-vue-components 会自动导入组件

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

规范化项目 commit

初始化 git

bash
git init

安装相关依赖

bash
pnpm install @commitlint/cli @commitlint/config-conventional cz-git czg husky lint-staged @esbuild-kit/cjs-loader -D

在项目根目录创建 commitlint.config.cjscommitlint.config.ts

commitlint.config.cjs 内容如下:

js
module.exports = require('./commitlint.config.ts').default

commitlint.config.ts 内容如下:

ts
import { execSync } from 'node:child_process'

const scopes = [
  'views',
  'components',
  'router',
  'store',
  'utils',
  'styles',
  'assets',
  'types',
  'other',
]

const gitStatus = execSync('git status --porcelain || true')
  .toString()
  .trim()
  .split('\n')

const scopeComplete = gitStatus
  .find(r => ~r.indexOf('M  src'))
  ?.replace(/(\/)/g, '%%')
  ?.match(/src%%((\w|-)*)/)?.[1];

const subjectComplete = gitStatus
  .find(r => ~r.indexOf('M  src'))
  ?.replace(/\//g, '%%')
   ?.match(/src%%((\w|-)*)/)?.[1];

export default {
  rules: {
    /**
     * type[scope]: [function] description
     *      ^^^^^
     */
    'scope-enum': [2, 'always', scopes],
    /**
     * type[scope]: [function] description
     *
     * ^^^^^^^^^^^^^^ empty line.
     * - Something here
     */
    'body-leading-blank': [1, 'always'],
    /**
     * type[scope]: [function] description
     *
     * - something here
     *
     * ^^^^^^^^^^^^^^
     */
    'footer-leading-blank': [1, 'always'],
    /**
     * type[scope]: [function] description [No more than 72 characters]
     *      ^^^^^
     */
    'header-max-length': [2, 'always', 72],
    'scope-case': [2, 'always', 'lower-case'],
    'subject-case': [
      1,
      'never',
      ['sentence-case', 'start-case', 'pascal-case', 'upper-case'],
    ],
    'subject-empty': [2, 'never'],
    'subject-full-stop': [2, 'never', '.'],
    'type-case': [2, 'always', 'lower-case'],
    'type-empty': [2, 'never'],
    /**
     * type[scope]: [function] description
     * ^^^^
     */
    'type-enum': [
      2,
      'always',
      [
        'build',
        'chore',
        'ci',
        'docs',
        'feat',
        'fix',
        'perf',
        'refactor',
        'revert',
        'release',
        'style',
        'test',
        'improvement',
      ],
    ],
  },
  prompt: {
    defaultScope: scopeComplete,
    customScopesAlign: !scopeComplete ? 'top' : 'bottom',
    defaultSubject: subjectComplete && `[${subjectComplete}] `,
    allowCustomIssuePrefixs: false,
    allowEmptyIssuePrefixs: false,
  },
}

修改 package.json

json
{
  "scripts": {
    "cz": "czg",
  },
  "config": {
    "commitizen": {
      "path": "./node_modules/cz-git"
    }
  },
  "lint-staged": {
    "*.{vue,js,ts,jsx,tsx,md,json}": "eslint --fix"
  }
}

配置 husky

执行 init

bash
npx husky-init

添加 hooks

bash
npx husky add .husky/commit-msg 'pnpm exec commitlint --config commitlint.config.cjs --edit "${1}"'

这时候会发现项目根目录下创建了 .husky 文件夹,.husky 结构如下:

📦.husky
 ┣ 📂_
 ┃ ┣ 📜.gitignore
 ┃ ┗ 📜husky.sh
 ┣ 📜commit-msg
 ┗ 📜pre-commit

commit-msg 内容修改如下:

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

pnpm exec commitlint --config commitlint.config.cjs --edit "${1}"

pre-commit 内容修改如下:

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

pnpm exec lint-staged

配置 unocss

安装依赖

bash
pnpm add -D unocss

配置 vite.config.ts

js
// vite.config.ts
import UnoCSS from 'unocss/vite'
import { defineConfig } from 'vite'

export default defineConfig({
  plugins: [
    UnoCSS(),
  ],
})

配置 uno.config.ts

ts
import {
  defineConfig,
  presetAttributify,
  presetIcons,
  presetTypography,
  presetUno,
  presetWebFonts,
  transformerDirectives,
  transformerVariantGroup,
} from 'unocss'

export default defineConfig({
  shortcuts: [
  ],
  presets: [
    presetUno(),
    presetAttributify(),
    presetIcons({
      scale: 1.2,
      warn: true,
    }),
    presetTypography(),
    presetWebFonts({
      fonts: {
        sans: 'DM Sans',
        serif: 'DM Serif Display',
        mono: 'DM Mono',
      },
    }),
  ],
  transformers: [
    transformerDirectives(),
    transformerVariantGroup(),
  ],
  safelist: 'prose prose-sm m-auto text-left'.split(' '),
})

引入样式

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

import '@unocss/reset/tailwind.css'
import 'uno.css'

createApp(App).mount('#app')

配置 eslint

安装 @unocss/eslint-config

这里配置的 eslint 是为了代码顺序更加美观,如果不需要可以不配置

bash
pnpm add -D @unocss/eslint-config

.eslintrc 中加入:

json
{
  "extends": [
    "@antfu",
    "@unocss"
  ],
  "rules": {
    "@unocss/order": "error",
    "@unocss/order-attributify": "error"
  }
}

安装 unocss 扩展

antfu.unocss

注意

这时候如果在代码中写样式没有提示的话,请把 .vscode/settings.json 中的 editor.quickSuggestions 设置下

json
{
  "editor.quickSuggestions": {
    "strings": "on"
  }
}

上面配置好后,如果写 unocss 的样式 vscode 还是没有提示的话,请重启编辑器!!!

配置 unplugin-vue-macros

安装依赖

bash
pnpm add -D unplugin-vue-macros

配置 vite.config.ts

ts
import path from 'node:path'
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import AutoImport from 'unplugin-auto-import/vite'
import Components from 'unplugin-vue-components/vite'
import VueMacros from 'unplugin-vue-macros/vite'

import UnoCSS from 'unocss/vite'

// https://vitejs.dev/config/
export default defineConfig({
  base: './',
  plugins: [
    // vue(),
    VueMacros({ 
      plugins: { 
        vue: vue(), 
      }, 
    }), 
    // https://github.com/unplugin/unplugin-auto-import
    AutoImport({
      imports: [
        // 预设
        'vue',
        // 'vue-router',
        // 'vuex',

        // 自定义
        {
          '@vueuse/core': [
            'useMouse', // import { useMouse } from '@vueuse/core',
            // alias
            ['useFetch', 'useMyFetch'], // import { useFetch as useMyFetch } from '@vueuse/core',
          ],
        },
      ],
      dts: 'types/auto-imports.d.ts',
      // 自动导入目录下的模块导出
      // 默认情况下,它只会扫描目录下的一个级别的模块
      dirs: [
        // './hooks',
        // './composables' // 只有根模块
        // './composables/**', // 所有嵌套模块
        // ...
      ],
    }),
    // https://github.com/unplugin/unplugin-vue-components
    Components({
      // 允许自动导入
      include: [/\.vue$/, /\.vue\?vue/],
      dts: 'types/components.d.ts',
    }),

    UnoCSS(),
  ],
  resolve: {
    alias: {
      '@': path.resolve(__dirname, './src'),
    },
  },
})

添加 ts 支持

tsconfig.json 中加入如下配置:

json
// tsconfig.json
{
  "compilerOptions": {
    // ...
    "types": ["unplugin-vue-macros/macros-global" /* ... */]
  }
}

添加 Volar 支持

bash
pnpm add -D @vue-macros/volar

tsconfig.json 中加入如下配置:

json
// tsconfig.json
{
  "vueCompilerOptions": {
    "plugins": [
      "@vue-macros/volar/define-options",
      "@vue-macros/volar/define-models",
      "@vue-macros/volar/define-props",
      "@vue-macros/volar/define-props-refs",
      "@vue-macros/volar/short-vmodel",
      "@vue-macros/volar/define-slots",
      "@vue-macros/volar/jsx-directive"
    ]
  }
}

修改 .vscode/extensions.json

json
{
  "recommendations": [
    "Vue.volar",
    "Vue.vscode-typescript-vue-plugin",
    "antfu.iconify",
    "antfu.unocss",
    "antfu.vite",
    "antfu.goto-alias",
    "csstools.postcss",
    "dbaeumer.vscode-eslint",
    "streetsidesoftware.code-spell-checker"
  ]
}

修改后 vscode 会自动安装这些插件,如果不需要可以删除。

总结

至此,一个基于 Vue3+Vite+Ts 的项目搭建完成!

项目集成了以下功能:

  • eslint 代码规范
  • alias 开发路径别名
  • unplugin-auto-import 按需导入 API
  • unplugin-vue-components 自动导入组件
  • unocss 样式库
  • 代码 commit 规范