Vite + Vue3.0

1. 初化化项目

安装vite

npm init @vitejs/app
or
yarn create @vitejs/app
注意node版本要>=12.0.0
安装好之后即可启动
npm run dev

2. 引入TypeScript

npm install --dev typescript
yarn add --dev typescript

在 项目根目录下创建 TypeScript 的配置文件 tsconfig.json
{
  "compilerOptions": {
      "target": "esnext", // 指定ECMAScript目标版本
      "module": "esnext", // 指定生成哪个模块系统代码
      "jsx": "preserve",
      "strict": true,  // 启用所有严格类型检查选项。
      "importHelpers": true, // 从 tslib 导入辅助工具函数(比如 __extends, __rest等)
      "moduleResolution": "node", // 决定如何处理模块。
      "experimentalDecorators": true,
      "esModuleInterop": true,  
      "allowSyntheticDefaultImports": true,  // 允许从没有设置默认导出的模块中默认导入。这并不影响代码的输出,仅为了类型检查。
      "sourceMap": true, // 生成相应的 .map文件
      "baseUrl": ".", // 解析非相对模块名的基准目录
      "paths": {
          "/@/*": [
              "src/*"
          ]
      }
  },
  "include": [
      "src/**/*.ts",
      "src/**/*.tsx",
      "src/**/*.vue",
  ],
  "exclude": [
      "node_modules",
      "dist",
      "**/*.js"
  ]
}

在src目录下新建shims-vue.d.ts

/* eslint-disable */
import type { DefineComponent } from 'vue'

declare module '*.vue' {
  const component: DefineComponent<{}, {}, any>
  export default component
}
// source.d.ts
declare module "*.png" {
  const src: string;
  export default src;
}
// vue.d.ts
import { Store } from "vuex";

declare module "@vue/runtime-core" {
  export interface ComponentCustomProperties {
    $store: Store<any>;
  }
}

vite.config.js

import { defineConfig } from 'vite';
import path from 'path';
import vue from '@vitejs/plugin-vue';
import vueJsx from '@vitejs/plugin-vue-jsx'
import { buildConfig } from './build/config/buildConfig';
export default defineConfig({
  server: {
    port: 7874,
    proxy: {
      // '/lsbdb': 'http://10.192.195.96:8087',
    },
    hmr: {
      overlay: true,
    },
    open: true,
  },
  ...buildConfig,
  resolve: {
    alias: {
      '/@': path.resolve(__dirname, '.', 'src'),
    },
  },
  optimizeDeps: {
    include: [],
  },
  plugins: [vue(), vueJsx()],
})
const buildConfig = {
  //在生产中使用时的基本公共路径。请注意,路径应以/开头和结尾
  base: '/',
  //默认值为Vite特殊值'modules',另一个特殊的值是'esnext'-仅执行最少的跨语言转换(用于最小化兼容性),并假定支持本机动态导入。
  target: 'modules',
  //是否自动注入动态导入的polyfill。
  polyfillDynamicImport: true,
  //指定输出目录
  outDir: 'dist',
  //指定目录以将生成的动态自由嵌套在下
  assetsDir: 'assets',
  //小于此阈值的导入或引用资产将作为base64 URL内联,以避免额外的http请求。设置为0完全禁用内联。
  assetsInlineLimit: 4096,
  //启用/禁用CSS代码拆分。启用后,在异步块中导入的CSS将内联到异步块本身中,并在加载块时插入。如果禁用,则整个项目中的所有CSS都将提取到一个CSS文件中。
  cssCodeSplit: true,
  //Generate production source maps.生成生产源图。
  sourcemap: false,
  //设置为时true,构建还将生成一个manifest.json文件,其中包含未哈希静态资源文件名到其哈希版本的映射,然后服务器框架可以使用该文件来呈现正确的静态资源链接。
  manifest: false,
};
export { buildConfig };

引入eslint

安装eslint prettier依赖 包含对TS的支持

@typescript-eslint/parser @typescript-eslint/eslint-plugin

yarn add --dev eslint prettier eslint-config-prettier eslint-plugin-prettier eslint-plugin-vue @typescript-eslint/parser @typescript-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: {
    'vue/no-multiple-template-root': 'off',
    '@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-setting-before-define': [
    //   'error',
    //   {
    //     functions: false,
    //     classes: true,
    //   },
    // ],
    '@typescript-eslint/no-use-before-define': 'off',
    // '@typescript-eslint/no-setting-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',
  },
};
// cnpm i --dev prettier eslint-config-prettier eslint-plugin-prettier
// prettier.config.js
module.exports = {
  printWidth: 100,
  tabWidth: 2,
  useTabs: false,
  semi: true, // 未尾逗号
  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'
}

vue-router vuex

cnpm i  vue-router@next vuex@next
// yarn add vue-router@next vuex@next
// vuex   在src目录下创建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.vue'

const app = createApp(App)

app.use(store, key)

app.mount('#app')

componentts/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>

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",
        component: () =>
            import("/@/components/About.vue")
    }
];

const router = createRouter({
    history: createWebHistory(),
    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')

安装element-plus

全局安装 npm i element-plus –save

// 完整引入
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')
//***样式文件需要单独引入
//按需引入 babel-plugin-component
npm i babel-plugin-component -D
//修改根目录下.babelrc文件
{
  "plugins": [
    [
      "component",
      {
        "libraryName": "element-plus",
        "styleLibraryName": "theme-chalk"
      }
    ]
  ]
}

引入部分组件

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')

全局配置,引入Element Plus时,可以传入一个全局配置对象

该对象目前支持 size 与 zIndex 字段。size 用于改变组件的默认尺寸,zIndex 设置弹框的初始 z-index(默认值:2000)。按照引入 Element Plus 的方式,具体操作如下:

// 完整引入
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 });
// 按需引入
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);