Vite 配置中 JavaScript 和 TypeScript 的区别

一、配置文件对比

Vite 配置文件
JavaScript 配置
TypeScript 配置
vite.config.js
vite.config.mjs
vite.config.ts
vite.config.mts
CommonJS 模块
ES 模块
需要 TypeScript
ES 模块 + TypeScript

二、配置文件写法对比

2.1 JavaScript 配置 (vite.config.js)

// vite.config.js - CommonJS 格式
const { defineConfig } = require('vite')
const vue = require('@vitejs/plugin-vue')
const path = require('path')

module.exports = defineConfig({
  plugins: [vue()],
  resolve: {
    alias: {
      '@': path.resolve(__dirname, './src')
    }
  }
})
// vite.config.mjs - ES Module 格式(推荐)
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import { fileURLToPath, URL } from 'node:url'

export default defineConfig({
  plugins: [vue()],
  resolve: {
    alias: {
      '@': fileURLToPath(new URL('./src', import.meta.url))
    }
  }
})

2.2 TypeScript 配置 (vite.config.ts)

// vite.config.ts
import { defineConfig, UserConfig, ConfigEnv } from 'vite'
import vue from '@vitejs/plugin-vue'
import { fileURLToPath, URL } from 'node:url'

// 使用类型注解
export default defineConfig((config: ConfigEnv): UserConfig => {
  const { command, mode } = config
  
  return {
    plugins: [vue()],
    resolve: {
      alias: {
        '@': fileURLToPath(new URL('./src', import.meta.url))
      }
    },
    server: {
      port: 3000,
      host: true
    }
  }
})

三、主要区别详解

3.1 类型安全对比

TypeScript
JavaScript
问题发现晚
问题发现早
编译时错误
静态类型检查
更少错误
智能提示
运行时错误
无类型检查
容易出错
依赖文档
调试困难
开发效率高
JavaScript 示例(无类型检查):
// vite.config.js - 可能的错误不会被提前发现
export default defineConfig({
  plugins: [vue()],
  server: {
    port: '3000',  // ❌ 错误:应该是数字,但 JS 不会报错
    open: 'yes'    // ❌ 错误:应该是布尔值
  },
  build: {
    rollupOptions: {
      output: {
        manualChunks: 'vendor'  // ❌ 错误:应该是函数或对象
      }
    }
  }
})
TypeScript 示例(有类型检查):
// vite.config.ts - 错误会在编译时被发现
import { defineConfig, UserConfig } from 'vite'

export default defineConfig((): UserConfig => {
  return {
    plugins: [vue()],
    server: {
      port: '3000',  // ❌ TypeScript 错误:类型"string"不能分配给类型"number"
      open: 'yes'    // ❌ TypeScript 错误:类型"string"不能分配给类型"boolean"
    },
    build: {
      rollupOptions: {
        output: {
          manualChunks: 'vendor'  // ❌ TypeScript 错误:类型不匹配
        }
      }
    }
  }
})

3.2 智能提示对比

// TypeScript 配置 - 完整的智能提示
import { defineConfig, PluginOption } from 'vite'

export default defineConfig({
  plugins: [
    // 鼠标悬停可以看到完整的类型定义
    {
      name: 'my-plugin',
      // 自动提示所有可用的钩子函数
      configResolved(config) {
        // config 参数有完整的类型定义
        console.log(config.base)
      },
      transform(code, id) {
        // 参数类型自动推断
        if (id.endsWith('.vue')) {
          return code
        }
      }
    } as PluginOption
  ]
})

四、TypeScript 特有配置

4.1 使用 TypeScript 需要的额外配置

TypeScript 项目配置
安装依赖
tsconfig.json
类型声明
typescript
vue-tsc
@types/node
编译选项
路径映射
类型检查
env.d.ts
vite-env.d.ts
自定义类型
1. 安装必要依赖:
# TypeScript 项目需要额外安装
npm install -D typescript vue-tsc @types/node
2. tsconfig.json 配置:
{
  "compilerOptions": {
    "target": "ES2020",
    "useDefineForClassFields": true,
    "module": "ESNext",
    "lib": ["ES2020", "DOM", "DOM.Iterable"],
    "skipLibCheck": true,
    "moduleResolution": "node",
    "allowImportingTsExtensions": true,
    "resolveJsonModule": true,
    "isolatedModules": true,
    "noEmit": true,
    "jsx": "preserve",
    "strict": true,
    "noUnusedLocals": true,
    "noUnusedParameters": true,
    "noFallthroughCasesInSwitch": true,
    "baseUrl": ".",
    "paths": {
      "@/*": ["./src/*"]
    }
  },
  "include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.vue"],
  "references": [{ "path": "./tsconfig.node.json" }]
}
3. 环境变量类型声明:
// env.d.ts
/// <reference types="vite/client" />

