【初始化项目 Vite Vue】

259 阅读3分钟

初始化

Node 版本 V18

使用 NPM:

$ npm init vite@latest 项目名

使用 Yarn:

$ yarn create vite@latest 项目名

激活PNPM

corepack prepare pnpm --activate

使用 PNPM:

$ pnpm create vite

选择框架 Vue,其他步骤如下:

Customize with create-vue 自定义
Add TypeScript? ye
Add JSX Support? jsx yes
Add Vue Router for Single Page Application development? router yes
Add Pinia for state management? pinia ~ yes
Add Vitest for Unit Testing? 测试用例 ~ yes
Add an End-to-End Testing Solution? 端到端测试解决方案 ~ Cypress
Add ESLint for code quality? eslint ~ yes
Add Prettier for code formatting? 格式化 ~ yes

依赖

pnpm install

或者直接指定项目名称和你想要使用的模板: github.com/vitejs/vite…

npm create vite@latest my-vue-app --template vue
yarn create vite my-vue-app --template vue
pnpm create vite my-vue-app --template vue

样式相关

Sass

vite 不需要安装 sass-loader

pnpm i -D sass

reset-css

reset 重置浏览器所有的默认样式,normalize 保留有用的默认CSS样式尽可能减少不同浏览器差异

pnpm install reset-css

main.ts

import 'reset-css'

tailwindcss

该依赖包含 reset-css

pnpm install -D tailwindcss@3.4.17 postcss autoprefixer

执行命令创建:tailwind.config.js 和 postcss.config.js

npx tailwindcss init -p

tailwind.config.js

/** @type {import('tailwindcss').Config} */
export default {
  content: [
    './index.html', // 入口文件
    './src/**/*.{vue,js,ts,jsx,tsx}' // 解析文件
  ],
  theme: {
    extend: {}
  },
  plugins: []
}

.vscode / settings.json

{
  "css.lint.unknownAtRules": "ignore" // 忽略未知的css规则
}

文件 assets/main.css 导入模块

@tailwind base;
@tailwind components;
@tailwind utilities;

入口文件 main.ts 导入

import './assets/main.css'

unocss

pnpm add unocss@0.63.4 @unocss/reset@0.63.4 -D 

vite.config.ts

import UnoCss from 'unocss/vite'
export default defineConfig({
  plugins: [
    UnoCss()
  ],
})

测试

<template>
    <h1 class="text-3xl font-bold underline">tailwind</h1>
</template>

根目录创建 uno.config.ts

import { defineConfig } from 'unocss'
export default defineConfig({})

main.ts

import 'virtual:uno.css'
// import '@unocss/reset/tailwind.css' // tailwind reset
import '@unocss/reset/normalize.css' // 二选一

unocss 和 tailwind 一起使用

pnpm add @unocss/preset-wind@0.63.4 -D

更改配置 uno.config.ts

import { defineConfig } from 'unocss'
import presetWind from '@unocss/preset-wind'
export default defineConfig({
  presets: [presetWind()]
})

测试

<template>
    <h1 class="p-4">unocss</h1>
</template>

TS

如果版本是 V4 建议升级 5.0 版本

pnpm add @vue/tsconfig @types/node -D 

不同版本配置 tsconfig.app.json

"extends": "@vue/tsconfig/tsconfig.dom.json", // Vue 官方提供的 TypeScript 5 基础配置文件
// "extends": "@vue/tsconfig/tsconfig.web.json", // ts 4

tsconfig.node.json

"extends": [
  "@tsconfig/node22/tsconfig.json",
  "@vue/tsconfig/tsconfig.json"
    
  // Node 20 TS5
  // "@tsconfig/node20/tsconfig.json"

  // Node 18 TS5
  // "@tsconfig/node18/tsconfig.json",
  // "@vue/tsconfig/tsconfig.json"

  // Node 18 TS4
  // "@vue/tsconfig/tsconfig.node.json"
],

自动化路由

vite-plugin-pages

只支持 vite

pnpm install -D vite-plugin-pages

vite.config.ts

import Pages from 'vite-plugin-pages'
export default defineConfig({
  plugins: [
    Pages({
      dirs:['src/views'] // 默认为 pages 、将 view 文件夹设置成自动路由的路径
    })
  ]
})

router > index.ts

import { createRouter, createWebHistory } from 'vue-router'
import routes from '~pages'
const router = createRouter({
  // history 底层是 history api pushState replaceState popstate
  history: createWebHistory(import.meta.env.BASE_URL),
  routes
})

env.d.ts

/// <reference types="vite-plugin-pages/client" />

views 文件名即路由名,views 下创建 index.vue( 默认/ )直接访问

<template>
  <div>hello</div>
</template>
<script setup lang="ts"></script>

404页:[...all].vue

<template>
  <div>404 Not Found</div>
</template>
<script setup lang="ts"></script>

重定向方案

拦截器重定向 router / index.ts

router.beforeEach((to, from, next) => {
  if (to.path === '/home') {
    next('/')
  }
  next()
})

编程式:home.vue

<script setup lang="ts">
	import { useRouter } from 'vue-router'
	const router = useRouter()
	router.push('/')
