使用Vite官方模板创建新项目(清除掉所有示例代码,保留干净的项目结构)

不使用 WSL,在本地新建一个新项目


Vue3 + Pinia + TypeScript + ElementPlus


使用 pnpm


使用Vite官方模板创建的项目,但是要清除掉所有示例代码,保留干净的项目结构。


步骤1:使用Vite创建Vue3项目

bash

# 创建项目(使用官方模板)
pnpm create vite my-games -- --template vue-ts

# 进入项目目录
cd my-games

步骤2:安装额外依赖

bash

# 安装Pinia和Element Plus
pnpm add pinia element-plus @element-plus/icons-vue

安装路由

pnpm add vue-router@4

安装 sass-embedded

pnpm install sass-embedded

sass-embedded 是官方推出的 Dart Sass 高性能版本。它并不是一个全新的框架,而是一个通过进程间通信调用原生 Dart 可执行文件来编译 Sass/SCSS 的封装器(Wrapper)

简单来说,你可以把它理解为 sass 包的“涡轮增压版”,适合在大型项目或需要高频编译的场景下提升性能。


核心特点与优势

特性sass (纯JS版)sass-embedded (嵌入式版)
运行方式纯 JavaScript 实现调用独立的 Dart 原生可执行文件
编译速度中等更快,尤其适合大型 Sass 文件
API 兼容性支持新版 JS API完全兼容 sass 包的 API,可无缝替换
跨平台支持全平台仅限 Dart 支持的平台:Windows、macOS、Linux
异步性能同步模式更快异步模式更快(因为编译在独立进程中)

它如何工作?

sass-embedded 的工作原理分为三个部分:

  1. 编译器:一个独立的 Dart 可执行文件,负责实际的 Sass 解析和编译工作。因为它本身是原生代码,所以速度很快。

  2. 主机 (Host):你项目中安装的 sass-embedded npm 包。它作为桥梁,提供你熟悉的 JavaScript API,并负责启动和管理编译器进程。

  3. 通信协议:主机和编译器之间通过标准输入/输出流,使用预定义的协议进行通信,完成编译任务。

使用场景与注意事项

  • 适用场景

    • 大型项目或代码库,对 CSS 编译速度有较高要求。

    • 需要利用异步模式来获得最佳性能的场景。

    • 希望从 node-sass 迁移,但又担心性能问题的用户。

  • 注意事项

    • 平台限制:如果你的开发或部署环境是非常规的操作系统或架构,需要确认 Dart 是否支持。

    • 兼容性:它支持新版 JS API 和旧版(Legacy)API。但对于旧版 API,有一些不常用的配置选项(如 precisionindentWidth)不被支持。不过对于绝大多数现代项目来说,这不会有任何影响。


步骤3:清理示例代码

清空 src/App.vue

清空 src/components/ 目录

bash

# 删除示例组件
rm src/components/HelloWorld.vue

# 或者Windows PowerShell
Remove-Item src/components/HelloWorld.vue

重置 src/style.css

简化 src/main.ts

typescript

import { createApp } from 'vue'
import { createPinia } from 'pinia'
import router from './router'
import ElementPlus from 'element-plus'
import 'element-plus/dist/index.css'
import './style.css'
import App from './App.vue'

const app = createApp(App)

app.use(router)

// 使用Pinia
app.use(createPinia())

// 使用Element Plus
app.use(ElementPlus)

app.mount('#app')

步骤4:创建基础目录结构

bash

# 创建必要的目录
mkdir src/views
mkdir src/router
mkdir src/stores
mkdir src/utils
mkdir src/types
mkdir src/api
mkdir src/layouts

创建 src/router/index.ts

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

const router = createRouter({
  history: createWebHistory(),
  routes: [
    {
      path: '/',
      name: 'Home',
      component: () => import('../views/Home.vue')
    },
  ]
})

export default router

步骤5:创建类型定义文件

创建 src/types/global.d.ts

typescript

