npm install vue --save
npm install @vitejs/plugin-vue @vue/compiler-sfc vite --save-dev
vite.config.js
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
// https://vitejs.dev/config/
export default defineConfig({
plugins: [vue()]
})
package.json
{
"name": "vite2-prepare",
"version": "1.0.0",
"scripts": {
"dev": "vite",
"build": "vite build",
"serve": "vite preview"
},
"dependencies": {
"vue": "^3.0.5"
},
"devDependencies": {
"@vitejs/plugin-vue": "^1.2.4",
"@vue/compiler-sfc": "^3.0.5",
"vite": "^2.4.0"
}
}
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" href="/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Vite App</title>
</head>
<body>
<div id="app"></div>
<script type="module" src="/src/main.js"></script>
</body>
</html>
src\main.js
import { createApp } from 'vue'
import App from './App.vue'
createApp(App).mount('#app')
src\App.vue
<template>
<img src="./assets/ico.jpg" />
<HelloWorld msg="Vue3 + Vite" />
</template>
<script setup>
//https://github.com/vuejs/rfcs/blob/master/active-rfcs/0040-script-setup.md
import HelloWorld from './components/HelloWorld.vue'
</script>
src\components\HelloWorld.vue
<template>
<h1>{{ msg }}</h1>
</template>
src\App.vue
<template>
+ <img src="./assets/avatar.jpg" />
</template>
<template>
<img src="./assets/avatar.jpg" />
+ <img :src="imgUrl" />
<HelloWorld msg="Hello Vue 3 + Vite" />
</template>
<script setup>
//https://github.com/vuejs/rfcs/blob/master/active-rfcs/0040-script-setup.md
import HelloWorld from './components/HelloWorld.vue'
+import imgUrl from './assets/avatar.jpg'
</script>
<template>
<img src="./assets/avatar.jpg" />
<img :src="imgUrl" />
+ <div class="avatar"></div>
<HelloWorld msg="Hello Vue 3 + Vite" />
</template>
<script setup>
//https://github.com/vuejs/rfcs/blob/master/active-rfcs/0040-script-setup.md
import HelloWorld from './components/HelloWorld.vue'
import imgUrl from './assets/avatar.jpg'
</script>
+<style scoped>
+.avatar{
+ width:200px;
+ height:200px;
+ background-image: url(./assets/avatar.jpg);
+ background-size: contain;
+}
+</style>
public
目录中,它应位于你的项目根目录/
根路径访问到,并且打包时会被完整复制到目标目录的根目录下public\avatar.jpg
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
+import {resolve} from 'path';
// https://vitejs.dev/config/
export default defineConfig({
+ resolve:{
+ alias:{
+ '@':resolve('src')
+ }
+ },
plugins: [vue()]
})
src\App.vue
<template>
+ <img src="@/assets/avatar.jpg" />
<img :src="avatarUrl" />
<div class="avatar"></div>
<HelloWorld msg="Hello Vue 3 + Vite" />
</template>
<script setup>
//https://github.com/vuejs/rfcs/blob/master/active-rfcs/0040-script-setup.md
+import HelloWorld from "@/components/HelloWorld.vue";
+import avatarUrl from "@/assets/avatar.jpg";
</script>
<style scoped>
.avatar {
width: 200px;
height: 200px;
+ background-image: url(@/assets/avatar.jpg);
background-size: contain;
}
</style>
src\main.js
import { createApp } from 'vue'
import App from './App.vue'
+import './global.css'
createApp(App).mount('#app')
src\global.css
#app {
background-color: lightgrey;
}
<style>
标签有 scoped
属性时,它的 CSS 只作用于当前组件中的元素data-v-hash
的方式来使css有了它对应模块的标识src\components\HelloWorld.vue
<template>
<h1>{{ msg }}</h1>
+ <a>超链接</a>
</template>
+<style scoped>
+a {
+ color: #42b983;
+}
+</style>
module
作用的style
都被保存到$style
对象中src\components\HelloWorld.vue
<template>
<h1>{{ msg }}</h1>
+ <a :class="$style.link">超链接</a>
</template>
+<style module>
+.link {
+ color: #42b983;
+}
+</style>
<template>
<h1>{{ msg }}</h1>
+ <a :class="style.link">超链接</a>
</template>
<script setup>
+import style from './HelloWorld.module.css';
</script>
src\components\HelloWorld.module.css
.link {
color: #42b983;
}
style lang="sass"
(或其他预处理器)自动开启npm i less sass -S
src\components\HelloWorld.vue
<template>
<h1>{{ msg }}</h1>
<a :class="style.link">超链接</a>
+ <h2>less</h2>
+ <h3>sass</h3>
</template>
<script setup>
import { reactive } from 'vue'
import style from './HelloWorld.module.css';
</script>
+<style scoped lang="less">
+@color:red;
+h2{
+ color:@color;
+}
+</style>
+<style scoped lang="scss">
+$color:green;
+h3{
+ color:$color;
+}
</style>
npm install autoprefixer --save
module.exports = {
plugins: [
require('autoprefixer')
]
}
>0.2%
not dead
not op_mini all
src\components\HelloWorld.vue
<template>
<h1>{{ msg }}</h1>
<a :class="style.link">超链接</a>
<h2>less</h2>
<h3>sass</h3>
+ <div class="postcss"></div>
</template>
<script setup>
import { reactive } from 'vue'
import style from './HelloWorld.module.css';
</script>
<style scoped lang="less">
@color:red;
h2{
color:@color;
}
</style>
<style scoped lang="scss">
$color:green;
h3{
color:$color;
}
</style>
+<style scoped>
+.postcss{
+ height:50px;
+ width:200px;
+ background-color: orange;
+ transform: rotate(90deg);
+}
+</style>
cnpm install typescript @babel/core @babel/preset-env @babel/preset-typescript --save-dev
.babelrc
{
"presets": [
["@babel/preset-env"],
"@babel/preset-typescript"
]
}
{
"compilerOptions": {
"target": "esnext",
"module": "esnext",
"moduleResolution": "node",
"strict": true,
"jsx": "preserve",
"sourceMap": true,
"resolveJsonModule": true,
"esModuleInterop": true,
"lib": ["esnext", "dom"]
},
"include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.vue"]
}
src\components\HelloWorld.vue
<template>
<h1>{{ msg }}</h1>
<h2>less</h2>
<h3>sass</h3>
<div class="postcss"></div>
+ <button @click="handleClick">{{state.count}}</button>
</template>
<script setup lang="ts">
import { reactive,defineProps } from 'vue'
+defineProps({
+ msg:String
+})
+interface State {
+ count:number;
+}
+let state = reactive<State>({count:0});
+const handleClick = ()=>{
+ console.log(state.count);
+ state.count++;
+}
</script>
<style scoped lang="less">
@color:red;
h2{
color:@color;
}
</style>
<style scoped lang="scss">
$color:green;
h3{
color:$color;
}
</style>
<style scoped>
.postcss{
height:50px;
width:200px;
background-color: orange;
transform: rotate(90deg);
}
</style>
.vue
文件src\shims-vue.d.ts
declare module '*.vue' {
import { DefineComponent } from 'vue'
const component: DefineComponent<{}, {}, any>
export default component
}
src\vite-env.d.ts
/// <reference types="vite/client" />
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import { resolve } from 'path';
// https://vitejs.dev/config/
export default defineConfig({
resolve: {
alias: {
'@': resolve('src')
}
},
+ server: {
+ proxy: {
+ '/api': {
+ target: 'http://jsonplaceholder.typicode.com',
+ changeOrigin: true,
+ rewrite: (path) => path.replace(/^\/api/, '')
+ }
+ }
+ },
plugins: [vue()]
})
src\App.vue
<template>
<img src="@/assets/avatar.jpg" />
<img :src="avatarUrl" />
<div class="avatar"></div>
<HelloWorld msg="Hello Vue 3 + Vite" />
</template>
<script setup>
//https://github.com/vuejs/rfcs/blob/master/active-rfcs/0040-script-setup.md
import HelloWorld from "@/components/HelloWorld.vue";
import avatarUrl from "@/assets/avatar.jpg";
+fetch('/api/todos/1')
+ .then(response => response.json())
+ .then(json => console.log(json))
</script>
<style scoped>
.avatar {
width: 200px;
height: 200px;
background-image: url(@/assets/avatar.jpg);
background-size: contain;
}
</style>
npm i mockjs vite-plugin-mock -D
node ./node_modules/vite-plugin-mock/node_modules/esbuild/install.js
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import { resolve } from 'path';
+import { viteMockServe } from "vite-plugin-mock";
// https://vitejs.dev/config/
export default defineConfig({
resolve: {
alias: {
'@': resolve('src')
}
},
server: {
proxy: {
'/api': {
target: 'http://jsonplaceholder.typicode.com',
changeOrigin: true,
rewrite: (path) => path.replace(/^\/api/, '')
}
}
},
+ plugins: [vue(),viteMockServe({})]
})
mock\test.ts
import { MockMethod } from 'vite-plugin-mock';
export default [
{
url: '/api/get',
method: 'get',
response: ({ query }) => {
return {
code: 0,
data: {
name: 'vben',
},
};
},
},
] as MockMethod[];
npm install eslint eslint-plugin-vue @vue/eslint-config-typescript @typescript-eslint/parser @typescript-eslint/eslint-plugin --save-dev
src\components\HelloWorld.vue
<template>
<h1>{{ msg }}</h1>
<h2>less</h2>
<h3>sass</h3>
<div class="postcss" />
<button @click="handleClick">
{{ state.count }}
</button>
</template>
<script setup lang="ts">
import { reactive,defineProps } from 'vue'
defineProps({
+ msg:{
+ type:String,
+ default:''
+ }
})
interface State {
count:number;
}
let state = reactive<State>({count:0});
const handleClick = ()=>{
console.log(state.count);
state.count++;
}
</script>
<style scoped lang="less">
@color:red;
h2{
color:@color;
}
</style>
<style scoped lang="scss">
$color:green;
h3{
color:$color;
}
</style>
<style scoped>
.postcss{
height:50px;
width:200px;
background-color: orange;
transform: rotate(90deg);
}
</style>
src\main.ts
import { createApp } from 'vue'
import App from './App.vue'
import './global.css'
createApp(App).mount('#app')
.eslintrc.js
module.exports = {
root: true,
env: {
browser: true,
es2021: true,
node: true
},
extends: [
"plugin:vue/vue3-recommended",
"eslint:recommended",
"@vue/typescript/recommended"
],
parserOptions: {
ecmaVersion: 2021
},
rules: {
"no-unused-vars": "off",
"@typescript-eslint/no-unused-vars": "off",
}
}
.eslintignore
*.css
*.jpg
*.jpeg
*.png
*.gif
*.d.ts
package.json
{
"name": "zhufeng-vite2-prepare",
"version": "1.0.0",
"scripts": {
"dev": "vite",
"build": "vite build",
"serve": "vite preview",
+ "lint":"eslint --ext .ts,vue src/** --no-error-on-unmatched-pattern --quiet",
+ "lint:fix":"eslint --ext .ts,vue src/** --no-error-on-unmatched-pattern --fix"
},
"dependencies": {
"less": "^4.1.1",
"sass": "^1.35.2",
"vue": "^3.0.5"
},
"devDependencies": {
+ "@typescript-eslint/eslint-plugin": "^4.28.2",
+ "@typescript-eslint/parser": "^4.28.2",
"@vitejs/plugin-vue": "^1.2.4",
"@vue/compiler-sfc": "^3.0.5",
+ "@vue/eslint-config-typescript": "^7.0.0",
"autoprefixer": "^10.2.6",
+ "eslint": "^7.30.0",
+ "eslint-plugin-vue": "^7.13.0",
"mockjs": "^1.1.0",
"vite": "^2.4.0",
"vite-plugin-mock": "^2.9.1"
}
}
Prettier
npm install prettier eslint-plugin-prettier @vue/eslint-config-prettier --save-dev
{
"name": "zhufeng-vite2-prepare",
"version": "1.0.0",
"scripts": {
"dev": "vite",
"build": "vite build",
"serve": "vite preview",
"lint": "eslint --ext .ts,vue src/** --no-error-on-unmatched-pattern --quiet",
"lint:fix": "eslint --ext .ts,vue src/** --no-error-on-unmatched-pattern --fix"
},
"dependencies": {
"less": "^4.1.1",
"sass": "^1.35.2",
"vue": "^3.0.5"
},
"devDependencies": {
"@typescript-eslint/eslint-plugin": "^4.28.2",
"@typescript-eslint/parser": "^4.28.2",
"@vitejs/plugin-vue": "^1.2.4",
"@vue/compiler-sfc": "^3.0.5",
+ "@vue/eslint-config-prettier": "^6.0.0",
"@vue/eslint-config-typescript": "^7.0.0",
"autoprefixer": "^10.2.6",
"eslint": "^7.30.0",
+ "eslint-plugin-prettier": "^3.4.0",
"eslint-plugin-vue": "^7.13.0",
"mockjs": "^1.1.0",
+ "prettier": "^2.3.2",
"vite": "^2.4.0",
"vite-plugin-mock": "^2.9.1"
}
}
.eslintrc.js
module.exports = {
root: true,
env: {
browser: true,
es2021: true,
node: true,
},
extends: [
"plugin:vue/vue3-recommended",
"eslint:recommended",
"@vue/typescript/recommended",
+ "@vue/prettier",
+ "@vue/prettier/@typescript-eslint",
],
parserOptions: {
ecmaVersion: 2021,
},
rules: {
"no-unused-vars": "off",
"@typescript-eslint/no-unused-vars": "off",
+ "prettier/prettier": ["error", { endOfLine: "auto" }],
},
};
cnpm i jest@next babel-jest@next @types/jest vue-jest@next ts-jest@next @vue/test-utils@next --save-dev
{
"name": "zhufeng-vite2-prepare",
"version": "1.0.0",
"scripts": {
"dev": "vite",
"build": "vite build",
"serve": "vite preview",
"lint": "eslint --ext .ts,vue src/** --no-error-on-unmatched-pattern --quiet",
"lint:fix": "eslint --ext .ts,vue src/** --no-error-on-unmatched-pattern --fix"
},
"dependencies": {
"less": "^4.1.1",
"sass": "^1.35.2",
"vue": "^3.0.5"
},
"devDependencies": {
"@typescript-eslint/eslint-plugin": "^4.28.2",
"@typescript-eslint/parser": "^4.28.2",
"@vitejs/plugin-vue": "^1.2.4",
"@vue/compiler-sfc": "^3.0.5",
"@vue/eslint-config-prettier": "^6.0.0",
"@vue/eslint-config-typescript": "^7.0.0",
"autoprefixer": "^10.2.6",
"eslint": "^7.30.0",
"eslint-plugin-prettier": "^3.4.0",
"eslint-plugin-vue": "^7.13.0",
"mockjs": "^1.1.0",
"prettier": "^2.3.2",
"vite": "^2.4.0",
"vite-plugin-mock": "^2.9.1"
}
}
jest.config.js
module.exports = {
testEnvironment: "jsdom",
transform: {
"^.+\\.vue$": "vue-jest",
"^.+\\.jsx?$": "babel-jest",
"^.+\\.tsx?$": "ts-jest",
},
moduleNameMapper: {
"^@/(.*)$": "<rootDir>/src/$1",
},
testMatch: ["**/tests/**/*.spec.[jt]s"],
};
tests\test.ts
import { mount } from '@vue/test-utils'
const MessageComponent = {
template: '<p>{{ msg }}</p>',
props: ['msg']
}
test('displays message', () => {
const wrapper = mount(MessageComponent, {
props: {
msg: 'Hello world'
}
})
expect(wrapper.text()).toContain('Hello world')
})
tsconfig.json
{
"compilerOptions": {
"target": "esnext",
"module": "esnext",
"moduleResolution": "node",
"strict": true,
"jsx": "preserve",
"sourceMap": true,
"resolveJsonModule": true,
"esModuleInterop": true,
"lib": ["esnext", "dom"],
+ "types":["vite/client","jest"],
+ "baseUrl": "./",
+ "paths": {
+ "@": ["./src"]
+ }
},
+ "include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.vue","tests/**/*.spec.ts", "tests/test.ts"]
}
package.json
{
"scripts": {
"dev": "vite",
"build": "vite build",
"serve": "vite preview",
"lint": "eslint --ext .ts,vue src/** --no-error-on-unmatched-pattern --quiet",
"lint:fix": "eslint --ext .ts,vue src/** --no-error-on-unmatched-pattern --fix",
+ "test": "jest --passWithNoTests"
}
}
git commit
之前检查代码,保证所有提交到版本库中的代码都是符合规范的git push
之前执行单元测试,保证所有的提交的代码经过的单元测试git commit -m ""
中的描述信息git commit -m <type>[optional scope]: <description>
类型 | 描述 |
---|---|
build | 编译相关的修改,例如发布版本、对项目构建或者依赖的改动 |
chore | 其他修改, 比如改变构建流程、或者增加依赖库、工具等 |
ci | 持续集成修改 |
docs | 文档修改 |
feature | 新特性、新功能 |
fix | 修改bug |
perf | 优化相关,比如提升性能、体验 |
refactor | 代码重构 |
revert | 回滚到上一个版本 |
style | 代码格式修改 |
test | 测试用例修改 |
cnpm i husky lint-staged @commitlint/cli @commitlint/config-conventional --save-dev
prepare
脚本会在npm install
(不带参数)之后自动执行husky install
命令,该命令会创建.husky/
目录并指定该目录为git hooks
所在的目录npm set-script prepare "husky install"
npm run prepare
npx husky add .husky/pre-commit "lint-staged"
npx husky add .husky/commit-msg "npx --no-install commitlint --edit $1"
npx husky add .husky/pre-push "npm run test"
commitlint.config.js
module.exports = {
extends: ["@commitlint/config-conventional"],
rules: {
"type-enum": [
2,
"always",
[
"feature",
"update",
"fixbug",
"refactor",
"optimize",
"style",
"docs",
"chore",
],
],
"type-case": [0],
"type-empty": [0],
"scope-empty": [0],
"scope-case": [0],
"subject-full-stop": [0, "never"],
"subject-case": [0, "never"],
"header-max-length": [0, "always", 72],
},
};