共计 10035 个字符,预计需要花费 26 分钟才能阅读完成。
五一期间,花了 3 天工夫,边学 Vue3 和 Vite2,边重构本人的我的项目,终于都用 Vue3 + TypeScript + Vite2 + Vuex4 + Vue-Router4 + element-plus 重构完啦!
终于实现一项心心念念的 2021 年度指标了 ✌️
我的项目地址:
https://github.com/biaochenxuying/blog-vue-typescript
成果
效果图:
- pc 端
- 挪动端
残缺成果请看:
https://biaochenxuying.cn
性能
曾经实现性能
- [x] 登录
- [x] 注册
- [x] 文章列表
- [x] 文章归档
- [x] 标签
- [x] 对于
- [x] 点赞与评论
- [x] 留言
- [x] 历程
- [x] 文章详情(反对代码语法高亮)
- [x] 文章详情目录
- [x] 挪动端适配
- [x] github 受权登录
⬆️ 返回顶部
前端次要技术
所有技术都是以后最新的。
- vue:^3.0.5
- typescript : ^4.1.3
- element-plus: ^1.0.2-beta.41
- vue-router : ^4.0.6
- vite: ^2.2.3
- vuex: ^4.0.0
- axios: ^0.21.1
- highlight.js: ^10.7.2
- marked:^2.0.3
1. 初化化我的项目
用 vite-app 创立我的项目
yarn create vite-app <project-name> | |
# 或者 | |
npm init vite-app <project-name> |
而后依照提醒操作即可!
进入我的项目,装置依赖
cd <project-name> | |
yarn # 或 npm i |
运行我的项目
yarn dev
关上浏览器 http://localhost:3000 查看
2. 引入 TypeScript
在创立我的项目的时候能够 TypeScript 的,如果你抉择了 TypeScript,能够疏忽第 2 个步骤。
退出 ts 依赖
yarn add --dev typescript
在 我的项目根目录下创立 TypeScript 的配置文件 tsconfig.json
{ | |
"compilerOptions": { | |
// 容许从没有设置默认导出的模块中默认导入。这并不影响代码的输入,仅为了类型查看。"allowSyntheticDefaultImports": true, | |
// 解析非绝对模块名的基准目录 | |
"baseUrl": ".", | |
"esModuleInterop": true, | |
// 从 tslib 导入辅助工具函数(比方 __extends,__rest 等)"importHelpers": true, | |
// 指定生成哪个模块零碎代码 | |
"module": "esnext", | |
// 决定如何解决模块。"moduleResolution": "node", | |
// 启用所有严格类型查看选项。// 启用 --strict 相当于启用 --noImplicitAny, --noImplicitThis, --alwaysStrict,// --strictNullChecks 和 --strictFunctionTypes 和 --strictPropertyInitialization。"strict": true, | |
// 生成相应的 .map 文件。"sourceMap": true, | |
// 疏忽所有的申明文件(*.d.ts)的类型查看。"skipLibCheck": true, | |
// 指定 ECMAScript 指标版本 | |
"target": "esnext", | |
// 要蕴含的类型申明文件名列表 | |
"types": [ ], | |
"isolatedModules": true, | |
// 模块名到基于 baseUrl 的门路映射的列表。"paths": { | |
"@/*": ["src/*"] | |
}, | |
// 编译过程中须要引入的库文件的列表。"lib": [ | |
"ESNext", | |
"DOM", | |
"DOM.Iterable", | |
"ScriptHost" | |
] | |
}, | |
"include": [ | |
"src/**/*.ts", | |
"src/**/*.tsx", | |
"src/**/*.vue", | |
"tests/**/*.ts", | |
"tests/**/*.tsx" | |
], | |
"exclude": ["node_modules"] | |
} |
在 src 目录下新加 shim.d.ts 文件
/* eslint-disable */ | |
import type {DefineComponent} from 'vue' | |
declare module '*.vue' {const component: DefineComponent<{}, {}, any> | |
export default component | |
} |
把 main.js 批改成 main.ts
在根目录,关上 Index.html
<script type="module" src="/src/main.js"></script> | |
批改为:<script type="module" src="/src/main.ts"></script> |
3. 引入 eslint
装置 eslint prettier 依赖
@typescript-eslint/parser @typescr ipt-eslint/eslint-plugin
为 eslint 对 typescript 反对。
yarn add --dev eslint prettier eslint-config-prettier eslint-plugin-prettier eslint-plugin-vue @typescript-eslint/parser @typescr ipt-eslint/eslint-plugin
在根目录下建设 eslint 配置文件:.eslintrc.js
module.exports = { | |
parser: 'vue-eslint-parser', | |
parserOptions: { | |
parser: '@typescript-eslint/parser', | |
ecmaVersion: 2020, | |
sourceType: 'module', | |
ecmaFeatures: {jsx: true} | |
}, | |
extends: [ | |
'plugin:vue/vue3-recommended', | |
'plugin:@typescript-eslint/recommended', | |
'prettier/@typescript-eslint', | |
'plugin:prettier/recommended' | |
], | |
rules: { | |
'@typescript-eslint/ban-ts-ignore': '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', | |
'vue/custom-event-name-casing': 'off', | |
'no-use-before-define': 'off', | |
// 'no-use-before-define': [ | |
// 'error', | |
// { | |
// functions: false, | |
// classes: true, | |
// }, | |
// ], | |
'@typescript-eslint/no-use-before-define': 'off', | |
// '@typescript-eslint/no-use-before-define': [ | |
// 'error', | |
// { | |
// functions: false, | |
// classes: true, | |
// }, | |
// ], | |
'@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', | |
'@typescript-eslint/no-unused-vars': [ | |
'error', | |
{ | |
argsIgnorePattern: '^h$', | |
varsIgnorePattern: '^h$' | |
} | |
], | |
'no-unused-vars': [ | |
'error', | |
{ | |
argsIgnorePattern: '^h$', | |
varsIgnorePattern: '^h$' | |
} | |
], | |
'space-before-function-paren': 'off', | |
quotes: ['error', 'single'], | |
'comma-dangle': ['error', 'never'] | |
} | |
}; |
建设 prettier.config.js
module.exports = { | |
printWidth: 100, | |
tabWidth: 2, | |
useTabs: false, | |
semi: false, // 未尾逗号 | |
vueIndentScriptAndStyle: true, | |
singleQuote: true, // 单引号 | |
quoteProps: 'as-needed', | |
bracketSpacing: true, | |
trailingComma: 'none', // 未尾分号 | |
jsxBracketSameLine: false, | |
jsxSingleQuote: false, | |
arrowParens: 'always', | |
insertPragma: false, | |
requirePragma: false, | |
proseWrap: 'never', | |
htmlWhitespaceSensitivity: 'strict', | |
endOfLine: 'lf' | |
} |
4. vue-router、vuex
npm install vue-router@4 vuex
4.1 vuex
在根目录下创立 store/index.ts
import {InjectionKey} from 'vue' | |
import {createStore, Store} from 'vuex' | |
export interface State {count: number} | |
export const key: InjectionKey<Store<State>> = Symbol() | |
export const store = createStore<State>({state() { | |
return {count: 0} | |
}, | |
mutations: {increment(state) {state.count++} | |
} | |
}) |
main.ts 批改
import {createApp} from 'vue' | |
import {store, key} from './store' | |
import App from './App' | |
import './index.css' | |
const app = createApp(App) | |
app.use(store, key) | |
app.mount('#app') |
components/HelloWord.vue 批改
<template> | |
<h1>{{msg}}</h1> | |
<button @click="inCrement"> count is: </button> | |
<p>{{count}}</p> | |
</template> | |
<script> | |
import {defineComponent, computed} from 'vue' | |
import {useStore} from 'vuex' | |
import {key} from '../store' | |
export default defineComponent({ | |
name: 'HelloWorld', | |
props: { | |
msg: { | |
type: String, | |
default: '' | |
} | |
}, | |
setup() {const store = useStore(key) | |
const count = computed(() => store.state.count) | |
return { | |
count, | |
inCrement: () => store.commit('increment') | |
} | |
} | |
}) | |
</script> |
4.2 vue-router
在 src 目录下建设 router/index.ts,内容如下:
import {createRouter, createWebHistory, RouteRecordRaw} from "vue-router"; | |
import HelloWorld from "../components/HelloWorld.vue"; | |
const routes: Array<RouteRecordRaw> = [ | |
{ | |
path: "/", | |
name: "HelloWorld", | |
component: HelloWorld, | |
}, | |
{ | |
path: "/about", | |
name: "About", | |
// route level code-splitting | |
// this generates a separate chunk (about.[hash].js) for this route | |
// which is lazy-loaded when the route is visited. | |
component: () => | |
import(/* webpackChunkName: "About" */ "../components/About.vue") | |
} | |
]; | |
const router = createRouter({history: createWebHistory(process.env.BASE_URL), | |
routes, | |
}); | |
export default router; |
再新建一个 components/About.vue 文件,内容如下:
<template> | |
<img | |
alt="Vue logo" | |
src="../assets/logo.png" | |
/> | |
<h1>{{msg}}</h1> | |
</template> | |
<script lang="ts"> | |
import {defineComponent} from 'vue' | |
export default defineComponent({ | |
name: 'About', | |
data() { | |
return {msg: 'Hello Vue 3.0 + Vite!'} | |
}, | |
setup() {} | |
}) | |
</script> |
再批改 main.ts
import {createApp} from 'vue' | |
import {store, key} from './store' | |
import router from "./router"; | |
import App from './App' | |
import './index.css' | |
const app = createApp(App) | |
app.use(store, key) | |
app.use(router) | |
app.mount('#app') |
再拜访 http://localhost:3000/
和 http://localhost:3000/about 即可
5. 退出 Element Plus
5.1 装置 element-plus
全局装置
npm install element-plus --save
5.2 引入 Element Plus
你能够引入整个 Element Plus,或是依据须要仅引入局部组件。咱们先介绍如何引入残缺的 Element。
残缺引入
在 main.js 中写入以下内容:
import {createApp} from 'vue' | |
import ElementPlus from 'element-plus'; | |
import router from "./router"; | |
import 'element-plus/lib/theme-chalk/index.css'; | |
import App from './App.vue'; | |
import './index.css' | |
const app = createApp(App) | |
app.use(ElementPlus) | |
app.use(router) | |
app.mount('#app') |
以上代码便实现了 Element Plus 的引入。须要留神的是,款式文件须要独自引入。
按需引入
借助 babel-plugin-component,咱们能够只引入须要的组件,以达到减小我的项目体积的目标。
首先,装置 babel-plugin-component:
npm install babel-plugin-component -D
而后,将 .babelrc 批改为:
{ | |
"plugins": [ | |
[ | |
"component", | |
{ | |
"libraryName": "element-plus", | |
"styleLibraryName": "theme-chalk" | |
} | |
] | |
] | |
} |
接下来,如果你只心愿引入局部组件,比方 Button 和 Select,那么须要在 main.js 中写入以下内容:
import {createApp} from 'vue' | |
import {store, key} from './store'; | |
import router from "./router"; | |
import {ElButton, ElSelect} from 'element-plus'; | |
import App from './App.vue'; | |
import './index.css' | |
const app = createApp(App) | |
app.component(ElButton.name, ElButton); | |
app.component(ElSelect.name, ElSelect); | |
/* or | |
* app.use(ElButton) | |
* app.use(ElSelect) | |
*/ | |
app.use(store, key) | |
app.use(router) | |
app.mount('#app') | |
app.mount('#app') |
更具体的装置办法请看 疾速上手。
5.3 全局配置
在引入 Element Plus 时,能够传入一个全局配置对象。
该对象目前反对 size
与 zIndex
字段。size
用于扭转组件的默认尺寸,zIndex
设置弹框的初始 z-index(默认值:2000)。依照引入 Element Plus 的形式,具体操作如下:
残缺引入 Element:
import {createApp} from 'vue' | |
import ElementPlus from 'element-plus'; | |
import App from './App.vue'; | |
const app = createApp(App) | |
app.use(ElementPlus, { size: 'small', zIndex: 3000}); |
按需引入 Element:
import {createApp} from 'vue' | |
import {ElButton} from 'element-plus'; | |
import App from './App.vue'; | |
const app = createApp(App) | |
app.config.globalProperties.$ELEMENT = option | |
app.use(ElButton); |
依照以上设置,我的项目中所有领有 size
属性的组件的默认尺寸均为 ‘small’,弹框的初始 z-index 为 3000。
5.4 配置 vite.config.ts
其中 proxy 和 alias 是和 vue-cli 区别比拟大的中央。
import {defineConfig} from 'vite' | |
import vue from '@vitejs/plugin-vue' | |
import styleImport from 'vite-plugin-style-import' | |
import path from 'path' | |
// https://vitejs.dev/config/ | |
export default defineConfig({ | |
plugins: [vue(), | |
styleImport({ | |
libs: [ | |
{ | |
libraryName: 'element-plus', | |
esModule: true, | |
ensureStyleFile: true, | |
resolveStyle: (name) => {return `element-plus/lib/theme-chalk/${name}.css`; | |
}, | |
resolveComponent: (name) => {return `element-plus/lib/${name}`; | |
}, | |
} | |
] | |
}) | |
], | |
/** | |
* 在生产中服务时的根本公共门路。* @default '/' | |
*/ | |
base: './', | |
/** | |
* 与“根”相干的目录,构建输入将放在其中。如果目录存在,它将在构建之前被删除。* @default 'dist' | |
*/ | |
// outDir: 'dist', | |
server: { | |
// hostname: '0.0.0.0', | |
host: "localhost", | |
port: 3001, | |
// // 是否主动在浏览器关上 | |
// open: true, | |
// // 是否开启 https | |
// https: false, | |
// // 服务端渲染 | |
// ssr: false, | |
proxy: { | |
'/api': { | |
target: 'http://localhost:3333/', | |
changeOrigin: true, | |
ws: true, | |
rewrite: (pathStr) => pathStr.replace('/api', '') | |
}, | |
}, | |
}, | |
resolve: { | |
// 导入文件夹别名 | |
alias: {'@': path.resolve(__dirname, './src'), | |
views: path.resolve(__dirname, './src/views'), | |
components: path.resolve(__dirname, './src/components'), | |
utils: path.resolve(__dirname, './src/utils'), | |
less: path.resolve(__dirname, "./src/less"), | |
assets: path.resolve(__dirname, "./src/assets"), | |
com: path.resolve(__dirname, "./src/components"), | |
store: path.resolve(__dirname, "./src/store"), | |
mixins: path.resolve(__dirname, "./src/mixins") | |
}, | |
} | |
}) |
踩到坑
在 npm run dev
打包时不报错,然而在 npm run build
时却报错了,build 的时候会把 node_modules
外面的文件也编译,所以挺多 element-plus 的类型文件报错了。
把 tsconfig.json
外面的 include
和 exclude
批改一下就不会了,配置如下
{ | |
"compilerOptions": { | |
"target": "esnext", | |
"module": "esnext", | |
"moduleResolution": "node", | |
"strict": true, | |
"jsx": "preserve", | |
"sourceMap": true, | |
// 疏忽 this 的类型查看, Raise error on this expressions with an implied any type. | |
"noImplicitThis": false, | |
"resolveJsonModule": true, | |
"esModuleInterop": true, | |
"lib": ["esnext", "dom"], | |
"types": ["vite/client"] | |
}, | |
"include": ["/src/**/*.ts", "/src/**/*.d.ts", "/src/**/*.tsx", "/src/**/*.vue"], | |
// ts 排除的文件 | |
"exclude": ["node_modules"] | |
} |
Vue3 + vite2 打包进去的文件和原来 vue2 版的差异也挺大的,由原来 2.5M 间接变成了 1.8M,amazing!
最初
我的项目代码大多都是 2 年前的,还有很多能够优化的中央,这次重构的过程没对原来的款式和代码做什么改变,没那么多工夫,加上我懒 😂
这次就降级了次要框架与相应的 ui 库,过了一遍 Vue3 中的 API,发现很多 Vue3 中新的 API 都用不上,次要是要纯熟一下 Vue3 和 Vite2 我的项目搭建,这假期也算有所播种。
具体我的项目源码请看:
https://github.com/biaochenxuying/blog-vue-typescript
至此,一个基于 Vue3 全家桶 + Vite2 + TypeScript + Element Plus 的开发环境曾经搭建结束,当初就能够编写代码了,各个组件的应用办法请参阅它们各自的文档。
不得不说 Vue3 + Element Plus + Vite + TypeScript 是真的香!
举荐一个 Vue3 相干的材料汇总:Vue3 的学习教程汇总、源码解释我的项目、反对的 UI 组件库、优质实战我的项目,置信你会挖到矿哦!
参考文章:vue3 + vite + typescript + eslint + jest 我的项目配置实际
举荐浏览
- TypeScript 中晋升幸福感的 10 个高级技巧
欢送关注公众号:“全栈修炼 ”,回复“ 电子书”即能够取得上面 300 本技术精髓书籍哦,猫哥 wx:CB834301747。