// 全局类型定义
export {};

declare global {
  // 在这里定义全局类型
}

步骤6:创建示例Store(可选,但建议保留模板)

创建 src/stores/index.ts

typescript

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

export const useMainStore = defineStore('main', () => {
  // 你的状态
  const count = ref(0)
  
  // 你的方法
  function increment() {
    count.value++
  }
  
  return {
    count,
    increment
  }
})

步骤7:更新配置文件(可选优化)

更新 vite.config.ts

typescript

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

export default defineConfig({
  plugins: [vue()],
  resolve: {
    alias: {
      '@': path.resolve(__dirname, './src'),
      '@components': path.resolve(__dirname, './src/components'),
      '@assets': path.resolve(__dirname, './src/assets'),
      '@utils': path.resolve(__dirname, './src/utils')
    }
  },
  server: {
    port: 3000,
    open: true
  }
})

更新 tsconfig.json 添加路径映射

原有的

{
  "files": [],
  "references": [
    { "path": "./tsconfig.app.json" },
    { "path": "./tsconfig.node.json" }
  ]
}

更新后

{
  "compilerOptions": {
    "target": "ES2020",
    "useDefineForClassFields": true,
    "module": "ESNext",
    "lib": ["ES2020", "DOM", "DOM.Iterable"],
    "skipLibCheck": true,
    "moduleResolution": "bundler",
    "allowImportingTsExtensions": true,
    "resolveJsonModule": true,
    "isolatedModules": true,
    "noEmit": true,
    "jsx": "preserve",
    "strict": true,
    "noUnusedLocals": true,
    "noUnusedParameters": true,
    "noFallthroughCasesInSwitch": true,
    "paths": {
      "@/*": ["./src/*"]
    }
  },
  "include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.vue"],
  "references": [{ "path": "./tsconfig.app.json" }, { "path": "./tsconfig.node.json" }]
}

补充建议

  1. 如果使用的是 Vite + Vue 3,可以完全放弃 TypeScript 的项目引用功能,只保留一个 tsconfig.json 文件(去掉 references 字段),这样配置更简单且无需处理 composite 问题。

  2. 若要保留项目引用,请确保 tsconfig.node.json 中的 module 设置为 CommonJS(或 ESNext 配合 moduleResolution: node),因为 Node 环境与浏览器环境不同。


去掉 references 字段

{
  "compilerOptions": {
    "target": "ES2020",
    "useDefineForClassFields": true,
    "module": "ESNext",
    "lib": ["ES2020", "DOM", "DOM.Iterable"],
    "skipLibCheck": true,
    "moduleResolution": "bundler",
    "allowImportingTsExtensions": true,
    "resolveJsonModule": true,
    "isolatedModules": true,
    "noEmit": true,
    "jsx": "preserve",
    "strict": true,
    "noUnusedLocals": true,
    "noUnusedParameters": true,
    "noFallthroughCasesInSwitch": true,
    "paths": {
      "@/*": ["./src/*"]
    }
  },
  "include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.vue"]
}

如果没去掉 references 字段,会提示


引用的项目“d:/MyProjects/my-fridge/tsconfig.app.json”必须拥有设置 "composite": true。ts

Path to referenced tsconfig or to folder containing tsconfig.


解决方法:在  tsconfig.app.json 和  tsconfig.node.json 文件中,分别添加  "composite": true

tsconfig.app.json

tsconfig.node.json


引用的项目“d:/MyProjects/my-fridge/tsconfig.node.json”可能不会禁用发出。


原因
被引用的项目(tsconfig.app.json / tsconfig.node.json)如果设置了 "noEmit": true,会导致它们无法生成供主项目引用的“输出文件”。项目引用模式通常要求这些子项目能够生成 .d.ts 等声明文件。


解决方法
检查 tsconfig.app.json 和 tsconfig.node.json 中是否包含 "noEmit": true。如果有,请将其移除或改为 false。同时,建议显式开启 "declaration": true 来生成类型声明文件。


