五一期间,花了 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 = optionapp.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 外面的 includeexclude 批改一下就不会了,配置如下

{  "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 。