Vue3.0+typescript+Vite+Pinia+Element-plus搭建vue3框架!

来源:https://www.cnblogs.com/jqCode/p/18228885
-Advertisement-
Play Games

使用 Vite 快速搭建腳手架 命令行選項直接指定項目名稱和想要使用的模板,Vite + Vue 項目,運行(推薦使用yarn) # npm 6.x npm init vite@latest my-vue-app --template vue # npm 7+, 需要額外的雙橫線: npm init ...


使用 Vite 快速搭建腳手架

命令行選項直接指定項目名稱和想要使用的模板,Vite + Vue 項目,運行(推薦使用yarn)

# npm 6.x
npm init vite@latest my-vue-app --template vue

# npm 7+, 需要額外的雙橫線:
npm init vite@latest my-vue-app -- --template vue

# yarn
yarn create vite my-vue-app --template vue

# pnpm
pnpm create vite my-vue-app -- --template vue

這裡我們想要直接生成一個Vue3+Vite2+ts的項目模板,因此我們執行的命令是: yarn create vite my-vue-app --template vue-ts,這樣我們就不需要你單獨的再去安裝配置ts了。

cd 到項目文件夾,安裝node_modules依賴,運行項目

# cd進入my-vue-app項目文件夾
cd my-vue-app
# 安裝依賴
yarn
# 運行項目
yarn dev

至此,一個最純凈的vue3.0+vite2+typescript項目就完成了。在瀏覽地址欄中輸入http://localhost:3000/,就看到瞭如下的啟動頁,然後就可以安裝所需的插件了。

配置文件路徑引用別名 alias

修改vite.config.ts中的reslove的配置

import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import path from 'path'

// https://vitejs.dev/config/
export default defineConfig({
  plugins: [vue()],
  resolve: {
    alias: {
      '@': path.resolve(__dirname, 'src'),
    },
  },
})

在修改tsconfig.json文件的配置

{
  "compilerOptions": {
    "target": "esnext",
    "module": "esnext",
    "moduleResolution": "node",
    "strict": true,
    "jsx": "preserve",
    "sourceMap": true,
    "resolveJsonModule": true,
    "esModuleInterop": true,
    "lib": ["esnext", "dom"],
    "baseUrl": ".",
    "paths": {
      "@/*":["src/*"]
    }
  },
  "include": [
    "src/**/*.ts", 
    "src/**/*.d.ts", 
    "src/**/*.tsx", 
    "src/**/*.vue"
  ]
}

配置路由

安裝

# npm
npm install vue-router@4

# yarn
yarn add vue-router@4

在src下新建router文件夾,用來集中管理路由,在router文件夾下新建 index.ts文件。

import { createRouter, createWebHistory, RouteRecordRaw } from 'vue-router'

const routes: RouteRecordRaw[] = [
  {
    path: '/',
    name: 'Login',
    // 註意這裡要帶上文件尾碼.vue
    component: () => import('@/pages/login/Login.vue'), 
    meta: {
      title: '登錄',
    },
  },
]

const router = createRouter({
  history: createWebHistory(),
  routes,
  strict: true,
  // 期望滾動到哪個的位置
  scrollBehavior(to, from, savedPosition) {
    return new Promise(resolve => {
      if (savedPosition) {
        return savedPosition;
      } else {
        if (from.meta.saveSrollTop) {
          const top: number =
            document.documentElement.scrollTop || document.body.scrollTop;
          resolve({ left: 0, top });
        }
      }
    });
  }
})

export function setupRouter(app: App) {
  app.use(router);
}

export default router

修改入口文件 mian.ts

import { createApp } from "vue";
import App from "./App.vue";
import router, { setupRouter } from './router';

const app = createApp(App);
// 掛在路由
setupRouter(app);
// 路由準備就緒後掛載APP實例
await router.isReady();

app.mount('#app', true);