只有在设置“noEmit”或“emitDeclarationOnly”时,才能使用选项“allowImportingTsExtensions”。


这个错误的原因非常明确:allowImportingTsExtensions 选项必须与 noEmit 或 emitDeclarationOnly 同时使用


您贴出的错误提示实际上指出了问题所在 —— 我上一条回复中建议移除 noEmit 的做法可能不适合所有子项目。


错误原因:allowImportingTsExtensions 允许在导入时写 .ts 扩展名,但这会生成无法直接运行的代码(因为最终输出应该是 .js 文件)。所以 TypeScript 强制要求:要么完全不生成输出文件noEmit: true),要么只生成声明文件emitDeclarationOnly: true)。


针对 tsconfig.node.json(通常用于 Node.js 环境,比如 vite.config.ts),有两种推荐的配置方式:


方案一:保持 noEmit: true(推荐用于仅类型检查的场景)

如果 tsconfig.node.json 只用于类型检查,而实际构建由 Vite 等工具完成

{
  "compilerOptions": {
    "composite": true,
    "noEmit": true,                      // ✅ 保留 noEmit
    "allowImportingTsExtensions": true,  // ✅ 允许使用
    // 其他选项...
  }
}

方案二:改为 emitDeclarationOnly: true(需要生成类型声明)

如果项目引用要求生成 .d.ts 文件供其他项目使用

{
  "compilerOptions": {
    "composite": true,
    "emitDeclarationOnly": true,         // ✅ 只生成 .d.ts
    "declaration": true,                 // 需要配合此选项
    "allowImportingTsExtensions": true,  // ✅ 允许使用
    // 其他选项...
  }
}

考虑到 Vue 3 + Vite 项目的典型结构,我建议:

tsconfig.node.json 完整示例

{
  "compilerOptions": {
    "composite": true,
    "target": "ES2020",
    "module": "ESNext",
    "moduleResolution": "bundler",
    "allowSyntheticDefaultImports": true,
    "noEmit": true,                      // ← 关键:不输出文件
    "allowImportingTsExtensions": true,  // ← 现在合法了
    "strict": true,
    "skipLibCheck": true,
    "types": ["node"]
  },
  "include": ["vite.config.ts", "vitest.config.ts", "cypress.config.ts"]
}

tsconfig.app.json 配合示例

{
  "compilerOptions": {
    "composite": true,
    "target": "ES2020",
    "module": "ESNext",
    "moduleResolution": "bundler",
    "jsx": "preserve",
    "noEmit": true,                      // ← 同样保持 noEmit
    "allowImportingTsExtensions": true,  // ← 合法
    "strict": true,
    "skipLibCheck": true,
    "paths": {
      "@/*": ["./src/*"]
    }
  },
  "include": ["src/**/*.ts", "src/**/*.tsx", "src/**/*.vue"]
}

关于 composite 的特别说明