interface ImportMetaEnv {
  readonly VITE_APP_TITLE: string
  readonly VITE_API_BASE_URL: string
  readonly VITE_APP_ENV: 'development'

4.2 高级 TypeScript 配置示例

// vite.config.ts - 使用高级类型
import { defineConfig, Plugin, UserConfig, ConfigEnv } from 'vite'
import vue from '@vitejs/plugin-vue'

// 自定义插件类型
interface MyPluginOptions {
  include?: string[]
  exclude?: string[]
}

// 创建自定义插件
function myPlugin(options: MyPluginOptions = {}): Plugin {
  return {
    name: 'my-custom-plugin',
    transform(code: string, id: string) {
      if (options.include?.some(pattern => id.includes(pattern))) {
        return {
          code: code.replace(/console\.log/g, ''),
          map: null
        }
      }
    }
  }
}

// 条件配置类型
type ViteConfig = UserConfig & {
  customOption?: {
    apiUrl: string
    timeout: number
  }
}

export default defineConfig(({ command, mode }: ConfigEnv): ViteConfig => {
  const isDev = mode === 'development'
  const isBuild = command === 'build'
  
  return {
    plugins: [
      vue(),
      myPlugin({
        include: ['src/components'],
        exclude: ['node_modules']
      })
    ],
    
    // 自定义配置(需要扩展类型)
    customOption: {
      apiUrl: isDev ? 'http://localhost:3000' : 'https://api.example.com',
      timeout: 5000
    },
    
    // 条件配置
    build: isBuild ? {
      minify: 'terser',
      terserOptions: {
        compress: {
          drop_console: true,
          drop_debugger: true
        }
      }
    } : undefined
  }
})

五、实际项目配置对比

5.1 JavaScript 项目完整配置

// vite.config.mjs
import { defineConfig, loadEnv } from 'vite'
import vue from '@vitejs/plugin-vue'
import path from 'path'

export default defineConfig(({ command, mode }) => {
  const env = loadEnv(mode, process.cwd())
  
  return {
    plugins: [vue()],
    
    resolve: {
      alias: {
        '@': path.resolve(__dirname, './src'),
        'components': path.resolve(__dirname, './src/components'),
        'views': path.resolve(__dirname, './src/views')
      }
    },
    
    server: {
      port: parseInt(env.VITE_PORT) || 3000,
      proxy: {
        '/api': {
          target: env.VITE_API_URL,
          changeOrigin: true,
          rewrite: (path) => path.replace(/^\/api/, '')
        }
      }
    },
    
    build: {
      outDir: 'dist',
      sourcemap: mode === 'development'
    }
  }
})

5.2 TypeScript 项目完整配置

// vite.config.ts
import { defineConfig, loadEnv, UserConfig, ConfigEnv } from 'vite'
import vue from '@vitejs/plugin-vue'
import { resolve } from 'path'

// 定义环境变量接口
interface ViteEnv {
  VITE_PORT: number
  VITE_API_URL: string
  VITE_PUBLIC_PATH: string
  VITE_PROXY: boolean
}

// 解析环境变量
function wrapperEnv(envConf: Record<string, string>): ViteEnv {
  const ret: any = {}
  
  for (const envName of Object.keys(envConf)) {
    let realName = envConf[envName].replace(/\\n/g, '\n')
    realName = realName === 'true' ? true : realName === 'false' ? false : realName
    
    if (envName === 'VITE_PORT') {
      realName = Number(realName)
    }
    
    ret[envName] = realName
  }
  
  return ret as ViteEnv
}

export default defineConfig(({ command, mode }: ConfigEnv): UserConfig => {
  const root = process.cwd()
  const env = loadEnv(mode, root)
  const viteEnv = wrapperEnv(env)
  
  const { VITE_PORT, VITE_PUBLIC_PATH, VITE_PROXY, VITE_API_URL } = viteEnv
  
  const isBuild = command === 'build'
  
  return {
    base: VITE_PUBLIC_PATH,
    root,
    
    plugins: [vue()],
    
    resolve: {
      alias: {
        '@': resolve(root, './src'),
        '#': resolve(root, './types'),
        'components': resolve(root, './src/components'),
        'views': resolve(root, './src/views')
      }
    },
    
    server: {
      host: true,
      port: VITE_PORT,
      proxy: VITE_PROXY ? {
        '/api': {
          target: VITE_API_URL,
          changeOrigin: true,
          rewrite: (path: string) => path.replace(/^\/api/, '')
        }
      } : undefined
    },
    
    build: {
      target: 'es2015',
      outDir: 'dist',
      sourcemap: !isBuild,
      reportCompressedSize: false,
      chunkSizeWarningLimit: 2000,
      rollupOptions: {
        output: {
          manualChunks: {
            vue: ['vue', 'vue-router', 'pinia'],
            elementPlus: ['element-plus'],
            utils: ['axios', 'dayjs']
          }
        }
      }
    },
    
    optimizeDeps: {
      include: ['vue', 'vue-router', 'pinia', 'axios'],
      exclude: ['vue-demi']
    }
  }
})

六、选择建议

项目类型
选择配置语言
小型项目
大型项目
团队项目
JavaScript
快速开发
TypeScript
类型安全
TypeScript
规范统一
优点:简单直接
缺点:缺少类型检查
优点:错误提前发现
缺点:需要学习成本
优点:团队协作友好
缺点:配置较复杂

总结建议:

  1. 小型/个人项目:使用 JavaScript 配置即可,快速简单
  2. 中大型项目:推荐使用 TypeScript,提供更好的类型安全和开发体验
  3. 团队协作项目:强烈推荐 TypeScript,统一的类型定义有助于团队协作
  4. 学习项目:建议从 JavaScript 开始,逐步过渡到 TypeScript
Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