使用Vite初始化Vue3.x+TS專案

語言: CN / TW / HK

使用Vite初始化專案

為什麼要使用Vite * Vite是一個面向現代瀏覽器的一個更輕、更快的web開發應用 * 基於ECMAScript標準原生模組系統(ESM)實現 Vite專案依賴項 * Vite只有當檔案請求時才會去編譯相應的模組 * ...

這裡使用npm初始化專案 bash npm init [email protected] 然後根據提示選擇模板、eslint標準等

配置eslint

``` bash npm install eslint --save-dev

設定eslint規則並生產配置檔案

./node_modules/.bin/eslint --init 預設生成的vue的配置檔案是Vue 2.x版本的規則,需要手動修改為Vue3的規則 js module.exports = { ... extends: [ 'plugin:vue/vue3-strongly-recommended', 'standard' ], } 如果出現eslint報錯,如`defineProps`等報錯,需要在eslint配置檔案中加上 js { globals: { defineProps: 'readonly', defineEmits: 'readonly', defineExpose: 'readonly', withDefaults: 'readonly'
} } ```

vscode編輯器配置

  • 安裝Volar這個外掛
  • 如果之前安裝過Vue2的Vetur這個外掛,需要把這個外掛禁用掉,然後重啟編輯器
  • 安裝eslint,設定eslint為預設格式化程式碼的方式

配置git commit hook

安裝lint-staged bash npx [email protected] lint-staged 配置lint-staged json { "lint-staged": { "*.{js,jsx,ts,tsx,vue}": [ "npm run lint", "git add" ] } }

程式碼提交規範

使用commitlint ``` bash

Install commitlint cli and conventional config

npm install --save-dev @commitlint/{config-conventional,cli}

For Windows:

npm install --save-dev @commitlint/config-conventional @commitlint/cli

生成commitlint.config.js

echo "module.exports = {extends: ['@commitlint/config-conventional']}" > commitlint.config.js 使用`commit-msg`鉤子 npx husky add .husky/commit-msg 'npx --no-install commitlint --edit "$1"' ``` 生成change log

如果提交是出現下面報錯,需要將commitlint.config.js的編碼設定為utf-8格式 bash commitlint.config.js:1 �� SyntaxError: Invalid or unexpected token

相關資料參考 http://www.ruanyifeng.com/blog/2016/01/commit_message_change_log.html

Vue3中的TS支援

文件地址 https://v3.cn.vuejs.org/guide/typescript-support.html

Vue3中的script setup

script setup可以是我們的開發程式碼變得更好,有了這個特性後,開發Vue專案變得更簡單了,沒有之前那麼多大樣板程式碼

文件地址 * https://v3.cn.vuejs.org/api/sfc-script-setup.html * https://github.com/vuejs/rfcs/blob/master/active-rfcs/0040-script-setup.md

props和emmit宣告

props 和 emits 都可以使用傳遞字面量型別的純型別語法做為引數給 defineProps 和 defineEmits 來宣告:

``` js const props = defineProps<{ foo: string bar?: number }>()

const emit = defineEmits<{ (e: 'change', id: number): void (e: 'update', value: string): void }>() 宣告props的預設值 js interface Props { msg?: string labels?: string[] }

const props = withDefaults(defineProps(), { msg: 'hello', labels: () => ['one', 'two'] }) ```

配置jsx

為什麼會用到jsx

Vue 推薦在絕大多數情況下使用模板來建立你的 HTML。然而在一些場景中,你真的需要 JavaScript 的完全程式設計的能力。這時你可以用渲染函式,它比模板更接近編譯器。

當我們建立下面的元件後 ``` js const { createApp, h } = Vue

const app = createApp({})

app.component('anchored-heading', { render() { return h( 'h' + this.level, // 標籤名 {}, // prop 或 attribute this.$slots.default() // 包含其子節點的陣列 ) }, props: { level: { type: Number, required: true } } }) 但我們使用渲染函式時,可能會很痛苦 js h( 'anchored-heading', { level: 1 }, { default: () => [h('span', 'Hello'), ' world!'] } ) 而模板使用會非常簡單 vue Hello world! ``` 這就是為什麼我們會使用jsx,還有就是React的開發者可以更喜歡使用jsx

Vue3提供了一個babel外掛,用於在 Vue3 中使用 JSX 語法 ``` js import AnchoredHeading from './AnchoredHeading.vue'

const app = createApp({ render() { return ( Hello world! ) } })

app.mount('#demo') ```

配置vite中的jsx

Vue 使用者應使用官方提供的 @vitejs/plugin-vue-jsx 外掛,它提供了 Vue 3 特性的支援,包括 HMR,全域性元件解析,指令和插槽。 ``` js import vueJsx from '@vitejs/plugin-vue-jsx'

export default { plugins: [ vueJsx({ // options are passed on to @vue/babel-plugin-jsx }) ] } ``` 相關文件地址 * Vue3中的jsx https://v3.cn.vuejs.org/guide/render-function.html#jsx * babel-plugin-jsx中文文件 https://github.com/vuejs/jsx-next/blob/dev/packages/babel-plugin-jsx/README-zh_CN.md * vite中配置jsx https://cn.vitejs.dev/guide/features.html#jsx

Vue Router

