Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Vue3 全家桶 + Element Plus + Vite + TypeScript + Eslint 项目配置最佳实践 #81

Open
biaochenxuying opened this issue Feb 1, 2021 · 0 comments
Assignees
Labels
vue.js vue 相关知识点

Comments

@biaochenxuying
Copy link
Owner

biaochenxuying commented Feb 1, 2021

尤大的 Vue3.0 已经发布有一阵子了,已经很成熟了。

而且 Element Plus + Vite 也出了一段时间了,是时候该上手体验分享一波了。

主要是要熟练一下 Vue3,好准备用 Vue3 重构一下自己的网站项目: blog-vue-typescript ,计划是过年期间会着手重构这个项目,年后会上线。

1. 初化化项目

全局安装 vite-app

npm i -g 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

加入 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

yarn add vue-router@next vuex@next

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。

最后

至此,一个基于 Vue3 全家桶 + Vite + TypeScript + Eslint + Element Plus 的开发环境已经搭建完毕,现在就可以编写代码了。

各个组件的使用方法请参阅它们各自的文档。

不得不说 Vue3 + Element Plus + Vite + TypeScript 是真的香!

Vue3 中文文档,国内 CDN 加速版:

https://vue3js.cn/docs/zh/

Element Plus 官网:

https://element-plus.org/#/zh-CN


作为 2021 第 2 篇原创技术文章,质量应该还可以吧,1 月的 KPI 完成,哈哈哈 😅

参考文章:vue3 + vite + typescript + eslint + jest 项目配置实践

@biaochenxuying biaochenxuying added the vue.js vue 相关知识点 label Feb 1, 2021
@biaochenxuying biaochenxuying self-assigned this Feb 1, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
vue.js vue 相关知识点
Projects
None yet
Development

No branches or pull requests

1 participant