当使用 noEmit: true 配合 composite: true 时,TypeScript 会:

  • 允许项目引用功能正常工作

  • 进行增量类型检查

  • 不生成任何输出文件(包括 .js 和 .d.ts

这对于仅将子项目用于类型检查的场景完全没问题。如果您需要生成声明文件给其他项目引用,才需要使用 emitDeclarationOnly: true


选项“baseUrl”已弃用,并将停止在 TypeScript 7.0 中运行。指定 compilerOption“ignoreDeprecations”:“6.0”以使此错误静音。

请访问 https://aka.ms/ts6 以获取迁移信息。


根  tsconfig.json 中的  baseUrl 废弃警告,建议直接删除  "baseUrl": ".",保留  paths 即可
{
  "compilerOptions": {
    // 删除 "baseUrl": ".",
    "paths": {
      "@/*": ["./src/*"]   // 改为完整相对路径
    }
  }
}

 关联阅读推荐

TypeScript baseUrl 弃用解决(附:怎么在 Vite 中配置 resolve.alias)


步骤8:最终项目结构

text

my-vue3-clean/
├── src/
│   ├── api/              # API接口
│   ├── assets/           # 静态资源
│   │   └── vue.svg       # 默认logo(可以删除)
│   ├── components/       # 公共组件(空目录)
│   ├── layouts/          # 布局组件
│   ├── router/           # 路由配置
│   ├── stores/           # Pinia状态管理
│   │   └── index.ts      # 示例store
│   ├── types/            # TypeScript类型定义
│   │   └── global.d.ts
│   ├── utils/            # 工具函数
│   ├── views/            # 页面组件
│   ├── App.vue           # 根组件(已清空)
│   ├── main.ts           # 入口文件(已简化)
│   ├── style.css         # 全局样式(已重置)
│   └── vite-env.d.ts     # Vite类型声明
├── index.html
├── package.json
├── tsconfig.json
├── tsconfig.node.json
├── vite.config.ts
└── .gitignore

步骤9:运行项目

# 安装依赖
pnpm install

# 启动开发服务器
pnpm run dev

示例代码未清除前


现在您拥有一个干净的Vue 3项目,没有任何示例代码,只有基础的技术栈配置(Vue 3 + Pinia + TypeScript + Element Plus)。


对这个 Vue 3 项目中 tsconfig.json 配置项的逐句解释


该配置主要用于支持 Vue 3 + TypeScript + Vite 的项目结构(比如 Vue CLI 或 Vite 创建的项目)。


一、compilerOptions(编译选项)

"target": "ES2020"

  • 作用:指定 TypeScript 编译后的 JavaScript 版本目标。

  • 含义:代码会被转译到 ES2020 标准。ES2020 支持 import.metaBigInt、可选链 ?.、空值合并 ?? 等现代特性,Vite 开发环境下可直接运行,不需要降级到 ES5/ES2015。


"useDefineForClassFields": true

  • 作用:是否使用 ECMAScript 标准定义的类字段初始化方式。

  • 含义:设为 true 后,类字段按标准行为([[Define]])处理,而不是旧版 TypeScript 的 [[Set]] 语义。Vue 3 响应式系统依赖此行为来正确处理 class 组件或类属性。


"module": "ESNext"

  • 作用:指定生成的模块系统格式。

  • 含义:使用最新的 ES 模块规范(import/export),Vite 基于原生 ES 模块开发,因此需要保持为 ESNext


"lib": ["ES2020", "DOM", "DOM.Iterable"]

  • 作用:指定 TypeScript 编译时包含的类型定义库。

  • 含义

    • ES2020:提供 ES2020 标准库的类型(如 PromiseMapSet)。

    • DOM:浏览器 DOM API 类型(documentwindow 等)。

    • DOM.Iterable:支持遍历 DOM 集合类型(如 NodeList 的 for...of)。


"skipLibCheck": true

  • 作用:跳过声明文件(.d.ts)的类型检查。

  • 含义:只检查项目源码,忽略依赖库中的类型错误。可大幅提升编译速度,尤其当某些依赖的类型定义存在小问题时不影响构建。


"moduleResolution": "bundler"

  • 作用:指定模块解析策略。

  • 含义"bundler" 是专为 Vite、Webpack 等打包器设计的解析模式,能正确处理无扩展名导入、条件导出(exports 字段)等,适配 Vue 3 单文件组件的导入。


"allowImportingTsExtensions": true

  • 作用:允许在导入路径中使用 .ts.tsx 扩展名。

  • 含义:开启后可以写 import App from './App.tsx',但必须配合 "noEmit": true 或 "emitDeclarationOnly": true 使用。


"resolveJsonModule": true

  • 作用:允许导入 .json 文件作为模块。

  • 含义import data from './config.json' 可以直接工作,并会获得 JSON 的类型推断。


"isolatedModules": true

  • 作用:强制将每个文件视为独立模块。

  • 含义:这是 Vite 等基于 ES 模块的构建工具的要求。防止使用无法被单文件转译器(如 esbuild)正确处理的 TypeScript 语法(如常量枚举、命名空间等)。


"noEmit": true

  • 作用:不生成编译输出文件(.js.d.ts 等)。

  • 含义:因为 Vite 或 Vue CLI 内部会使用 esbuild 或 rollup 处理代码转换,TypeScript 只用来进行类型检查,不负责生成输出文件。


"jsx": "preserve"

  • 作用:控制 JSX 语法的处理方式。

  • 含义"preserve" 表示保留 JSX 语法,不进行转换,交给后续的构建工具(如 Vite + Vue 插件)处理。Vue 3 支持 JSX/TSX,但通过 @vitejs/plugin-vue-jsx 插件转换。


"strict": true

  • 作用:启用所有严格类型检查选项。

  • 含义:包括 noImplicitAnystrictNullChecksstrictFunctionTypes 等,大幅提升类型安全性,Vue 3 + TS 项目强烈建议开启。


"noUnusedLocals": true

  • 作用:报告未使用的局部变量。

  • 含义:如果一个变量声明了但没有被读取,TypeScript 会报错,帮助保持代码整洁。


"noUnusedParameters": true

  • 作用:报告未使用的函数参数。

  • 含义:如果一个函数参数声明了但未被使用,会报错(但参数以下划线 _arg 开头可忽略)。


"noFallthroughCasesInSwitch": true

  • 作用:防止 switch 语句中的“穿透”行为(case 之间没有 break/return)。

  • 含义:如果没有 break 或 return 显式结束,会报错,避免逻辑错误。


"baseUrl": "."

  • 作用:设置非相对模块导入的基目录。

  • 含义:设置为项目根目录,用于配合 paths 解析路径别名。


"paths": { "@/*": ["src/*"] }

  • 作用:路径别名映射。

  • 含义@/components/Button 会被映射到 <项目根>/src/components/Button,使导入路径更简洁。需要构建工具(如 Vite)配合配置相同的别名。


二、顶层配置项

"include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.vue"]

  • 作用:指定需要 TypeScript 处理的文件范围。

  • 含义

    • src/**/*.ts:所有 .ts 文件

    • src/**/*.d.ts:类型声明文件

    • src/**/*.tsx:TSX 组件文件

    • src/**/*.vue:Vue 单文件组件(通过 vue 的类型支持)