安裝Vue Router bash npm install [email protected] router-linkrouter-view和在使用Vue2.x時是一樣的 ``` ts import { createRouter, createWebHashHistory, RouteRecordRaw } from 'vue-router'

const routes:RouteRecordRaw[] = [ { path: '/', name: 'Home', // 使用ts時,這裡的檔名和字尾都不能省略掉,因為如果省略,ts沒辦法識別它的型別 component: () => import('../views/Home/index.vue') }, { path: '/login', name: 'Login', component: () => import('../views/Login/Login.vue') } ]

const router = createRouter({ history: createWebHashHistory(), routes }) export default router

在入口檔案中使用vue-router js import { createApp } from 'vue' import App from './App.vue' import router from './router'

createApp(App) .use(router) .mount('#app') ```

Vuex

安裝Vuex bash npm install [email protected] --save

使用

``` js // store/index.js import { createStore } from 'vuex'

export interface State { count: number }

const store = createStore({ state () { return { count: 0 } }, mutations: { increment (state) { state.count++ state.a = 1 } } }) export default store 在入口檔案引入 diff import { createApp } from 'vue' import App from './App.vue' import router from './router' + import store from './store'

createApp(App) + .use(store) .use(router) .mount('#app') 在頁面中使用 vue

``` ts無法推斷頁面中$store.state.count和store.state.count,我們可以參考vuex中ts支援文件

在專案中建立vuex.d.ts檔案 ``` ts // eslint-disable-next-line no-unused-vars import { ComponentCustomProperties } from 'vue' import { Store } from 'vuex'

declare module '@vue/runtime-core' { // 宣告自己的 store state interface State { count: number }

// 為 this.$store 提供型別宣告 // eslint-disable-next-line no-unused-vars interface ComponentCustomProperties { $store: Store } }

```

在使用useStore的時候,ts無法推斷 store.state

``` ts // store/index.js import { InjectionKey } from 'vue' import { createStore, Store, useStore as baseUseStore } from 'vuex'

export interface State { count: number }

export const key: InjectionKey> = Symbol('store')

export const store = createStore({ state () { return { count: 0 } }, mutations: { increment (state) { state.count++ } } })

export function useStore () { return baseUseStore(key) } 入口檔案 ts import { createApp } from 'vue' import App from './App.vue' import router from './router' import { store, key } from './store'

createApp(App) .use(store, key) .use(router) .mount('#app') 在頁面中使用 vue

... ```

簡化 useStore 用法

``` ts import { InjectionKey } from 'vue' import { createStore, Store, useStore as baseUseStore } from 'vuex'

export interface State { count: number }

export const key: InjectionKey> = Symbol('store')

export const store = createStore({ state () { return { count: 0 } }, mutations: { increment (state) { state.count++ } } })

export function useStore () { return baseUseStore(key) } 在vue元件中使用 vue

... ```

處理檔案路徑

配置vite alias ``` ts import { defineConfig } from 'vite' import vue from '@vitejs/plugin-vue' import eslintPlugin from 'vite-plugin-eslint' import vueJsx from '@vitejs/plugin-vue-jsx' import path from 'path'

export default defineConfig({ resolve: { alias: { '@': path.join(__dirname, 'src') } }, plugins: [ vue(), eslintPlugin(), vueJsx({ // options are passed on to @vue/babel-plugin-jsx })] }) ``` 配置後在專案中程式碼執行沒問題,在ts會報錯,需要在ts配置檔案中配置下路徑。相關文件

json { "compilerOptions": { ... "baseUrl": "./", "paths": { "@/*": [ "src/*" ] } }, ... } 配置路徑別名後,不僅可以在js中可以使用,在html、css中也可以使用

css處理

Vite中處理css可以參考Vite Css 文件

PostCSS

如果專案包含有效的 PostCSS 配置 (任何受 postcss-load-config 支援的格式,例如 postcss.config.js),它將會自動應用於所有已匯入的 CSS。

CSS Modules

任何以 .module.css 為字尾名的 CSS 檔案都被認為是一個 CSS modules 檔案。匯入這樣的檔案會返回一個相應的模組物件:

CSS前處理器

Vite中使用CSS前處理器無須配置,只需要安裝前處理器依賴即可 npm i sass -D npm i stylus -D npm i less -D

Vite 為 Sass 和 Less 改進了 @import 解析,以保證 Vite 別名也能被使用。另外,url() 中的相對路徑引用的,與根檔案不同目錄中的 Sass/Less 檔案會自動變基以保證正確性。

由於 Stylus API 限制,@import 別名和 URL 變基不支援 Stylus。

跨域處理

在開發過程中,跨域的解決方案主要有兩種 * 服務端解決(cors) * 配置代理 * 這裡我們可以使用vite-server.proxy * 其他方案如jsonp等使用條件有限,這裡不考慮使用

在vite專案中,我們可以使用vite-server.proxy,可以參考文件

Vite中的快取

在我們開發的過程中可能會遇到一些問題,如明明修改了檔案,構建完成的結果報的錯誤還是上一次的內容,這時候我們可以手動刪除node_modules/.vite檔案,然後重新構建

Vite 會將預構建的依賴快取到 node_modules/.vite。它根據幾個源來決定是否需要重新執行預構建步驟: * package.json 中的 dependencies 列表 * 包管理器的 lockfile,例如 package-lock.json, yarn.lock,或者 pnpm-lock.yaml * 可能在 vite.config.js 相關欄位中配置過的

如果出於某些原因,你想要強制 Vite 重新構建依賴,你可以用 --force 命令列選項啟動開發伺服器,或者手動刪除 node_modules/.vite 目錄。

相關文件參考 https://cn.vitejs.dev/guide/dep-pre-bundling.html#caching