个人主页:Silence Lamb
本章内容:【基于VITE项目开发框架】
Tips
:vue-cli + vue3 + yarn + vite + ts
# vue/cli
yarn global add @vue/cli
# typescript parser
yarn add @typescript-eslint/parser --dev
# 如果没有安装yarn,需先安装yarn
npm i yarn -g
# 创建vite项目
yarn create vite vue3-vite-app --template vue-ts
# 进入项目根目录
cd vue3-vite-app
# 安装依赖
yarn install
# 启动项目
yarn dev
Tips
:建议配合 .npmrc 配置使用
# 提升一些依赖包至 node_modules
# 解决部分包模块not found的问题
# 用于配合 pnpm
shamefully-hoist = true
# node-sass 下载问题
# sass_binary_site="https://npm.taobao.org/mirrors/node-sass/"
Tips
:模板语法配合jsx语法,使用起来非常方便、灵活~一些必须的插件
yarn add @vitejs/plugin-legacy -S // 低版本浏览器兼容
yarn add @vitejs/plugin-vue -S // vue 支持
yarn add @vitejs/plugin-vue-jsx -S // jsx 支持
Tips
:开启Eslint的支持
yarn add eslint -D
yarn add eslint-plugin-vue -D
yarn add @typescript-eslint/eslint-plugin -D
yarn add @typescript-eslint/parser -D
Tips
:**echo {}> .**eslintrc.js
module.exports = {
root: true,
env: {
browser: true,
node: true,
es6: true,
},
parser: 'vue-eslint-parser',
parserOptions: {
parser: '@typescript-eslint/parser',
ecmaVersion: 2020,
sourceType: 'module',
jsxPragma: 'React',
ecmaFeatures: {
jsx: true,
},
},
plugins: ['vue', '@typescript-eslint', 'prettier'],
rules: {
'@typescript-eslint/ban-ts-ignore': 'off',
'@typescript-eslint/no-unused-vars': 'off',
'@typescript-eslint/explicit-function-return-type': 'off',
'@typescript-eslint/no-explicit-any': 'off',
'@typescript-eslint/no-var-requires': 'off',
'@typescript-eslint/no-empty-function': 'off',
'@typescript-eslint/no-use-before-define': 'off',
'@typescript-eslint/ban-ts-comment': 'off',
'@typescript-eslint/ban-types': 'off',
'@typescript-eslint/no-non-null-assertion': 'off',
'@typescript-eslint/explicit-module-boundary-types': 'off',
'no-var': 'error',
'prettier/prettier': ['error', { trailingComma: 'es5', singleQuote: true, printWidth: 80, tabWidth: 2 }],
// 禁止出现console
'no-console': 'warn',
// 禁用debugger
'no-debugger': 'warn',
// 禁止出现重复的 case 标签
'no-duplicate-case': 'warn',
// 禁止出现空语句块
'no-empty': 'warn',
// 禁止不必要的括号
'no-extra-parens': 'off',
// 禁止对 function 声明重新赋值
'no-func-assign': 'warn',
// 禁止在 return、throw、continue 和 break 语句之后出现不可达代码
'no-unreachable': 'warn',
// 强制所有控制语句使用一致的括号风格
curly: 'warn',
// 要求 switch 语句中有 default 分支
'default-case': 'warn',
// 强制尽可能地使用点号
'dot-notation': 'warn',
// 要求使用 === 和 !==
eqeqeq: 'warn',
// 禁止 if 语句中 return 语句之后有 else 块
'no-else-return': 'warn',
// 禁止出现空函数
'no-empty-function': 'warn',
// 禁用不必要的嵌套块
'no-lone-blocks': 'warn',
// 禁止使用多个空格
'no-multi-spaces': 'warn',
// 禁止多次声明同一变量
'no-redeclare': 'warn',
// 禁止在 return 语句中使用赋值语句
'no-return-assign': 'warn',
// 禁用不必要的 return await
'no-return-await': 'warn',
// 禁止自我赋值
'no-self-assign': 'warn',
// 禁止自身比较
'no-self-compare': 'warn',
// 禁止不必要的 catch 子句
'no-useless-catch': 'warn',
// 禁止多余的 return 语句
'no-useless-return': 'warn',
// 禁止变量声明与外层作用域的变量同名
'no-shadow': 'off',
// 允许delete变量
'no-delete-var': 'off',
// 强制数组方括号中使用一致的空格
'array-bracket-spacing': 'warn',
// 强制在代码块中使用一致的大括号风格
'brace-style': 'warn',
// 强制使用骆驼拼写法命名约定
camelcase: 'warn',
// 强制使用一致的缩进
indent: 'off',
// 强制在 JSX 属性中一致地使用双引号或单引号
// 'jsx-quotes': 'warn',
// 强制可嵌套的块的最大深度4
'max-depth': 'warn',
// 强制最大行数 300
// "max-lines": ["warn", { "max": 1200 }],
// 强制函数最大代码行数 50
// 'max-lines-per-function': ['warn', { max: 70 }],
// 强制函数块最多允许的的语句数量20
'max-statements': ['warn', 100],
// 强制回调函数最大嵌套深度
'max-nested-callbacks': ['warn', 3],
// 强制函数定义中最多允许的参数数量
'max-params': ['warn', 3],
// 强制每一行中所允许的最大语句数量
'max-statements-per-line': ['warn', { max: 1 }],
// 要求方法链中每个调用都有一个换行符
'newline-per-chained-call': ['warn', { ignoreChainWithDepth: 3 }],
// 禁止 if 作为唯一的语句出现在 else 语句中
'no-lonely-if': 'warn',
// 禁止空格和 tab 的混合缩进
'no-mixed-spaces-and-tabs': 'warn',
// 禁止出现多行空行
'no-multiple-empty-lines': 'warn',
// 禁止出现;
semi: ['warn', 'never'],
// 强制在块之前使用一致的空格
'space-before-blocks': 'warn',
// 强制在 function的左括号之前使用一致的空格
// 'space-before-function-paren': ['warn', 'never'],
// 强制在圆括号内使用一致的空格
'space-in-parens': 'warn',
// 要求操作符周围有空格
'space-infix-ops': 'warn',
// 强制在一元操作符前后使用一致的空格
'space-unary-ops': 'warn',
// 强制在注释中 // 或 /* 使用一致的空格
// "spaced-comment": "warn",
// 强制在 switch 的冒号左右有空格
'switch-colon-spacing': 'warn',
// 强制箭头函数的箭头前后使用一致的空格
'arrow-spacing': 'warn',
'no-var': 'warn',
'prefer-const': 'warn',
'prefer-rest-params': 'warn',
'no-useless-escape': 'warn',
'no-irregular-whitespace': 'warn',
'no-prototype-builtins': 'warn',
'no-fallthrough': 'warn',
'no-extra-boolean-cast': 'warn',
'no-case-declarations': 'warn',
'no-async-promise-executor': 'warn',
},
}
Tips
:**echo {}> **.eslintignore
# eslint 忽略检查 (根据项目需要自行添加)
node_modules
dist
Tips
:安装 prettier
# 安装 prettier
yarn add prettier -D
# 安装插件 eslint-config-prettier
yarn add eslint-config-prettier -D
Tips
:echo {}> .prettierrc.js
/*
* @Description :
* @Author : SilenceLamb
* @Version : V1.0.0
*/
module.exports = {
printWidth: 150,
// 指定每个缩进级别的空格数
tabWidth: 4,
// 使用制表符而不是空格缩进行
useTabs: false,
// 在语句末尾打印分号
semi: false,
// 使用单引号而不是双引号
singleQuote: true,
// 更改引用对象属性的时间 可选值""
quoteProps: 'as-needed',
// 在JSX中使用单引号而不是双引号
jsxSingleQuote: false,
// 多行时尽可能打印尾随逗号。(例如,单行数组永远不会出现逗号结尾。) 可选值"",默认none
trailingComma: 'es5',
// 在对象文字中的括号之间打印空格
bracketSpacing: true,
// 在单独的箭头函数参数周围包括括号 always:(x) => x \ avoid:x => x
arrowParens: 'always',
// 这两个选项可用于格式化以给定字符偏移量(分别包括和不包括)开始和结束的代码
rangeStart: 0,
rangeEnd: Infinity,
// 指定要使用的解析器,不需要写文件开头的 @prettier
requirePragma: false,
// 不需要自动在文件开头插入 @prettier
insertPragma: false,
// 使用默认的折行标准 always\never\preserve
proseWrap: 'preserve',
// 指定HTML文件的全局空格敏感度 css\strict\ignore
htmlWhitespaceSensitivity: 'css',
// Vue文件脚本和样式标签缩进
vueIndentScriptAndStyle: false,
// 换行符使用 lf 结尾是 可选值""
endOfLine: 'lf',
}
Tips
:echo {}> .prettierignore
# 忽略格式化文件 (根据项目需要自行添加)
node_modules
dist
Tips
:package.json
"scripts": {
"lint": "eslint src --fix --ext .ts,.tsx,.vue,.js,.jsx",
"prettier": "prettier --write ."
},
import MyComponent from '@/components/MyComponent';
Tips
:首先,在tsconfig.json中添加一个"paths"属性,然后以别名为键名,路径为键值
{
"compilerOptions": {
"baseUrl": "./",
"paths": {
"@/*": ["src/*"]
}
},
"exclude": ["node_modules", "dist"]
}
Tips
:在项目根目录下新建config文件夹,在其中新建一个alias.js文件
/*
* @Description : 配置别名
* @Author : SilenceLamb
* @Version : V1.0.0
*/
import {resolve} from 'path'
function pathResolve(dir: string) {
return resolve(process.cwd(), '.', dir)
}
export default {
'/@/': pathResolve('src/'),
'/#/': pathResolve('config/'),
}
Tips
: 如果path找不到:npm install @types/node --save-dev
import { UserConfig, ConfigEnv } from 'vite'
import aliasList from "./config/aliases";
export default ({ command, mode }: ConfigEnv): UserConfig => {
const isBuild = command === 'build'
return {
resolve: {
alias: aliasList ,
},
}
}
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相反)
import.meta.env.SSR: {boolean} 应用是否运行在 server 上
.env # 所有情况下都会加载
.env.local # 所有情况下都会加载,但会被 git 忽略
.env.[mode] # 只在指定模式下加载
.env.[mode].local # 只在指定模式下加载,但会被 git 忽略
# 页面标题
VITE_APP_TITLE=开发环境
# 开发环境配置
ENV='development'
# 开发环境
VITE_APP_BASE_API='/dev-api'
# 路由懒加载
VITE_CLI_BABEL_TRANSPILE_MODULES=true
Tips
:另外一种配置方式
# 页面标题
VITE_APP_TITLE=线上环境
# 生产环境配置
ENV='production'
# 生产环境
VITE_APP_BASE_API='/'
# 页面标题
VITE_APP_TITLE=测试环境配置
NODE_ENV=production
# 测试环境配置
ENV='staging'
# 测试环境
VITE_APP_BASE_API='/stage-api'
/*
* @Description : 为环境变量增加智能提示
* @Author : SilenceLamb
* @Version : V1.0.0
*/
interface ImportMetaEnv {
readonly VITE_NODE_ENV:string;//定义提示信息 数据是只读的无法被修改
//多个变量定义多个...
}
interface ImportMeta {
readonly env: ImportMetaEnv
}
Tips
:vite.config.ts: 不能使用 import.meta.env
const env = loadEnv(mode, process.cwd());
const { VITE_NODE_ENV, VITE_APP_BASE_API } = env;
console.log(VITE_APP_BASE_API);
console.log(VITE_NODE_ENV);
Tips
:package.json
"scripts": {
"dev": "vite --mode development",
"build": "vue-tsc --noEmit && vite build",
"build:prod": "vue-tsc --noEmit && vite build --mode production",
},
/*
* @Description : 项目设置
* @Author : SilenceLamb
* @Version : V1.0.0
*/
export default {
/**
* 前端端口
*/
vuePort: 80,
/**
* 后端接口
*/
adminUrl: 'http://localhost:88',
};
export default defineConfig({
...
server: {
port: 8080, // 开发环境启动的端口
proxy: {
'/api': {
// 当遇到 /api 路径时,将其转换成 target 的值
target: 'http://127.0.0.1:8080/api/',
changeOrigin: true,
rewrite: (path) => path.replace(/^\/api/, ''), // 将 /api 重写为空
},
}
}
})
yarn add unplugin-vue-components unplugin-auto-import -D
/*
* @Description : 按需加载,自动引入依赖
* @Author : SilenceLamb
* @Version : V1.0.0
*/
import AutoImport from 'unplugin-auto-import/vite'
import { ElementPlusResolver } from 'unplugin-vue-components/resolvers'
export default function AutoImportDeps() {
return AutoImport({
resolvers: [ElementPlusResolver()],
imports: ['vue', 'vue-router', 'vue-i18n', '@vueuse/head', '@vueuse/core'],
dts: 'src/auto/auto-imports.d.ts',
})
}
/*
* @Description : 按需加载,自动引入组件
* @Author : SilenceLamb
* @Version : V1.0.0
*/
import Components from 'unplugin-vue-components/vite'
import { ElementPlusResolver } from 'unplugin-vue-components/resolvers'
export default function AutoComponents () {
return Components({
// 自动导入自定义的组件
dirs: ['src/components'],
// 组件的有效文件扩展名
extensions: ['vue'],
// 搜索子目录
deep: true,
// 组件解释器
resolvers: [ElementPlusResolver()],
// 文件生成目录
dts: 'src/auto/components.d.ts',
// 允许子目录作为组件的命名空间前缀
directoryAsNamespace: false,
// 用于忽略命名空间前缀的子目录路径
// works when `directoryAsNamespace: true`
globalNamespaces: [],
// 用于转换目标的筛选器
include: [/\.vue$/, /\.vue\?vue/],
exclude: [/[\\/]node_modules[\\/]/, /[\\/]\.git[\\/]/, /[\\/]\.nuxt[\\/]/],
})
}
yarn add vite-plugin-style-import -D
yarn add consola -D
import { createStyleImportPlugin, ElementPlusResolve } from 'vite-plugin-style-import'
export default function AutoImportStyle () {
return createStyleImportPlugin({
resolves: [ElementPlusResolve()],
// 自定义规则
libs: [
{
libraryName: 'element-plus',
esModule: true,
resolveStyle: (name) => {
return `element-plus/es/components/${name}/style/index`
},
},
],
})
}
/*
* @Description : 配置插件
* @Author : SilenceLamb
* @Version : V1.0.0
*/
import type { Plugin } from 'vite'
import vue from '@vitejs/plugin-vue'
import vueJsx from '@vitejs/plugin-vue-jsx'
import AutoComponents from './modules/autoComponents'
import AutoImportDeps from './modules/autoImportDeps'
import AutoImportStyle from './modules/autoImportStyle'
import autoRestartVite from '/#/plugins/modules/autoRestartVite'
export default function createVitePlugins(isBuild: boolean) {
const vitePlugins: (Plugin | Plugin[])[] = [
// vue支持
vue(),
// JSX支持
vueJsx(),
// 自动按需引入组件
AutoComponents(),
// 自动按需引入依赖
AutoImportDeps(),
//自动引入样式
AutoImportStyle(),
//自动重启Vite服务
autoRestartVite(),
]
console.log(isBuild)
getPlus()
return vitePlugins
}
import { UserConfig, ConfigEnv } from 'vite'
import server from "./config/server";
import aliasList from "./config/aliases";
import createVitePlugins from "/#/plugins";
export default ({ command, mode }: ConfigEnv): UserConfig => {
const isBuild = command === 'build'
console.log(command, mode)
return {
resolve: {
alias: aliasList,
},
//插件配置
plugins: createVitePlugins(isBuild),
//跨域配置
server: server,
}
}
yarn add npm i vite-plugin-restart -D
/*
* @Description : 自动重启Vite服务
* @Author : SilenceLamb
* @Version : V1.0.0
*/
import ViteRestart from 'vite-plugin-restart'
export default function autoRestartVite() {
return ViteRestart({
restart: ['vite.config.ts'],
})
}