</script>

vite.config.ts

export default defineConfig({
  plugins: [
    Pages({
      extendRoute(route) {
        if (route.path === '/home') {
          return { ...route, redirect: '/' }
        }
        return route
      }
    })
  ],
})

官方推荐:home.vue

<route lang="yaml">
name: home
redirect: /
</route>
<route lang="yaml">
{ name: 'home', redirect: '/' }
</route>

unplugin-vue-router

vite / webpack 均支持

pnpm add -D unplugin-vue-router@0.6.4

vite.config.ts

import VueRouter from 'unplugin-vue-router/vite'
export default defineConfig({
  plugins: [
    VueRouter({}), // 在 vue() 之前
    vue(),
  ]
})

router > index.ts

import { createRouter, createWebHistory } from 'vue-router/auto'
const router = createRouter({
  history: createWebHistory(import.meta.env.BASE_URL)
})

设置自动导入文件时需要排除的模式,希望手动导入 vue-router,而不是通过自动导入来处理它。

.vscode > settings.json

{
  "typescript.preferences.autoImportFileExcludePatterns": ["vue-router"]
}

tsconfig.app.json

{
  "include": [
    // ...
    "typed-router.d.ts" // 启动项目自动生成声明配置
  ],
  "compilerOptions": {
    // 解决路由自动引入TS错误,按照 commonJs 解析模块
    // bundler 会交由打包工具作为解析(如webpack rollup vite)
    "moduleResolution": "node"
  }
}


创建 pages 文件夹

创建 index.vue,默认路由 /

<template>
  <div class="home">index</div>
</template>

创建 404 模板, [...all].vue

<template>
  <div class="error-page">Not Found</div>
</template>
<script setup lang="ts"></script>
<style scoped></style>

自动导入

导入依赖

自动导入 JavaScript 包中的模块,并将其添加到项目中的代码中。

pnpm i -D unplugin-auto-import@0.16.6

vite.config

import AutoImport from 'unplugin-auto-import/vite' // 自动导入依赖
import { VueRouterAutoImports } from 'unplugin-vue-router' // 帮助简化 Vue Router 的使用
export default defineConfig({
  plugins: [
    AutoImport({
      include: [
        /\.[tj]sx?$/, // .ts, .tsx, .js, .jsx
        /\.vue$/,
        /\.vue\?vue/, // .vue
        /\.md$/ // .md
      ],
      imports: [
        'vue',
        // 'vue-router', // 如果不使用自动化路由
        VueRouterAutoImports // 如已配置自动路由、代替 vue-router
      ]
    })
  ],
})

tsconfig.app.json

"include": [
  "auto-imports.d.ts" // unplugin-auto-import 自动导入
],

示范

<template>
	<h2>{{ msg }}</h2>
</template>
<script setup lang="ts">
const msg = ref('hello')
</script>

导入组件

pnpm add unplugin-vue-components@0.27.4 -D
pnpm i element-plus

vite.config

import Components from 'unplugin-vue-components/vite' // 自动组件导入
import { ElementPlusResolver } from 'unplugin-vue-components/resolvers' // 自动导入 element-plus
export default defineConfig({
  plugins: [
    // 自动导入组件
    Components({
      // 如 User 文件下的 user.vue 直接使用 <Useruser></Useruser>
      directoryAsNamespace: true, // 以文件名开头作为前缀,因为一些组件会重名
      // 如 User 文件下的 user.vue 直接使用 <User></User>
      collapseSamePrefixes: true, // 如果文件名和组件前缀一致,则省略
      resolvers: [
          ElementPlusResolver()  // 集成 element-plus
      ]
    })
  ]
})

测试

<template>
  <div class="container">
    <HelloWorld msg="Hello" />
    <el-button type="primary">Default</el-button>
  </div>
</template>
<script setup lang="ts"></script>

Hooks

@vueuse/core 是一个集合了许多实用工具函数的库,旨在简化日常开发中的常见需求,这些工具函数涵盖了状态管理、事件监听、浏览器交互等多个方面

pnpm i @vueuse/core@10.2.1

vite.config.ts

    AutoImport({
      include: [
        /\.[tj]sx?$/, // .ts, .tsx, .js, .jsx
        /\.vue$/,
        /\.vue\?vue/, // .vue
        /\.md$/, // .md
      ],
      imports: [
        'vue',
        // 'vue-router', // 如果不使用自动化路由
        VueRouterAutoImports, // 自动路由专用 - 代替 vue-router
        '@vueuse/core', //  提供一些常用的 hooks,vue 3.3 以后不需要
      ],
    }),

组件中使用:

<template>
  <div ref="target">
    x:{{ x }} ,y:{{ y }} ,isOutside:{{ isOutside }}
  </div>
</template>
<script setup lang="ts">
// import {useMouseInElement} from '@vueuse/core' // 如果没有配置自动导入
const target = ref(null)
const { x, y, isOutside } = useMouseInElement(target)
</script>

图标集

如果使用 tailwind 类似没有提供图标集的CSS框架,即可使用此工具; 简化项目中的图标管理,允许应用中轻松引入并使用各种流行的图标库(如 Material Design Icons, Font Awesome 等);