"references": [{ "path": "./tsconfig.app.json" }, { "path": "./tsconfig.node.json" }]

  • 作用:TypeScript 项目引用(Project References)。

  • 含义:这个 tsconfig.json 是一个“根配置”,引用了两个子项目:

    • tsconfig.app.json:通常用于编译前端应用源码(src/ 目录)

    • tsconfig.node.json:通常用于编译 Node.js 环境的配置脚本(如 vite.config.ts

这样可以:

  • 分别配置不同环境的编译选项(如 targetmodule 等不同)

  • 提升类型检查和编译效率


总结

这个配置是一个典型的 Vue 3 + Vite + TypeScript 项目的 根 tsconfig.json,主要负责:

  • 配置现代语法支持(ES2020、ESNext)

  • 与 Vite 的构建流程兼容(isolatedModulesnoEmitmoduleResolution: bundler

  • 严格类型检查(strictnoUnusedLocals 等)

  • 路径别名 @/* 指向 src/*

  • 使用项目引用拆分应用代码与 Node 工具代码

通常配合 tsconfig.app.json(前端源码)和 tsconfig.node.json(Node 脚本)共同工作。


找不到“element-plus/dist/index.css”的副作用导入的模块或类型声明。


这个错误表示 TypeScript 无法识别 CSS 文件的导入类型。这是因为 TypeScript 默认只能处理 .ts/.js 等代码文件,不支持直接导入 CSS。


解决方案:添加类型声明(推荐)

创建或修改 src/vite-env.d.ts 文件:

typescript

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

declare module '*.vue' {
  import type { DefineComponent } from 'vue'
  const component: DefineComponent<{}, {}, any>
  export default component
}

// 支持 CSS 导入
declare module '*.css' {
  const css: string
  export default css
}

declare module '*.scss' {
  const content: string
  export default content
}

// 针对 Element Plus
declare module 'element-plus/dist/index.css' {
  const css: string
  export default css
}

检查 tsconfig.json 配置

确保 tsconfig.json 包含了正确的类型配置:

json

{
  "compilerOptions": {
    "types": ["vite/client"],  // 确保有这一行
    "skipLibCheck": true,       // 可选,跳过库类型检查
    // ...其他配置
  },
  "include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.vue"]
}

为什么会出现这个问题?

  1. TypeScript 默认只理解 .ts.tsx.d.ts 文件

  2. 导入 .css 文件时,TypeScript 不知道它的类型

  3. Vite 运行时能正确处理 CSS,但编译时的类型检查会报错


验证修复

创建声明文件后:

  1. 重启 TypeScript 服务器(VS Code 中按 Ctrl+Shift+P → "TypeScript: Restart TS server")

  2. 检查编辑器中的红色波浪线是否消失

这个修复不会影响运行时的功能,只是让 TypeScript 理解 CSS 导入的语法。推荐使用创建 vite-env.d.ts 文件的方式,这是 Vite 项目的标准做法。


启动项目,为什么有的是pnpm dev,有的是pnpm run dev


简单直接的回答:

  • pnpm dev 是 简写形式,只有当 package.json 中有一个名为 dev 的脚本时才能用。

  • pnpm run dev 是 完整形式,明确告诉 pnpm 去执行 scripts 块里的 dev 命令。


1. 为什么两种写法都能用?


pnpm(以及 npm、yarn)的设计是:

  • 对于 predefined(预定义)或常见的生命周期脚本,如 startstoptest,可以省略 runpnpm start

  • 对于 自定义脚本(比如大家常用的 devbuildlint),理论上需要 pnpm run dev

但是,现在绝大多数现代前端工具链(Vite、Create Vue App、Nuxt 等)生成的 package.json 里,默认脚本就叫 dev,而 pnpm 为了便捷性,允许省略 run 来执行任意 scripts 中的命令所以两者完全等价。


2. 在哪里设置/定义的?


唯一设置的地方就是 package.json 文件中的 "scripts" 字段。

json

{
  "name": "my-vue-project",
  "scripts": {
    "dev": "vite",          // ← 这里定义了 dev 命令
    "build": "vue-tsc && vite build",
    "preview": "vite preview"
  }
}
  • 当你运行 pnpm dev 或 pnpm run dev → 实际执行 vite

  • 当你运行 pnpm build → 实际执行 vue-tsc && vite build


3. 为什么不同项目写法不一样?


这不是“设置”不同,而是文档/教程/团队习惯不同。有些人习惯写全 run(更明确),有些人省略(更简洁)。两种在任何 Vue 3 项目里都能用。


4. 什么时候必须用 pnpm run


当你执行的脚本名 不是顶级命令,或者需要传递参数时,有时需要显式写 run,但现代 pnpm 版本中,以下情况也基本都能省略:

bash

# 如果需要给脚本传参数,建议写全(但省略也行)
pnpm run dev -- --port 3000
# 或简写(可能被解析为传给 pnpm 本身,而非脚本)
pnpm dev -- --port 3000  # 大部分情况也能工作

唯一必须写 run 的场景:当你有一个与 pnpm 内置命令重名的脚本,例如你定义了一个 install 脚本,则必须 pnpm run install,否则 pnpm 会执行包安装命令。


总结

写法适用性是否必须
pnpm dev任何 scripts 中的自定义命令推荐简写
pnpm run dev同上更显式,适合脚本新手

没有任何地方“设置”哪种写法,只是你看到的项目示例或教程作者的个人风格。


你在自己的项目里可以随意混用,效果完全相同。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

星汉灿烂星河

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值