vue3 项目构建
1.项目基础搭建
1.1 使用 vite 搭建 Vue3 项目
基础条件
已安装 16.0 或更高版本的 Node.js
初始化项目
npm create vite@latest
或者
yarn create vite
- 输入项目名称:vue3-vite-ts-demo
- 输入项目框架:Vue
- 输入项目语言:TypeScript
success Installed "create-vite@4.1.0" with binaries:
- create-vite
- cva
√ Project name: ... vue3-vite-ts-demo
√ Select a framework: » Vue
√ Select a variant: » TypeScript
安装依赖
cd vue3-vite-ts-demo && yarn
项目初始化完成
|-- vue3-vite-ts-demo
| |-- .gitignore
| |-- index.html
| |-- package.json
| |-- README.md
| |-- tsconfig.json
| |-- tsconfig.node.json
| |-- vite.config.ts
| |-- .vscode
| | |-- extensions.json
| |-- public
| | |-- vite.svg
| |-- src
| |-- App.vue
| |-- main.ts
| |-- style.css
| |-- vite-env.d.ts
| |-- assets
| | |-- vue.svg
| |-- components
| |-- HelloWorld.vue
增加 vscode 插件TypeScript Vue Plugin (Volar)
屏蔽 vscode 插件vetur
1.2 优化 tsconfig.json
1.2.1 添加 node 类型识别
避免 vite.config.ts 中不能识别 nodeJs 的代码
yarn add @types/node -D
"compilerOptions": {
"types": [
"node"
],
}
1.2.2 添加别名'@'路径识别
"compilerOptions": {
"baseUrl": ".",
"paths": {
"@/*": [
"src/*"
]
},
}
1.2.3 取消部分严格语法的校验
"compilerOptions": {
// 不使用的变量
"noUnusedLocals": false,
// 不使用的参数
"noUnusedParameters": false,
// 禁止未申明时类型默认为any
"noImplicitAny": false,
// 禁止未申明时this
"noImplicitThis": false,
}
1.2.4 排除对构建代码的编译
/* "exclude"指定哪些文件不包含
"*" 表示任意文件
"**" 表示任意目录
*/
"exclude": [
"publish/*",
"vite.config.ts"
],
1.3 添加 eslint
1.3.1 安装包 eslint eslint-plugin-vue
yarn add -D eslint eslint-plugin-vue
1.3.2 初始化 eslInt 配置
npm init @eslint/config
√ How would you like to use ESLint? · style
√ What type of modules does your project use? · esm
√ Which framework does your project use? · vue
√ Does your project use TypeScript? · No / Yes
√ Where does your code run? · browser
√ How would you like to define a style for your project? · prompt
√ What format do you want your config file to be in? · JavaScript
√ What style of indentation do you use? · tab
√ What quotes do you use for strings? · single
√ What line endings do you use? · unix
√ Do you require semicolons? · No / Yes
之后生成文件 .eslintrc.js
- 增加 extends:"plugin:prettier/recommended",对 prettier 的支持
- 增加排除路径 ignorePatterns: ['publish/**/*', 'vite.config.ts', '.prettierrc.js', '.eslintrc.js'],
- 增加 rules 根据需要
module.exports = {
env: {
browser: true,
es2021: true,
},
extends: [
"eslint:recommended",
"plugin:@typescript-eslint/recommended",
"plugin:vue/vue3-essential",
"plugin:prettier/recommended",
],
overrides: [
{
env: {
node: true,
},
files: [".eslintrc.{js,cjs}"],
parserOptions: {
sourceType: "script",
},
},
],
ignorePatterns: [
"publish/**/*",
"vite.config.ts",
".prettierrc.js",
".eslintrc.js",
],
parserOptions: {
ecmaVersion: "latest",
parser: "@typescript-eslint/parser",
sourceType: "module",
},
plugins: ["@typescript-eslint", "vue"],
rules: {
indent: ["off", 2],
"linebreak-style": ["error", "unix"],
quotes: ["error", "single"],
semi: ["error", "always"],
"no-unused-vars": "off",
"@typescript-eslint/no-unused-vars": "off",
"@typescript-eslint/no-explicit-any": "off",
"no-empty": "off",
"vue/multi-word-component-names": "off",
},
};
"semi"和"quotes"是 ESLint 中规则的名称。第一个值是规则的错误级别,可以是以下值之一:
- "off"或 0 -关闭规则
- "warn"或 1 -将规则作为警告打开(不影响退出代码)
- "error"或 2 -将规则作为错误打开(退出代码将为 1)
- 这三个错误级别允许你细粒度地控制 ESLint 如何应用规则。
1.3.3 配置 VS Code
在 vscode 插件里边搜索 ESLint 插件
1.3.4 添加其他插件
yarn add @typescript-eslint/parser
1.3.5 增加 lint 命令
"lint": "eslint . --ext .vue,.js,.jsx,.cjs,.mjs,.ts,.tsx,.cts,.mts --fix --ignore-path .gitignore",
1.4 添加 prettier
在 vscode 插件里边搜索 prettier 插件
yarn add prettier
添加其他插件
yarn add eslint-config-prettier eslint-plugin-prettier
配置.prettierrc.js 文件:
- useTabs:使用 tab 缩进还是空格缩进,选择 false 时表示使用空格;
- tabWidth:tab 是空格的情况下,是几个空格,选择 2 个;
- printWidth:当行字符的长度,推荐 80;
- singleQuote:使用单引号还是双引号,选择 true,使用单引号;
- trailingComma:在多行输入的尾逗号是否添加,设置为 none;
- semi:语句末尾是否要加分号,默认值 true,选择 false 表示不加;
- endOfLine:结尾符号 lf
module.exports = {
useTabs: true,
printWidth: 80,
singleQuote: true,
trailingComma: "none",
semi: true,
endOfLine: "lf",
};
添加 vscode prettier 插件
在项目根目录添加.vscode/settings.json
{
"editor.defaultFormatter": "esbenp.prettier-vscode",
"editor.formatOnPaste": false, // required
"editor.formatOnType": false, // required
"editor.formatOnSave": true, // optional
"editor.formatOnSaveMode": "file", // required to format on save
"files.autoSave": "onFocusChange", // optional but recommended
"[typescript]": {
"editor.defaultFormatter": "dbaeumer.vscode-eslint"
},
"[vue]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
}, // set as "true" to run 'prettier' last not first
"[javascript]": {
"editor.defaultFormatter": "dbaeumer.vscode-eslint"
},
"eslint.validate": [
"javascript",
"typeScript",
"javascriptreact",
"vue"
],
}
在项目根目录 **package.json** 的 **script** 添加 **format** 命令
```sh
"format": "prettier --write \"src/**/*.ts\" \"src/**/*.vue\" ",
1.5 增加环境变量
根目录增加各种模式的环境变量文件:
// .env.local-mode文件
VITE_APP_API_URL_MODE = "local";
VITE_APP_API_DOMAIN = "http://localhost:9010";
// .env.local-test文件
VITE_APP_API_URL_MODE = "test";
VITE_APP_API_DOMAIN = "http://test.api.xxx.com";
// .env.local-prod文件
VITE_APP_API_URL_MODE = "prod";
VITE_APP_API_DOMAIN = "http://api.xxx.com";
在 package.json的文件中的script增加命令
"script":{
"local-dev": "vite --mode local-mode",
"test-dev": "vite --mode test-mode",
"prod-dev": "vite --mode prod-mode",
"test-build": "vue-tsc && vite build --mode test-mode",
"prod-build": "vue-tsc && vite build --mode prod-mode"
}
在命令行加载 --mode local-mode 的时候就会加载文件 .env 与.env-local
在 js 实际代码中就能通过环境变量 i
通过环境变量 i
const mode = import.meta.env.VITE_APP_API_URL_MODE || "local";
const apiUrlPrefix = import.meta.env.VITE_APP_API_DOMAIN + "/";
vite 的环境变量:为了防止意外地将一些环境变量泄漏到客户端,只有以 VITE_ 为前缀的变量才会暴露给经过 vite 处理的代码。
Vite 在一个特殊的 import.meta.env 对象上暴露环境变量。这里有一些在所有情况下都可以使用的内建变量:
import.meta.env.MODE: {string} 应用运行的模式。
import.meta.env.BASE_URL: {string} 部署应用时的基本 URL。他由base 配置项决定。
import.meta.env.PROD: {boolean} 应用是否运行在生产环境。
import.meta.env.DEV: {boolean} 应用是否运行在开发环境 (永远与 import.meta.env.PROD相反)。
.env.[mode] # 只在指定模式下加载
1.6 修改 vite.config.ts
首先添加@types/node
,便于识别vite.config.ts
文件,否则文件中的 path 模块无法识别类型
yarn add -D @types/node
# 或者
npm i -D @types/node
自动导入:首先你需要安装unplugin-vue-components
和 unplugin-auto-import
这两款插件
yarn add -D unplugin-vue-components unplugin-auto-import
# 或者
npm i -D unplugin-vue-components unplugin-auto-import
1.6.1 Vant 版本情况
- 添加别名@
- 添加 less,less 文件中注入 less 代码
@import '@/style/variable.less'
,相当于增加全部 less 变量 - 修改本地开发的端口为 8010
- 设置 http 代理,有需要时候设置
增加环境变量文件 .env.local-mode
// env.local-mode
VITE_APP_API_URL_MODE = "local"; // 有无分号均可
VITE_APP_API_DOMAIN = "http://localhost:9010";
在package.json中
增加local-mode
的相关脚本
// package.json
{
// ...
"scripts": {
"dev": "vite",
// 对应.env.local-mode文件
"local-dev": "vite --mode local-mode"
}
}
import vue from "@vitejs/plugin-vue";
import Components from "unplugin-vue-components/vite";
import { VantResolver } from "unplugin-vue-components/resolvers";
import { defineConfig, loadEnv, ConfigEnv, UserConfig } from "vite";
import eslint from "vite-plugin-eslint";
import path from "path";
export default defineConfig(({ mode }: ConfigEnv): UserConfig => {
const root = process.cwd();
/*当运行"vite --mode local-mode", mode的值为"local-mode" */
const env = loadEnv(mode, root); // 环境变量对象
/****当运行"vite --mode local-mode"时:
* env的值为:
* {
* VITE_APP_API_URL_MODE: '"local";',
* VITE_APP_API_DOMAIN: '"http://localhost:9010";'
* }
*
*/
const { VITE_APP_API_DOMAIN } = env;
const proxyTargetUrl = VITE_APP_API_DOMAIN;
return {
plugins: [
vue(),
eslint(),
Components({
resolvers: [VantResolver()],
}),
],
resolve: {
//设置别名
alias: {
"@": path.resolve(__dirname, "src"),
},
},
css: {
preprocessorOptions: {
less: {
additionalData: "@import '@/style/variable.less';",
},
},
},
server: {
port: 8010, //启动端口
hmr: {
host: "localhost",
port: 8010,
},
// 设置 https 代理
proxy: {
"/api": {
target: proxyTargetUrl,
changeOrigin: true,
// rewrite: (path: string) => path.replace(/^\/api/, 'api/')
},
},
},
};
});
1.6.2 Element-plus 版本情况
- 添加别名@
- 添加 less,less 文件中注入 less 代码
@import '@/style/variable.less'
,相当于增加全部 less 变量 - 修改本地开发的端口为 8010
- 设置 http 代理,有需要时候设置
import vue from "@vitejs/plugin-vue";
import Components from "unplugin-vue-components/vite";
import { defineConfig, loadEnv, ConfigEnv, UserConfig } from "vite";
import { ElementPlusResolver } from "unplugin-vue-components/resolvers";
import AutoImport from "unplugin-auto-import/vite";
import eslint from "vite-plugin-eslint";
import path from "path";
export default defineConfig(({ mode }: ConfigEnv): UserConfig => {
const root = process.cwd();
const env = loadEnv(mode, root); // 环境变量对象
const { VITE_APP_API_DOMAIN } = env;
const proxyTargetUrl = VITE_APP_API_DOMAIN;
return {
plugins: [
vue(),
eslint(),
AutoImport({
resolvers: [ElementPlusResolver()],
}),
Components({
resolvers: [ElementPlusResolver()],
}),
],
resolve: {
//设置别名
alias: {
"@": path.resolve(__dirname, "src"),
},
},
css: {
preprocessorOptions: {
less: {
additionalData: "@import '@/style/variable.less';",
},
},
},
server: {
port: 8010, //启动端口
hmr: {
host: "localhost",
port: 8010,
},
// 设置 https 代理
proxy: {
"/api": {
target: proxyTargetUrl,
changeOrigin: true,
// rewrite: (path: string) => path.replace(/^\/api/, 'api/')
},
},
},
};
});
1.6.3 vite.config.ts 参考配置
import { defineConfig, loadEnv } from "vite";
import type { UserConfig, ConfigEnv } from "vite";
import vue from "@vitejs/plugin-vue";
import vueJsx from "@vitejs/plugin-vue-jsx"; //tsx插件引入
import AutoImport from "unplugin-auto-import/vite"; //自动引入ref,reactive等等等
// 配置antd-v按需加载
import Components from "unplugin-vue-components/vite";
import { AntDesignVueResolver } from "unplugin-vue-components/resolvers";
// import path from 'path';
import { resolve, join } from "path";
import { wrapperEnv } from "./build/utils";
// defineConfig 工具函数,这样不用 jsdoc 注解也可以获取类型提示
export default defineConfig(({ command, mode }: ConfigEnv): UserConfig => {
console.log(command, mode, "===");
const root = process.cwd();
const env = loadEnv(mode, root); // 环境变量对象
console.log("环境变量------", env);
console.log("文件路径( process.cwd())------", root);
console.log("文件路径(dirname)------", __dirname + "/src");
const { VITE_DROP_CONSOLE } = wrapperEnv(env);
// // dev 独有配置
return {
root, //项目根目录(index.html 文件所在的位置) 默认: process.cwd()
base: "/", // 开发或生产环境服务的公共基础路径:默认'/' 1、绝对 URL 路径名: /foo/; 2、完整的 URL: https://foo.com/; 3、空字符串或 ./(用于开发环境)
publicDir: resolve(__dirname, "./dist"), //默认'public' 作为静态资源服务的文件夹 (打包public文件夹会没有,里面得东西会直接编译在dist文件下)
assetsInclude: resolve(__dirname, "./src/assets"), // 静态资源处理
// ******插件配置******
plugins: [
vue(),
vueJsx(),
AutoImport({
imports: [
"vue",
"vue-router",
"pinia",
{
axios: [
["default", "axios"], // import { default as axios } from 'axios',
],
},
],
dts: "types/auto-import.d.ts", //生成全局引入的文件
}),
Components({
resolvers: [
AntDesignVueResolver({
importStyle: "less", //修改antdv主题色
}),
],
}),
], //配置插件
// ******开发服务器配置******
server: {
https: true, //(使用https)启用 TLS + HTTP/2。注意:当 server.proxy 选项 也被使用时,将会仅使用 TLS
host: true, // 监听所有地址
port: 8080, //指定开发服务器端口:默认3000
open: true, //启动时自动在浏览器中打开
cors: false, //为开发服务器配置 CORS
proxy: {
//配置自定义代理规则
// 字符串简写写法
"/jpi": "http://192.168.1.97:4567",
"/api": {
target: "http://192.168.1.97:108",
changeOrigin: true, //是否跨域
rewrite: (path) => path.replace(/^\/api/, ""),
},
},
// hmr: {
// overlay: false
// }
},
// ******项目构建配置******
build: {
target: "modules", //设置最终构建的浏览器兼容目标 //es2015(编译成es5) | modules
outDir: "dist", // 构建得包名 默认:dist
assetsDir: "assets", // 静态资源得存放路径文件名 assets
sourcemap: false, //构建后是否生成 source map 文件
brotliSize: false, // 启用/禁用 brotli 压缩大小报告。 禁用该功能可能会提高大型项目的构建性能
minify: "esbuild", // 项目压缩 :boolean | 'terser' | 'esbuild'
chunkSizeWarningLimit: 1000, //chunk 大小警告的限制(以 kbs 为单位)默认:500
cssTarget: "chrome61", //防止 vite 将 rgba() 颜色转化为 #RGBA 十六进制符号的形式 (要兼容的场景是安卓微信中的 webview 时,它不支持 CSS 中的 #RGBA 十六进制颜色符号)
},
// ******resolver配置******
resolve: {
alias: {
// 别名配置
// 键必须以斜线开始和结束
"@": resolve(__dirname, "src"),
components: resolve(__dirname, "./src/components"),
assets: resolve(__dirname, "./src/assets"),
"#": resolve(__dirname, "types"),
build: resolve(__dirname, "build"),
},
},
// ******打印+debugger清除配置******
// 测试环境保留打印
esbuild: {
pure: VITE_DROP_CONSOLE ? ["console.log", "debugger"] : [],
},
css: {
// 全局变量+全局引入less+配置antdv主题色
preprocessorOptions: {
less: {
javascriptEnabled: true,
// 全局变量使用:@primary-color
modifyVars: {
"primary-color": "#1890ff", // 全局主色
"link-color": " #1890ff", // 链接色
"success-color": " #52c41a", // 成功色
"warning-color": " #faad14", // 警告色
"error-color": " #f5222d", // 错误色
"font-size-base": " 14px", // 主字号
"heading-color": " rgba(0, 0, 0, 0.85)", // 标题色
"text-color": " rgba(0, 0, 0, 0.65)", // 主文本色
"text-color-secondary": " rgba(0, 0, 0, 0.45)", // 次文本色
"disabled-color": " rgba(0, 0, 0, 0.25)", // 失效色
"border-radius-base": " 2px", // 组件/浮层圆角
"border-color-base": " #d9d9d9", // 边框色
"box-shadow-base": " 0 2px 8px rgba(0, 0, 0, 0.15)", // 浮层阴影
},
},
},
},
};
});