pnpm i -D unplugin-icons@0.22.0

配置自动导入,按需加载。vite.config.ts

import Components from 'unplugin-vue-components/vite'
import Icons from 'unplugin-icons/vite'
import IconsResolver from 'unplugin-icons/resolver'
export default defineConfig({
  plugins: [
    // 自动导入组件
    Components({
       // ...
      resolvers: [
        // 集成图标集
        IconsResolver({
          prefix: 'icon' // 私有前缀
        })
      ]
    }),
    Icons({
      autoInstall: true // 自动安装所需图标集
    })
  ]
})

测试

<template>
  <div>
    <icon-mdi-account style="color: red" />
  </div>
</template>

@iconify/json

pnpm i -D @iconify/json@2.2.260

uno.config.ts

import { defineConfig } from 'unocss'
import { presetWind, presetIcons } from 'unocss' // tailwind unocss  一起使用

export default defineConfig({
  presets: [
    presetWind(), // 样式一起使用
    // 图标一起使用
    presetIcons({
      prefix: 'i-', // 图标前缀
      extraProperties: {
        display: 'inline-block', // 图标样式
      },
    }),
  ],
})

<template>
	<div class="i-logos-vue"></div>
</template>

其他图标集推荐: react-icons lucide heroicons pikaicons

自动布局 layouts

pnpm i -D vite-plugin-vue-layouts

vite.config.ts

import Layouts from 'vite-plugin-vue-layouts'
export default defineConfig({
  plugins: [
    Layouts({
      layoutsDirs: 'src/layouts', // 指定布局文件(Layout)的目录路径
      defaultLayout: 'default' // 指定默认布局文件的名称
    })
  ]
}) 

env.d.ts

/// <reference types="vite-plugin-vue-layouts/client" />

tsconfig.json

"types": ["vite-plugin-vue-layouts/client"]

router > main.ts

import { createRouter, createWebHistory } from 'vue-router/auto'
import { setupLayouts } from 'virtual:generated-layouts'
const router = createRouter({
  history: createWebHistory(import.meta.env.BASE_URL), // 路由的历史模式
  // 扩展路由配置。它接受一个路由配置数组作为参数,并返回包含布局配置的新路由配置。
  extendRoutes: (routes) => setupLayouts(routes)
})

创建 layouts 文件夹 > layouts 组件,如 default.vue

<template>
  <div>
    im defult layouts
    <router-view></router-view>
  </div>
</template>

pages 文件夹 > index.vue

<template>
  <div>
    <RouterLink to="/">home</RouterLink> |
    <RouterLink to="/about">about</RouterLink>
  </div>
</template>

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

<route lang="yaml">
meta:
  layout: default
</route>

版本 > 3.3 不需要

pnpm add -D unplugin-vue-macros @vue-macros/volar

vite.config.ts

plugins: [
    // vue(),
    // vueJsx(),
    // 代替以上
    VueMacros({
      plugins: {
        vue: vue(),
        vueJsx: vueJsx()
      }
    })
]

示范

<template>
    <button @click="handleClick">Click me</button>
</template>

<script setup lang="ts">
const num = ref(0)

// macros
const emits = defineEmits<{
  (e: 'clickCount', num: number): void
}>()

// 官方:
// const emits2 = defineEmits<
//   SE<{
//     clickCount(num: number): void
//   }>
// >()

const handleClick = () => {
  console.log('click')
  emits('clickCount', ++num.value)
}
</script>

mock

pnpm add mockjs vite-plugin-mock -D

vite.config.ts

import { viteMockServe } from 'vite-plugin-mock'
export default defineConfig({
  plugins: [
    viteMockServe({
      mockPath: 'mock', // 模拟接口数据的文件存放在项目根目录下的 ‘mock’ 文件夹中。
      enable: true // 是否启用模拟接口数据
    })
  ]
})

根目录创建 mock 文件夹 >text.ts

import type { MockMethod } from 'vite-plugin-mock'
import fs from 'fs'
import path from 'path'
// 模拟数据
export default [
  {
    url: '/api/get', // 访问 http://localhost:5173/api/get
    method: 'get',
    response: () => {
      return {
        code: 0,
        data: {
          name: 'zs'
        }
      }
    }
  }
] as MockMethod[]

Pwa

pnpm add -D vite-plugin-pwa

vite.config.ts

import { VitePWA } from 'vite-plugin-pwa'
export default defineConfig({
	plugins: [
	     VitePWA({
      registerType: 'autoUpdate' // 自动更新
    }),
	]
})

env.d.ts

/// <reference types="vite-plugin-pwa/client" />

演示

import { registerSW } from 'virtual:pwa-register'
onMounted(() => {
  registerSW({
    immediate: true, // 立即注册
    // pwa 注册完成 回调
    onRegisteredSW(url, reg) {},
    // 提示文件需要更新
    onNeedRefresh() {
      console.log('need refresh')
    }
  })
})

vite 5

pnpm i -D workbox-window

打包目录:

registerSW.js:注册 serviceWorker 文件
sw.js:文件核心信息记录