vite-vue-ts 脚手架快速搭建

340 阅读5分钟

1. 初始化vite项目

pnpm create vite

2. vscode配置

插件

  • Vue Language Features (Volar) // 代码高亮,语法提示等
  • TypeScript Vue Plugin (Volar) // 支持在ts中 import .vue文件
  • ESlint // 代码错误检查

注意:注释 Vetur 插件,避免冲突

settings.json

配置.vscode/settings.json

{
    "editor.codeActionsOnSave": {
        "source.fixAll.eslint": true
    },
    "editor.formatOnType": true
}

3. 修改eslint配置

这里引用Alloy Team 团队的规范(eslint-config-alloy

pnpm add -D  @babel/core @babel/eslint-parser @typescript-eslint/eslint-plugin @typescript-eslint/parser @vue/eslint-config-typescript eslint eslint-config-alloy eslint-plugin-vue vue-eslint-parser

.eslintrc.cjs

module.exports = {
  extends: ['alloy', 'alloy/vue', 'alloy/typescript'],
  root: true,
  parser: "vue-eslint-parser",
  parserOptions: {
    parser: {
      sourceType: "module",
      js: "@babel/eslint-parser",
      jsx: "@babel/eslint-parser",
      ts: "@typescript-eslint/parser",
      tsx: "@typescript-eslint/parser",
      project: './vite.config.ts',
    }
  },
  env: {
    browser: true,
    node: true
  },
  globals: {},
  rules: {
    '@typescript-eslint/prefer-optional-chain': 'off',
    'no-undef': 'off',
  }
}

添加vite-plugin-eslint,运行时eslint校验,控制台显示报错

pnpm add -D vite-plugin-eslint

vite.config.js

import { fileURLToPath, URL } from 'node:url';
import { defineConfig } from 'vite';
import vue from '@vitejs/plugin-vue';
import vueJsx from '@vitejs/plugin-vue-jsx';
+ import eslint from 'vite-plugin-eslint';

// https://vitejs.dev/config/
export default defineConfig({
  plugins: [
    vue(),
    vueJsx(),
+   eslint(),
  ],
  resolve: {
    alias: {
      '@': fileURLToPath(new URL('./src', import.meta.url)),
    },
  },
});

4. eslint托管prettier

将 prettier 作为 ESLint 的规则来使用

pnpm add -D eslint-config-prettier

.eslintrc.cjs

module.exports = {
- extends: ['alloy', 'alloy/vue', 'alloy/typescript'],
+ extends: ['alloy', 'alloy/vue', 'alloy/typescript', 'prettier'],
+ plugins: ['prettier'],
  rules: {
+   'prettier/prettier': 'error',
    '@typescript-eslint/prefer-optional-chain': 'off',
    'no-undef': 'off',
  },
  ...
};

根目录新增 .prettierrc文件,使用 alloy 的prettier规范

.prettierrc

"eslint-config-alloy/.prettierrc.js"

5. 运行时,ts类型检查配置

pnpm add -D vite-plugin-checker
pnpm add -D vue-tsc

vite.config.js

import { fileURLToPath, URL } from 'node:url';
import { defineConfig } from 'vite';
import vue from '@vitejs/plugin-vue';
import vueJsx from '@vitejs/plugin-vue-jsx';
import eslint from 'vite-plugin-eslint';
+ import checker from 'vite-plugin-checker';

// https://vitejs.dev/config/
export default defineConfig({
  plugins: [
    vue(),
    vueJsx(),
    eslint(),
+   checker({
+    typescript: true,
+    vueTsc: true,
+   }),
  ],
  resolve: {
    alias: {
      '@': fileURLToPath(new URL('./src', import.meta.url)),
    },
  },
});

ts文件无法识别vue文件的导入。定义vue模块,ts识别.vue文件为vue模块。

env.d.ts

/// <reference types="vite/client" />

+ declare module '*.vue' {
+  import { ComponentOptions } from 'vue';
+  const componentOptions: ComponentOptions;
+  export default componentOptions;
+ }

6. husky + lint-stage 内容提交检测

pnpm dlx husky-init && pnpm install # pnpm
pnpm add -D lint-staged

./husky/pre-commit

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

echo husky running
npx lint-staged

新增 .lintstagedrc.json

+ {
+   "*.js": ["eslint --fix"],
+   "*.jsx": ["eslint --fix"],
+   "*.ts": ["eslint --fix"],
+   "*.tsx": ["eslint --fix"],
+   "*.vue": ["eslint --fix"]
+ }

7. git commit 规范提交

全局安装

npm install -g commitizen

项目安装

pnpm add -D cz-git

添加 config 指定使用的适配器,添加commit脚本,代替 git add . ; git commit

package.json

{
  ...
  "scripts": {
+    "commit": "git-cz"  
  },
+ "config": {
+   "commitizen": {
+     "path": "node_modules/cz-git"
+   }
  },  
}

根目录添加commitlint.config.cjs

commitlint.config.cjs

// .commitlintrc.js
/** @type {import('cz-git').UserConfig} */
module.exports = {
  rules: {
    // @see: https://commitlint.js.org/#/reference-rules
  },
  prompt: {
    alias: { fd: 'docs: fix typos' },
    messages: {
      type: '选择你要提交的类型 :',
      scope: '选择一个提交范围(可选):',
      customScope: '请输入自定义的提交范围 :',
      subject: '填写简短精炼的变更描述 :\n',
      body: '填写更加详细的变更描述(可选)。使用 "|" 换行 :\n',
      breaking: '列举非兼容性重大的变更(可选)。使用 "|" 换行 :\n',
      footerPrefixesSelect: '选择关联issue前缀(可选):',
      customFooterPrefix: '输入自定义issue前缀 :',
      footer: '列举关联issue (可选) 例如: #31, #I3244 :\n',
      confirmCommit: '是否提交或修改commit ?'
    },
    types: [
      { value: 'feat', name: 'feat:     新增功能 | A new feature' },
      { value: 'fix', name: 'fix:      修复缺陷 | A bug fix' },
      { value: 'docs', name: 'docs:     文档更新 | Documentation only changes' },
      { value: 'style', name: 'style:    代码格式 | Changes that do not affect the meaning of the code' },
      { value: 'refactor', name: 'refactor: 代码重构 | A code change that neither fixes a bug nor adds a feature' },
      { value: 'perf', name: 'perf:     性能提升 | A code change that improves performance' },
      { value: 'test', name: 'test:     测试相关 | Adding missing tests or correcting existing tests' },
      { value: 'build', name: 'build:    构建相关 | Changes that affect the build system or external dependencies' },
      { value: 'ci', name: 'ci:       持续集成 | Changes to our CI configuration files and scripts' },
      { value: 'revert', name: 'revert:   回退代码 | Revert to a commit' },
      { value: 'chore', name: 'chore:    其他修改 | Other changes that do not modify src or test files' },
    ],
    useEmoji: false,
    emojiAlign: 'center',
    themeColorCode: '',
    scopes: [],
    allowCustomScopes: true,
    allowEmptyScopes: true,
    customScopesAlign: 'bottom',
    customScopesAlias: 'custom',
    emptyScopesAlias: 'empty',
    upperCaseSubject: false,
    markBreakingChangeMode: false,
    allowBreakingChanges: ['feat', 'fix'],
    breaklineNumber: 100,
    breaklineChar: '|',
    skipQuestions: [],
    issuePrefixes: [
      // 如果使用 gitee 作为开发管理
      { value: 'link', name: 'link:     链接 ISSUES 进行中' },
      { value: 'closed', name: 'closed:   标记 ISSUES 已完成' }
    ],
    customIssuePrefixAlign: 'top',
    emptyIssuePrefixAlias: 'skip',
    customIssuePrefixAlias: 'custom',
    allowCustomIssuePrefix: true,
    allowEmptyIssuePrefix: true,
    confirmColorize: true,
    maxHeaderLength: Infinity,
    maxSubjectLength: Infinity,
    minSubjectLength: 0,
    scopeOverrides: undefined,
    defaultBody: '',
    defaultIssues: '',
    defaultScope: '',
    defaultSubject: ''
  }
}

8. 多环境配置

新增文件,加入多个环境配置(根据需求制定)

├── env
|  ├── .env.development // 开发环境
|  ├── .env.testing // 测试环境
|  ├── .env.staging // 预发布环境
|  ├── .env.production // 生产环境

.env.development

VITE_PROJECT_ENV=development
VITE_APP_TITLE=My App (development)

.env.testing

VITE_PROJECT_ENV=development
VITE_APP_TITLE=My App (testing)

.env.staging

VITE_PROJECT_ENV=production
VITE_APP_TITLE=My App (staging)

.env.production

VITE_PROJECT_ENV=production
VITE_APP_TITLE=My App (production)

vite.config.js

export default defineConfig({
  ...
+  envDir: './env' // 用于加载 .env 文件的目录
+  // envPrefix: '' // 以 envPrefix 开头的环境变量会通过 import.meta.env 暴露在你的客户端源码中
});

package.json修改,配置多个环境执行脚本

{
  ...
  "script": {
+   "dev": "vite --mode development",
+   "start:dev": "vite --mode development",
+   "start:test": "vite --mode testing",
+   "start:staging": "vite --mode staging",
+   "start:prod": "vite --mode production",
-   "build": "run-p type-check build-only",
+   "build": "pnpm type-check && vite build --mode production",
+   "build:dev": "pnpm type-check && vite build --mode development",
+   "build:test": "pnpm type-check && vite build --mode testing",
+   "build:staging": "pnpm type-check && vite build --mode staging",
+   "build:prod": "pnpm type-check && vite build --mode production",
  }
}

9. sass配置

pnpm add sass -D // 安装sass即可,无需下载loader等

拓展

移动端场景:

px 转换 vw

存在px 转换 vw单位的情况。

pnpm add -D postcss-px-to-viewport

vite.config.ts

+ import px2vw from 'postcss-px-to-viewport';export default defineConfig({
+   css: {
+   postcss: {
+     plugins: [
+       px2vw({
+         unitToConvert: 'px', // 要转化的单位
+         viewportWidth: 750, // UI设计稿的宽度
+         unitPrecision: 6, // 转换后的精度,即小数点位数
+         propList: ['*'], // 指定转换的css属性的单位,*代表全部css属性的单位都进行转换
+         viewportUnit: 'vw', // 指定需要转换成的视窗单位,默认vw
+         fontViewportUnit: 'vw', // 指定字体需要转换成的视窗单位,默认vw
+         selectorBlackList: ['ignore-'], // 指定不转换为视窗单位的类名,
+         minPixelValue: 1, // 默认值1,小于或等于1px则不进行转换
+         mediaQuery: true, // 是否在媒体查询的css代码中也进行转换,默认false
+         replace: true, // 是否转换后直接更换属性值
+         // exclude: [/node_modules/], // 设置忽略文件,用正则做目录名匹配
+         exclude: [],
+         landscape: false, // 是否处理横屏情况
        }),
      ],
    },
  },
})

由于 postcss-px-to-viewport 缺少声明文件。这里需要处理一下

根目录增加 env.node.d.ts

+ declare module 'postcss-px-to-viewport';

修改tsconfig.config.json。types增加 ./env.node 的引用

{
  "extends": "@vue/tsconfig/tsconfig.node.json",
  "include": ["vite.config.*", "vitest.config.*", "cypress.config.*", "playwright.config.*"],
  "compilerOptions": {
    "composite": true,
-   "types": ["node"]
+   "types": ["node", "./env.node"]
  }
}

html meta 设置

<meta
  name="viewport"
  content="width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no, minimal-ui, viewport-fit=cover"
/>
<!-- 删除默认的苹果工具栏和菜单栏。 -->
<meta content="no" name="apple-mobile-web-app-capable">
<!-- 关闭电话号码,邮件识别 -->
<meta name="format-detection" content="telephone=no, email=no" />
<!-- windows phone 点击无高光 -->
<meta name="msapplication-tap-highlight" content="no">
<!-- 设置苹果工具栏颜色 -->
<meta name="apple-mobile-web-app-status-bar-style" content="black" />    

问题

  • 使用vite-plugin-checker 配置eslint vite对vue文件检查不生效,需要vite-plugin-eslint 来配置eslint

  • 因为' run-p type-check build-only '会和' config ' 的配置冲突报错,见链接。把并行执行任务去除,改成顺序执行。

  • postcss-px-to-viewport 插件引用问题

项目地址:

github.com/jayyoonn/te…