更多的路由配置可以移步vue-router(https://next.router.vuejs.org/zh/introduction.html)。 vue-router4.x支持typescript,路由的類型為RouteRecordRaw。meta欄位可以讓我們根據不同的業務需求擴展 RouteMeta 介面來輸入它的多樣性。以下的meta中的配置僅供參考:

// typings.d.ts or router.ts
import 'vue-router'

declare module 'vue-router' {
  interface RouteMeta {
    // 頁面標題,通常必選。
    title: string; 
    // 菜單圖標
    icon?: string; 
    // 配置菜單的許可權
    permission: string[];
    // 是否開啟頁面緩存
    keepAlive?: boolean;
    // 二級頁面我們並不想在菜單中顯示
    hidden?: boolean; 
    // 菜單排序
    order?: number; 
    // 嵌套外鏈
    frameUrl?: string; 
  }
}

配置 css 預處理器 scss

安裝

yarn add sass-loader --dev
yarn add dart-sass --dev
yarn add sass --dev

配置全局 scss 樣式文件 在 src文件夾下新增 styles 文件夾,用於存放全局樣式文件,新建一個 varibles.scss文件,用於統一管理聲明的顏色變數:

$white: #FFFFFF;
$primary-color: #1890ff;
$success-color: #67C23A;
$warning-color: #E6A23C;
$danger-color: #F56C6C;
$info-color: #909399;

組件中使用在vite.config.ts中將這個樣式文件全局註入到項目即可全局使用,不需要在任何組件中再次引入這個文件或者顏色變數。

css: {
  preprocessorOptions: {
    scss: {
      modifyVars: {},
      javascriptEnabled: true,
      // 註意這裡的引入的書寫
      additionalData: '@import "@/style/varibles.scss";'
    }
  }
},

在組件中使用

.div {
  color: $primary-color;
  background-color: $success-color;
}

統一請求封裝

在src文件夾下,新建http文件夾,在http文件夾下新增index.ts,config.ts,core.ts,types.d.ts,utils.ts

core.ts

import Axios, { AxiosRequestConfig, CancelTokenStatic, AxiosInstance } from "axios";
import NProgress from 'nprogress'
import { genConfig } from "./config";
import { transformConfigByMethod } from "./utils";
import {
  cancelTokenType,
  RequestMethods,
  HttpRequestConfig,
  HttpResoponse,
  HttpError
} from "./types.d";

class Http {
  constructor() {
    this.httpInterceptorsRequest();
    this.httpInterceptorsResponse();
  }
  // 初始化配置對象
  private static initConfig: HttpRequestConfig = {};

  // 保存當前Axios實例對象
  private static axiosInstance: AxiosInstance = Axios.create(genConfig());

  // 保存 Http實例
  private static HttpInstance: Http;

  // axios取消對象
  private CancelToken: CancelTokenStatic = Axios.CancelToken;

  // 取消的憑證數組
  private sourceTokenList: Array<cancelTokenType> = [];

  // 記錄當前這一次cancelToken的key
  private currentCancelTokenKey = "";

  public get cancelTokenList(): Array<cancelTokenType> {
    return this.sourceTokenList;
  }

  // eslint-disable-next-line class-methods-use-this
  public set cancelTokenList(value) {
    throw new Error("cancelTokenList不允許賦值");
  }

  /**
   * @description 私有構造不允許實例化
   * @returns void 0
   */
  // constructor() {}

  /**
   * @description 生成唯一取消key
   * @param config axios配置
   * @returns string
   */
  // eslint-disable-next-line class-methods-use-this
  private static genUniqueKey(config: HttpRequestConfig): string {
    return `${config.url}--${JSON.stringify(config.data)}`;
  }

  /**
   * @description 取消重覆請求
   * @returns void 0
   */
  private cancelRepeatRequest(): void {
    const temp: { [key: string]: boolean } = {};

    this.sourceTokenList = this.sourceTokenList.reduce<Array<cancelTokenType>>(
      (res: Array<cancelTokenType>, cancelToken: cancelTokenType) => {
        const { cancelKey, cancelExecutor } = cancelToken;
        if (!temp[cancelKey]) {
          temp[cancelKey] = true;
          res.push(cancelToken);
        } else {
          cancelExecutor();
        }
        return res;
      },
      []
    );
  }

  /**
   * @description 刪除指定的CancelToken
   * @returns void 0
   */
  private deleteCancelTokenByCancelKey(cancelKey: string): void {
    this.sourceTokenList =
      this.sourceTokenList.length < 1
        ? this.sourceTokenList.filter(
            cancelToken => cancelToken.cancelKey !== cancelKey
          )
        : [];
  }

  /**
   * @description 攔截請求
   * @returns void 0
   */

  private httpInterceptorsRequest(): void {
    Http.axiosInstance.interceptors.request.use(
      (config: HttpRequestConfig) => {
        const $config = config;
        NProgress.start(); // 每次切換頁面時,調用進度條
        const cancelKey = Http.genUniqueKey($config);
        $config.cancelToken = new this.CancelToken(
          (cancelExecutor: (cancel: any) => void) => {
            this.sourceTokenList.push({ cancelKey, cancelExecutor });
          }
        );
        this.cancelRepeatRequest();
        this.currentCancelTokenKey = cancelKey;
        // 優先判斷post/get等方法是否傳入回掉,否則執行初始化設置等回掉
        if (typeof config.beforeRequestCallback === "function") {
          config.beforeRequestCallback($config);
          return $config;
        }
        if (Http.initConfig.beforeRequestCallback) {
          Http.initConfig.beforeRequestCallback($config);
          return $config;
        }
        return $config;
      },
      error => {
        return Promise.reject(error);
      }
    );
  }

  /**
   * @description 清空當前cancelTokenList
   * @returns void 0
   */
  public clearCancelTokenList(): void {
    this.sourceTokenList.length = 0;
  }

  /**
   * @description 攔截響應
   * @returns void 0
   */
  private httpInterceptorsResponse(): void {
    const instance = Http.axiosInstance;
    instance.interceptors.response.use(
      (response: HttpResoponse) => {
        const $config = response.config;
        // 請求每次成功一次就刪除當前canceltoken標記
        const cancelKey = Http.genUniqueKey($config);
        this.deleteCancelTokenByCancelKey(cancelKey);

        NProgress.done();
        // 優先判斷post/get等方法是否傳入回掉,否則執行初始化設置等回掉
        if (typeof $config.beforeResponseCallback === "function") {
          $config.beforeResponseCallback(response);
          return response.data;
        }
        if (Http.initConfig.beforeResponseCallback) {
          Http.initConfig.beforeResponseCallback(response);
          return response.data;
        }
        return response.data;
      },
      (error: HttpError) => {
        const $error = error;
        // 判斷當前的請求中是否在 取消token數組理存在,如果存在則移除(單次請求流程)
        if (this.currentCancelTokenKey) {
          const haskey = this.sourceTokenList.filter(
            cancelToken => cancelToken.cancelKey === this.currentCancelTokenKey
          ).length;
          if (haskey) {
            this.sourceTokenList = this.sourceTokenList.filter(
              cancelToken =>
                cancelToken.cancelKey !== this.currentCancelTokenKey
            );
            this.currentCancelTokenKey = "";
          }
        }
        $error.isCancelRequest = Axios.isCancel($error);
        NProgress.done();
        // 所有的響應異常 區分來源為取消請求/非取消請求
        return Promise.reject($error);
      }
    );
  }

  public request<T>(
    method: RequestMethods,
    url: string,
    param?: AxiosRequestConfig,
    axiosConfig?: HttpRequestConfig
  ): Promise<T> {
    const config = transformConfigByMethod(param, {
      method,
      url,
      ...axiosConfig
    } as HttpRequestConfig);
    // 單獨處理自定義請求/響應回掉
    return new Promise((resolve, reject) => {
      Http.axiosInstance
        .request(config)
        .then((response: undefined) => {
          resolve(response);
        })
        .catch((error: any) => {
          reject(error);
        });
    });
  }

  public post<T>(
    url: string,
    params?: T,
    config?: HttpRequestConfig
  ): Promise<T> {
    return this.request<T>("post", url, params, config);
  }

  public get<T>(
    url: string,
    params?: T,
    config?: HttpRequestConfig
  ): Promise<T> {
    return this.request<T>("get", url, params, config);
  }
}

export default Http;

config.ts

import { AxiosRequestConfig } from "axios";
import { excludeProps } from "./utils";
/**
 * 預設配置
 */
export const defaultConfig: AxiosRequestConfig = {
  baseURL: "",
  //10秒超時
  timeout: 10000,
  headers: {
    Accept: "application/json, text/plain, */*",
    "Content-Type": "application/json",
    "X-Requested-With": "XMLHttpRequest"
  }
};

export function genConfig(config?: AxiosRequestConfig): AxiosRequestConfig {
  if (!config) {
    return defaultConfig;
  }

  const { headers } = config;
  if (headers && typeof headers === "object") {
    defaultConfig.headers = {
      ...defaultConfig.headers,
      ...headers
    };
  }
  return { ...excludeProps(config!, "headers"), ...defaultConfig };
}

export const METHODS = ["post", "get", "put", "delete", "option", "patch"];

utils.ts

import { HttpRequestConfig } from "./types.d";

export function excludeProps<T extends { [key: string]: any }>(
  origin: T,
  prop: string
): { [key: string]: T } {
  return Object.keys(origin)
    .filter(key => !prop.includes(key))
    .reduce((res, key) => {
      res[key] = origin[key];
      return res;
    }, {} as { [key: string]: T });
}

export function transformConfigByMethod(
  params: any,
  config: HttpRequestConfig
): HttpRequestConfig {
  const { method } = config;
  const props = ["delete", "get", "head", "options"].includes(
    method!.toLocaleLowerCase()
  )
    ? "params"
    : "data";
  return {
    ...config,
    [props]: params
  };
}

types.d.ts

import Axios, {
  AxiosRequestConfig,
  Canceler,
  AxiosResponse,
  Method,
  AxiosError
} from "axios";

import { METHODS } from "./config";

export type cancelTokenType = { cancelKey: string; cancelExecutor: Canceler };

export type RequestMethods = Extract<
  Method,
  "get" | "post" | "put" | "delete" | "patch" | "option" | "head"
>;

export interface HttpRequestConfig extends AxiosRequestConfig {
  // 請求發送之前
  beforeRequestCallback?: (request: HttpRequestConfig) => void; 
  // 相應返回之前
  beforeResponseCallback?: (response: HttpResoponse) => void; 
}

export interface HttpResoponse extends AxiosResponse {
  config: HttpRequestConfig;
}

export interface HttpError extends AxiosError {
  isCancelRequest?: boolean;
}

export default class Http {
  cancelTokenList: Array<cancelTokenType>;
  clearCancelTokenList(): void;
  request<T>(
    method: RequestMethods,
    url: string,
    param?: AxiosRequestConfig,
    axiosConfig?: HttpRequestConfig
  ): Promise<T>;
  post<T>(
    url: string,
    params?: T,
    config?: HttpRequestConfig
  ): Promise<T>;
  get<T>(
    url: string,
    params?: T,
    config?: HttpRequestConfig
  ): Promise<T>;
}

index.ts

import Http from "./core";
export const http = new Http();

統一api管理

在src下新增api文件夾,對項目中介面做統一管理,按照模塊來劃分。

例如,在 api 文件下新增 user.ts和types.ts ,分別用於存放登錄,註冊等模塊的請求介面和數據類型。

// login.ts
import { http } from "@/http/index";
import { ILoginReq, ILoginRes } from "./types";

export const getLogin = async(req: ILoginParams): Promise<ILoginRes> => {
  const res:any = await http.post('/login/info', req)
  return res as ILoginRes
}
# 或者
export const getLogin1 = async(req: ILoginParams): Promise<ILoginRes> => {
  const res:any = await http.request('post', '/login/info', req)
  return res as ILoginRes
}
// types.ts
export interface ILoginReq {
  userName: string;
  password: string;
}

export interface ILoginRes {
  access_token: string;
  refresh_token: string;
  scope: string
  token_type: string
  expires_in: string
}

除了自己手動封裝 axios ,這裡還推薦一個十分非常強大牛皮的 vue3 的請求庫: VueRequest,裡面的功能非常的豐富(偷偷告訴你我也在使用中)。官網地址:https://www.attojs.com/

狀態管理 Pinia

Pinia 是 Vue.js 的輕量級狀態管理庫,最近很受歡迎。它使用 Vue 3 中的新反應系統來構建一個直觀且完全類型化的狀態管理庫。

由於 vuex 4 對 typescript 的支持很不友好,所以狀態管理棄用了 vuex 而採取了 pinia, pinia 的作者是 Vue 核心團隊成員,並且pinia已經正式加入了Vue,成為了Vue中的一員。尤大佬 pinia 可能會代替 vuex,所以請放心使用(公司項目也在使用中)。

Pinia官網地址(https://pinia.vuejs.org

Pinia的一些優點:

(1)Pinia 的 API 設計非常接近 Vuex 5 的提案。

(2)無需像 Vuex 4 自定義複雜的類型來支持 typescript,天生具備完美的類型推斷。

(3)模塊化設計,你引入的每一個 store 在打包時都可以自動拆分他們。

(4)無嵌套結構,但你可以在任意的 store 之間交叉組合使用。

(5)Pinia 與 Vue devtools 掛鉤,不會影響 Vue 3 開發體驗。

Pinia的成功可以歸功於其管理存儲數據的獨特功能(可擴展性、存儲模塊組織、狀態變化分組、多存儲創建等)。

另一方面,Vuex也是為Vue框架建立的一個流行的狀態管理庫,它也是Vue核心團隊推薦的狀態管理庫。Vuex高度關註應用程式的可擴展性、開發人員的工效和信心。它基於與Redux相同的流量架構。

Pinia和Vuex都非常快,在某些情況下,使用Pinia的web應用程式會比使用Vuex更快。這種性能的提升可以歸因於Pinia的極輕的體積,Pinia體積約1KB。

安裝

# 安裝
yarn add pinia@next

在src下新建store文件夾,在store文件夾下新建index.ts,mutation-types(變數集中管理),types.ts(類型)和modules文件夾(分模塊管理狀態)

// index.ts
import type { App } from "vue";
import { createPinia } from "pinia";

const store = createPinia();
export function setupStore(app: App<Element>) {
    app.use(store)
}

export { store }
// modules/user.ts
import { defineStore } from 'pinia';
import { store } from '@/store';
import { ACCESS_TOKEN } from '@/store/mutation-types';
import { IUserState } from '@/store/types'

export const useUserStore = defineStore({
  // 此處的id很重要
  id: 'app-user',
  state: (): IUserState => ({
    token: localStorge.getItem(ACCESS_TOKEN)
  }),
  getters: {
    getToken(): string {
      return this.token;
    }
  },
  actions: {
    setToken(token: string) {
      this.token = token;
    },
    // 登錄
    async login(userInfo) {
      try {
        const response = await login(userInfo);
        const { result, code } = response;
        if (code === ResultEnum.SUCCESS) {
          localStorage.setItem(ACCESS_TOKEN, result.token);
          this.setToken(result.token);
        }
        return Promise.resolve(response);
      } catch (e) {
        return Promise.reject(e);
      }
    },
  }
})

// Need to be used outside the setup
export function useUserStoreHook() {
  return useUserStore(store);
}
/// mutation-types.ts
// 對變數做統一管理
export const ACCESS_TOKEN = 'ACCESS-TOKEN'; // 用戶token

修改main.ts

import { createApp } from 'vue'
import App from './App.vue'
import { setupStore } from '@/store'
import router from './router/index'

const app = createApp(App)
// 掛載狀態管理
setupStore(app);

app.use(router)

app.mount('#app')

在組件中使用

<template>
  <div>{{userStore.token}}</div>
</template>

<script lang="ts">
import { defineComponent } from 'vue'
import { useUserStoreHook } from "@/store/modules/user"

export default defineComponent({
  setup() {
    const userStore = useUserStoreHook()
    
    return {
      userStore
    }
  },
})
</script>

getters的用法介紹

// modules/user.ts
import { defineStore } from 'pinia';
import { store } from '@/store';
import { ACCESS_TOKEN } from '@/store/mutation-types';
import { IUserState } from '@/store/types'
 
export const useUserStore = defineStore({
  // 此處的id很重要
  id: 'app-user',
  state: (): IUserState => ({
    token: localStorge.getItem(ACCESS_TOKEN),
    name: ''
  }),
  getters: {
    getToken(): string {
      return this.token;
    },
    nameLength: (state) => state.name.length,
  },
  actions: {
    setToken(token: string) {
      this.token = token;
    },
    // 登錄
    async login(userInfo) {
      // 調用介面,做邏輯處理
    }
  }
})

// Need to be used outside the setup
export function useUserStoreHook() {
  return useUserStore(store);
}
<template>
  <div>
   <span>{{userStore.name}}</span>
  <span>{{userStore.nameLength}}</span>
  <buttton @click="changeName"></button>
  </div>
</template>

<script lang="ts">
import { defineComponent } from 'vue'
import { useUserStoreHook } from "@/store/modules/user"

export default defineComponent({
  setup() {
    const userStore = useUserStoreHook()
    
    const changeName = ()=>{
    // $patch 修改 store 中的數據
      userStore.$patch({
        name: '名稱被修改了,nameLength也改變了'
      })
  }
    
    return {
      userStore,
      updateName
    }
  },
})
</script>

actions

這裡與 Vuex 有極大的不同,Pinia 僅提供了一種方法來定義如何更改狀態的規則,放棄 mutations 只依靠 Actions,這是一項重大的改變。

Pinia 讓 Actions 更加的靈活

  • 可以通過組件或其他 action 調用

  • 可以從其他 store 的 action 中調用

  • 直接在商店實例上調用

  • 支持同步非同步

  • 有任意數量的參數

  • 可以包含有關如何更改狀態的邏輯(也就是 vuex 的 mutations 的作用)

  • 可以 $patch 方法直接更改狀態屬性

    更多詳細的用法請參考Pinia中的actions官方網站:

    actions的用法(https://pinia.vuejs.org/core-concepts/actions.html)

環境變數配置

vite 提供了兩種模式:具有開發伺服器的開發模式(development)和生產模式(production)。在項目的根目錄中我們新建開發配置文件.env.development和生產配置文件.env.production。

# 網站根目錄
VITE_APP_BASE_URL= ''

組件中使用:

console.log(import.meta.env.VITE_APP_BASE_URL)

配置 package.json,打包區分開發環境和生產環境

"build:dev": "vue-tsc --noEmit && vite build --mode development",
"build:pro": "vue-tsc --noEmit && vite build --mode production",

使用組件庫

根據自己的項目需要選擇合適的組件庫即可,這裡推薦兩個優秀的組件庫Element-plus和Naive UI。下麵簡單介紹它們的使用方法。

使用element-plus(https://element-plus.gitee.io/zh-CN/)

yarn add element-plus

推薦按需引入的方式:

按需引入需要安裝unplugin-vue-components和unplugin-auto-import兩個插件。

yarn add -D unplugin-vue-components unplugin-auto-import

再將vite.config.ts寫入一下配置,即可在項目中使用element plus組件,無需再引入。

// vite.config.ts
import AutoImport from 'unplugin-auto-import/vite'
import Components from 'unplugin-vue-components/vite'
import { ElementPlusResolver } from 'unplugin-vue-components/resolvers'

export default {
  plugins: [
    // ...
    AutoImport({
      resolvers: [ElementPlusResolver()],
    }),
    Components({
      resolvers: [ElementPlusResolver()],
    }),
  ],
}

Naive UI(https://www.naiveui.com/zh-CN/os-theme)

# 安裝naive-ui
npm i -D naive-ui

# 安裝字體
npm i -D vfonts

按需全局安裝組件

import { createApp } from 'vue'
import {
  // create naive ui
  create,
  // component
  NButton
} from 'naive-ui'

const naive = create({
  components: [NButton]
})

const app = createApp()
app.use(naive)

安裝後,你可以這樣在 SFC 中使用你安裝的組件。

<template>
  <n-button>naive-ui</n-button>
</template>

Vite 常用基礎配置

基礎配置

運行代理和打包配置

server: {
    host: '0.0.0.0',
    port: 3000,
    open: true,
    https: false,
    proxy: {}
},

生產環境去除 console debugger

build:{
  ...
  terserOptions: {
      compress: {
        drop_console: true,
        drop_debugger: true
      }
  }
}

生產環境生成 .gz 文件,開啟 gzip 可以極大的壓縮靜態資源,對頁面載入的速度起到了顯著的作用。使用 vite-plugin-compression 可以 gzip 或 brotli 的方式來壓縮資源,這一步需要伺服器端的配合,vite 只能幫你打包出 .gz 文件。此插件使用簡單,你甚至無需配置參數,引入即可。

# 安裝
yarn add --dev vite-plugin-compression
// vite.config.ts中添加
import viteCompression from 'vite-plugin-compression'

// gzip壓縮 生產環境生成 .gz 文件
viteCompression({
  verbose: true,
  disable: false,
  threshold: 10240,
  algorithm: 'gzip',
  ext: '.gz',
}),

最終 vite.config.ts文件配置如下(自己根據項目需求配置即可)

import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import path from 'path'
//@ts-ignore
import viteCompression from 'vite-plugin-compression'

// https://vitejs.dev/config/
export default defineConfig({
  base: './', //打包路徑
  plugins: [
    vue(),
    // gzip壓縮 生產環境生成 .gz 文件
    viteCompression({
      verbose: true,
      disable: false,
      threshold: 10240,
      algorithm: 'gzip',
      ext: '.gz',
    }),
  ],
  // 配置別名
  resolve: {
    alias: {
      '@': path.resolve(__dirname, 'src'),
    },
  },
  css:{
    preprocessorOptions:{
      scss:{
        additionalData:'@import "@/assets/style/mian.scss";'
      }
    }
  },
  //啟動服務配置
  server: {
    host: '0.0.0.0',
    port: 8000,
    open: true,
    https: false,
    proxy: {}
  },
  // 生產環境打包配置
  //去除 console debugger
  build: {
    terserOptions: {
      compress: {
        drop_console: true,
        drop_debugger: true,
      },
    },
  },
})

您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 前言 請求響應是指客戶端發送請求給伺服器,伺服器接收到請求後返回的響應。響應包含了伺服器處理請求的結果,並將結果返回給客戶端。 頁面調試是指在開發過程中,通過調試工具分析頁面的運行狀況,查找問題和修複錯誤。常用的頁面調試工具包括瀏覽器的開發者工具和調試插件,可以檢查頁面的網路請求、HTML代碼、 ...
  • 在Android啟動過程-萬字長文(Android14)中介紹了Android系統的啟動過程,本篇文章將繼續介紹桌面應用Launcher。 一、Launcher介紹 在Android啟動過程-萬字長文(Android14)中提到Launcher是Android系統啟動後,由SystemServerA ...
  • 前言 Cookie是一種存儲在用戶電腦上的小文本文件,用於在用戶訪問網站時存儲和提取信息。它由網站伺服器發送到用戶的瀏覽器,並存儲在用戶的電腦上。每當用戶訪問該網站時,瀏覽器將發送該Cookie回伺服器,以用於識別用戶和存儲用戶的首選項和其他信息。 Cookie可以用於跟蹤用戶的行為,例如記 ...
  • 如何在 Flutter 中分享視頻到抖音 話不多說,先上效果: 原理 發佈內容至抖音 H5 場景_移動/網站應用_抖音開放平臺 (open-douyin.com) 本教程沒有接入抖音原生 SDK 以及任何第三方插件,使用抖音的 h5 分享介面配合 url_launcher 插件實現跳轉至抖音分享頁面 ...
  • 前言 頁面跳轉是指在瀏覽器中從當前頁面跳轉到另一個頁面的操作。可以通過點擊鏈接、輸入網址、提交表單等方式實現頁面跳轉。 瀏覽記錄是指記錄用戶在瀏覽器中瀏覽過的頁面的歷史記錄。當用戶跳轉到一個新頁面時,該頁面會被加入瀏覽記錄中,用戶可以通過瀏覽器的後退按鈕或者瀏覽歷史列表來查看和訪問之前瀏覽過的頁 ...
  • 在電腦啟動過程和Linux內核Kernel啟動過程介紹了電腦啟動和內核載入,本篇文章主要介紹Android系統是如何啟動的。 一、Android啟動流程 Android系統的啟動流程與Linux接近: sequenceDiagram participant Bootloader as 引導載入程 ...
  • 傳統實現方式 當前文章的gif文件較大,載入的時長可能較久 這裡我拿小紅書的首頁作為分析演示 可以看到他們的實現方式是傳統做法,把每個元素通過獲取尺寸,然後算出left、top的排版位置,最後在每個元素上設置偏移值,思路沒什麼好說的,就是算元素坐標。那麼這種做法有什麼缺點?請看下麵這張圖的操作 容器 ...
  • title: Vue渲染函數與JSX指南 date: 2024/6/3 下午6:43:53 updated: 2024/6/3 下午6:43:53 categories: 前端開發 tags: Vue渲染 JSX基礎 性能優化 組件對比 React JSX 大項目 測試策略 第1章:Vue.js入門 ...
一周排行
    -Advertisement-
    Play Games
  • 示例項目結構 在 Visual Studio 中創建一個 WinForms 應用程式後,項目結構如下所示: MyWinFormsApp/ │ ├───Properties/ │ └───Settings.settings │ ├───bin/ │ ├───Debug/ │ └───Release/ ...
  • [STAThread] 特性用於需要與 COM 組件交互的應用程式,尤其是依賴單線程模型(如 Windows Forms 應用程式)的組件。在 STA 模式下,線程擁有自己的消息迴圈,這對於處理用戶界面和某些 COM 組件是必要的。 [STAThread] static void Main(stri ...
  • 在WinForm中使用全局異常捕獲處理 在WinForm應用程式中,全局異常捕獲是確保程式穩定性的關鍵。通過在Program類的Main方法中設置全局異常處理,可以有效地捕獲並處理未預見的異常,從而避免程式崩潰。 註冊全局異常事件 [STAThread] static void Main() { / ...
  • 前言 給大家推薦一款開源的 Winform 控制項庫,可以幫助我們開發更加美觀、漂亮的 WinForm 界面。 項目介紹 SunnyUI.NET 是一個基於 .NET Framework 4.0+、.NET 6、.NET 7 和 .NET 8 的 WinForm 開源控制項庫,同時也提供了工具類庫、擴展 ...
  • 說明 該文章是屬於OverallAuth2.0系列文章,每周更新一篇該系列文章(從0到1完成系統開發)。 該系統文章,我會儘量說的非常詳細,做到不管新手、老手都能看懂。 說明:OverallAuth2.0 是一個簡單、易懂、功能強大的許可權+可視化流程管理系統。 有興趣的朋友,請關註我吧(*^▽^*) ...
  • 一、下載安裝 1.下載git 必須先下載並安裝git,再TortoiseGit下載安裝 git安裝參考教程:https://blog.csdn.net/mukes/article/details/115693833 2.TortoiseGit下載與安裝 TortoiseGit,Git客戶端,32/6 ...
  • 前言 在項目開發過程中,理解數據結構和演算法如同掌握蓋房子的秘訣。演算法不僅能幫助我們編寫高效、優質的代碼,還能解決項目中遇到的各種難題。 給大家推薦一個支持C#的開源免費、新手友好的數據結構與演算法入門教程:Hello演算法。 項目介紹 《Hello Algo》是一本開源免費、新手友好的數據結構與演算法入門 ...
  • 1.生成單個Proto.bat內容 @rem Copyright 2016, Google Inc. @rem All rights reserved. @rem @rem Redistribution and use in source and binary forms, with or with ...
  • 一:背景 1. 講故事 前段時間有位朋友找到我,說他的窗體程式在客戶這邊出現了卡死,讓我幫忙看下怎麼回事?dump也生成了,既然有dump了那就上 windbg 分析吧。 二:WinDbg 分析 1. 為什麼會卡死 窗體程式的卡死,入口門檻很低,後續往下分析就不一定了,不管怎麼說先用 !clrsta ...
  • 前言 人工智慧時代,人臉識別技術已成為安全驗證、身份識別和用戶交互的關鍵工具。 給大家推薦一款.NET 開源提供了強大的人臉識別 API,工具不僅易於集成,還具備高效處理能力。 本文將介紹一款如何利用這些API,為我們的項目添加智能識別的亮點。 項目介紹 GitHub 上擁有 1.2k 星標的 C# ...