目的:使用vite创建vue3项目记录细节点
上篇vue2/vue3 + webpack多页面遇到的问题和思考我们使用vue-cli搭建项目都是使用webpack打包的,现在对比一下vite感受一下极速开发体验
增:下一篇vite + vue3 多页面实战优化续集:eslint+lint-staged+husky+stylelint
第一部分:项目基础配置ts相关: lib, references,loadEnv
说到vue3,不得不提ts,说到ts,一定要先到 官方文档了解tsconfig.json配置的意思,这里我觉得有意思的就是references/lib。
我们通过处理一些警告来了解配置:
例如你使用了vue自动导入插件:unplugin-auto-import/vite
, 组件自动导入unplugin-vue-components/vite
,可能会遇到以下问题
-
在自定义ts文件中引入资源,ts无法识别别名@
要在tsconfig.json配置paths
记得将以上自动导入插件生成的文件auto-imports.d.ts,components.d.ts放入到 tsconfig.json的include数组中
// vite.config.ts
import { resolve } from 'path'
export default defineConfig({
plugins,
resolve: {
alias: {
'@': resolve(__dirname, 'src')
}
}
})
// tsconfig.json
"compilerOptions": {
"baseUrl": ".",
"paths":{
"@": ["src"],
"@/*": ["src/*"],
},
"include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.vue", "auto-imports.d.ts",
"components.d.ts"],
"references": [{ "path": "./tsconfig.node.json" }],
},
- 上面有个references,相当于拆分了tsconfig配置到tsconfig.node.json,关于这个配置我们看官方文档ts3.0新特性:项目引用
这个单独拆分出来的配置文件include包含vite.config.ts,说明只是负责编译 vite 的配置文件。
我在根目录新建了一个build文件夹,拆分了plugin的引入和多页面配置,这里红色警告提示要在tsconfig.node.json的include中加入文件
// tsconfig.node.json
{
"compilerOptions": {
"composite": true,
"module": "esnext",
"moduleResolution": "node",
"allowSyntheticDefaultImports": true
},
"include": ["vite.config.ts", "build/*.ts"]
}
- src/env.d.ts中我们可以看到有帮助ts识别vue文件的代码,还有三个斜线和reference,这个reference是不是和上面我们tsconfig.json配置文件中的references长的很像
///
declare module '*.vue' {
import type { DefineComponent } from 'vue'
// eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/ban-types
const component: DefineComponent<{}, {}, any>
export default component
}
interface ImportMetaEnv {
readonly VITE_APP_TITLE: string
// 更多环境变量...
}
src/env.d.ts 中的三斜线指令官方文档说明 ///
三斜线引用告诉编译器在编译过程中用types形式引入的额外的文件vite/client.d.ts,这个文件里面就是vite帮我们定义的各种常用类型定义,比如css,图片等。下图可以看到又用path的形式引入了./types/importMeta.d.ts
,还引入了dom相关声明
想一想:这个lib在tsconfig.json/compilerOptions配置项目中也有
继续深入到types/importMeta.d.ts
发现了可以全局使用的一些声明ImportMetaEnv,GlobOptions
// vite/client/types/importMeta.d.ts
interface ImportMetaEnv {
[key: string]: any
BASE_URL: string
MODE: string
DEV: boolean
PROD: boolean
SSR: boolean
}
综上我们可以发现
- vite官方文档环境变量告诉我们在配置多个环境变量的时候可以在src/env.d.ts中再次声明ImportMetaEnv插入自己的全局变量。原来是合并了内部类型,达到新增全局变量的作用。
新增环境变量记得VITE_ 开头
// 项目根目录新增的 .env.development文件
VITE_PROJECT_ENV = 'development'
VITE_APP_URL = "https://app-api-0.com/"
-
中用到的lib,types 和tsconfig.json配置文件中的references/compilerOptions中的"lib": ["esnext", "dom"],types属性一样的,只是不同文件场景不同的使用方式而已。
(1) 在d.ts文件中
声明对某个包的依赖用到了types: ///
用路径声明依赖的用到了path: ///
(2) 在.ts文件里声明一个对@types包的依赖,可以使用–types命令行选项或在tsconfig.json里指定
///
官方文档-编译选项告诉我们:target 选项用来指定最终代码运行环境所支持的 JavaScrpt 语法的版本; lib 选项的值默认继承自 target:es5,默认注入target值版本es5库和dom 库。所以我们才能在默认项目中看到vite帮我们配置了"lib": ["esnext", "dom"]
关于配置文件
references
,我们可以看到在vite项目拆分了出了tsconfig.node.json
配置文件,专门用来负责vite.config.ts
配置相关编译工作,结构清晰。
它更重要的作用references官方文档已经告诉我们了: 一套配置,多个工程,修改时只编译子项目本身,显著地加速类型检查和编译。 更细致的举例文章
所以:拆开后,vite项目中修改vite.config.ts
配置并不会导致整个src项目重新编译ts,仅仅只是触发reload
关于环境变量,这里汇总一波
- 想在
vite.config.ts
中使用环境变量,要用vite提供的loadEnv(mode, process.cwd())
单页面应用在src目录下项目中用环境变量可以使用
import.meta.env
查看.env文件
中的自定义环境变量,或者使用import.meta.glob
(类似webpack的require.context
)读取文件,但是在vite.config.ts
配置文件中import.meta是空的
loadEnv的第一参数mode哪里有?两种方式
(1)官网环境变量告诉我们可以直接在vite.config.ts
中将defineConfig
参数写成函数,函数就有mode参数可用
下面代码中有define,我们在下面讲
export default defineConfig(({ mode }) => {
// 根据当前工作目录中的 `mode` 加载 .env 文件
return {
// vite config
define: {
// 设置第三个参数为 '' 来加载所有环境变量,而不管是否有 `VITE_` 前缀。
'process.env': loadEnv(mode, process.cwd(), '')
}
}
})
(2)mode值也可以配合scripts命令从process.argv
中拿,实际上defineConfig的mode参数也是拿的这个
tips:
a. 注意下面的 --mode development
命令在最后面,方便process.argv
取其值;
b. 注意 --mode development
和新建的.env.development
文件同名
// package.json
"scripts": {
"dev": "vite --host --mode development",
"test": "vue-tsc --noEmit && vite build --mode test",
"build": "vue-tsc --noEmit && vite build --mode production",
"preview": "vite preview"
}
import { loadEnv } from 'vite'
const mode = process.argv[process.argv.length - 1]
console.log(mode)
const env = loadEnv(mode, process.cwd())
// env
// {
// VITE_PROJECT_ENV: 'development',
// VITE_APP_URL: 'https://app-api-0.com/'
// }
- 上面代码中提到define,定义全局常量。这在多页面应用中非常有用
在多页面中你会发现:process没有,报错:process is not defined
,import.meta.env
也没有合并自定义的变量
define: {
// 设置第三个参数为 '' 来加载所有环境变量,而不管是否有 `VITE_` 前缀。
'process.env': loadEnv(mode, process.cwd(), '')
}
全局使用
const {VITE_APP_URL} = process.env
第二部分:多页面配置
目录结构还是一样的,views下面多个页面都有自己的main.ts/index.vue
├── public
└── build // 多页面生成
└── src
├── api // 请求
├── assets // 静态资源
├── components // 公共组件
├── config // 公用类
└── views // 页面
└── home // 页面
├── lang // 多语言
├── icons // svg图标
├── components // 组件
├── router // 路由,选择性需要
├── store // 选择性需要
├── main.ts //
├── index.vue //
第一步:还是一样新建build文件夹下面有puligns.ts/getPages.ts,我们拆分plugins的引用以及多页面生成代码
//getPages.ts多页面入口html生成
import glob from "glob";
import fs from "fs";
import { resolve } from 'path'
const input = {}
const mainEntry = []
const iconDirs = []
function getPages() {
// 遍历文件夹中含有main.ts的文件夹路径
const allEntry = glob.sync("./src/views/**/main.ts");
// 获取模板
const temp = fs.readFileSync("./index.html");
console.log('allEntry', allEntry)
// 创建多页面模板
allEntry.forEach((entry: string) => {
const pathArr = entry.split("/");
const name = pathArr[pathArr.length - 2];
// 判断文件是否存在
try {
fs.accessSync(`./src/views/${name}.html`);
} catch (err) {
console.log(`创建${name}.html文件`);
const index = temp.toString().indexOf("