主頁 > 企業開發 > 教程 - 在 Vue3+Ts 中引入 CesiumJS 的最佳實踐@2023

教程 - 在 Vue3+Ts 中引入 CesiumJS 的最佳實踐@2023

2023-04-09 09:25:12 企業開發

目錄
  • 1. 本篇適用范圍與目的
    • 1.1. 適用范圍
    • 1.2. 目的
  • 2. 牛刀小試 - 先看到地球
    • 2.1. 創建 Vue3 - TypeScript 工程并安裝 cesium
    • 2.2. 清理不必要的檔案并創建三維地球
    • 2.3. 中段解疑 - 奇怪的路徑
    • 2.4. 打包部署
    • 2.5. 有限的優化
  • 3. CesiumJS 前置知識
    • 3.1. CesiumJS 依賴包中的資料說明
    • 3.2. 構建后的 CesiumJS 庫組成 - 主庫檔案與四大檔案夾
    • 3.3. 鏈接庫檔案和四大檔案夾的 CESIUM_BASE_URL 變數
  • 4. 現代前端工具的基本常識
    • 4.1. 選擇 Vite 的理由
    • 4.2. 為什么外部化引入(External)一個庫
    • 4.3. TypeScript 型別提示
    • 4.4. 開發服務器的路徑與代碼中的路徑問題
  • 5. 教程(原理)正文
    • 5.1. 使用 create-vite 在命令列創建工程
    • 5.2. 指定版本安裝 cesium
    • 5.3. 包管理工具鎖檔案的取舍
    • 5.4. 使用插件外部化 CesiumJS
    • 5.5. 使用插件自動在 index.html 引入 Cesium.js 庫檔案
    • 5.6. 四大靜態檔案夾與庫檔案的拷貝(CDN或獨立部署了 CesiumJS 庫可省略此步)
    • 5.7. 額外優化 - 使用環境變數配置 CESIUM_BASE_URL 并適配其它配置
    • 5.9. 額外優化 - 使用 gzip 預先壓縮打包產物
    • 5.8. 如何共享 CesiumJS 的 Viewer 物件
  • 6. 探究 CesiumJS 等庫的前端組件封裝
    • 6.1. 以 CesiumJS 等庫為主的看板式工程
    • 6.2. 后臺管理系統式工程
  • 7. 示例工程下載


這篇如果 Vue 和 CesiumJS 不發生史詩級的變動,應該不會再有后文了,主要是這類文章沒什么營養,

這篇主要修正上篇 https://www.cnblogs.com/onsummer/p/16629036.html 中一些插件的變化,并升級開發服務器的版本,

心急的朋友拉到文末,有示例工程鏈接下載,

1. 本篇適用范圍與目的

1.1. 適用范圍

  • 嚴格使用 Vue3 + TypeScript 的前端專案,包管理器默認使用 pnpm

  • 構建工具使用 Vite4

  • 使用原生 CesiumJS 依賴做應用開發

  • 客戶端渲染,因為我不太熟悉 Vue 的服務端渲染,有本篇的介紹后,熟悉 SSR 的讀者可以自己接入

  • 單頁應用,多頁應用也可以參考此法

鑒于國內使用 CesiumJS 的比例大多數為應用開發(粗話即“APICaller”),而非擴展開發(基于原始碼作新功能封裝、打包),所以我默認讀者使用 CesiumJS 是通過 npmjs 網站(或鏡像站)拉取的依賴,即:

pnpm add cesium@latest

有想修改原始碼再自己打包的讀者,我覺得應該去看我的原始碼系列博客,

1.2. 目的

在 Vue3 工程中引入 CesiumJS 的最佳方式,并引出地圖組件封裝的簡單經驗兩則,

這篇文章更傾向于給讀者一些原理,而不是提供一套開箱即用的工具,有能力的讀者可以根據這篇文章的原理,結合 Vite 或其它打包工具的 API,寫一個專屬插件,

2. 牛刀小試 - 先看到地球

如果沒有快速看到 3D 虛擬地球,我覺得心急的朋友會心急(廢話),

第 2 節不需要知道原理,原理和最佳實踐請往下閱讀 3、4、5 節,

2.1. 創建 Vue3 - TypeScript 工程并安裝 cesium

如果你沒有命令列基礎,也不懂什么是 NodeJS、npm,不知道 node-package 是什么東西,建議先補補 NodeJS 為基礎的前端工具鏈知識,

直接上命令列(要聯網,配好你的 npm 源),請在任意你方便的地方運行:

pnpm create vite

輸入你想要的手動選擇 Vue、TypeScript 的模板即可,然后進入工程檔案夾,我的工程檔案夾叫作 v3ts-cesium-2023,所以我接下來要安裝 CesiumJS:

cd ./v3ts-cesium-2023
pnpm add [email protected]

pnpm add 會一并把模板的其它依賴下載下來,所以就不用再執行 pnpm install 了,

我在安裝 cesium 時指定了版本,是考慮到 很多專案可能不太注意依賴版本管理,所以干脆鎖死固定版本,

2.2. 清理不必要的檔案并創建三維地球

我移除了 src/assetssrc/components 檔案夾,并洗掉全部 src/style.css 的代碼,改寫 main.tsApp.vuestyle.css 如下:

// main.ts

import { createApp } from 'vue'
import App from './App.vue'

import './style.css'

declare global {
  interface Window {
    CESIUM_BASE_URL: string
  }
}

createApp(App).mount('#app')

你注意到了,我在 main.ts 中為全域宣告了 CESIUM_BASE_URL 變數的型別為 string,這在 App.vue 中就會用到:

<script setup lang="ts">
import { onMounted, ref } from 'vue'
import { TileMapServiceImageryProvider, Viewer, buildModuleUrl } from 'cesium'
import 'cesium/Build/CesiumUnminified/Widgets/widgets.css'

const viewerDivRef = ref<HTMLDivElement>()
window.CESIUM_BASE_URL = 'node_modules/cesium/Build/CesiumUnminified/'

onMounted(() => {
  new Viewer(viewerDivRef.value as HTMLElement, {
    imageryProvider: new TileMapServiceImageryProvider({
      url: 'node_modules/cesium/Build/CesiumUnminified/Assets/Textures/NaturalEarthII',
    })
  })
})
</script>

<template>
  <div id="cesium-viewer" ref="viewerDivRef"></div>
</template>

<style scoped>
#cesium-viewer {
  width: 100%;
  height: 100%;
}
</style>

我在 App.vue 組件的 mounted hook 中輕松地創建了 Viewer,語法不再贅述,我做了如下幾個點讓地球顯示出來:

  • Viewer 構造引數傳遞了 div#cesium-viewer 元素的 ref 值,并將其型別 as HTMLElement,以滿足 CesiumJS 的型別
  • 引入 CesiumJS 自己的 css,供 Viewer 的各個內置界面小組件(時間軸等)提供 CSS 樣式
  • Viewer 創建了一個 CesiumJS 自帶的離線 TMS 瓦片服務,你可能很奇怪為什么路徑是 node_modules 起頭的,待會解釋,這個 TMS 瓦片服務只有 2 級
  • 設定 CESIUM_BASE_URL

帶著好奇心,先別急,等我講完,最后是 style.css,是一些簡單的樣式:

/* style.css */

html, body {
  padding: 0;
  margin: 0;
}

#app {
  height: 100vh;
  width: 100vw;
}

隨后,命令列啟動開發服務器:

pnpm dev

在 Vite4 的強大性能加持下,很快就起起來了,這個時候就可以在瀏覽器看到一個具有兩級離線 TMS 瓦片服務的三維地球:

image

2.3. 中段解疑 - 奇怪的路徑

你注意到了,2.2 小節里有兩個奇怪的路徑:

window.CESIUM_BASE_URL = 'node_modules/cesium/Build/CesiumUnminified/'
new TileMapServiceImageryProvider({
  url: 'node_modules/cesium/Build/CesiumUnminified/Assets/Textures/NaturalEarthII',
})

這是因為 Vite 開發模式下(pnpm devNODE_ENVdevelopment)是直接把工程根路徑(即 vite.config.ts 所在的檔案夾)映射到 http://localhost:5173/ 這個 URL 上的,所以理所當然填寫 CesiumJS 庫檔案的路徑就要從 node_modules 開始寫起,

我這里選用的是 CesiumUnminified 版本(未壓縮版本),

CESIUM_BASE_URL 的含義是,專案運行的根網路路徑(這里就是指 Vite 開發服務器的默認地址 http://localhost:5173/),加上 CESIUM_BASE_URL 后,在這個拼成的路徑就能訪問到 CesiumJS 的入口檔案,即完整版:

http://localhost:5173/node_modules/cesium/Build/CesiumUnminified/Cesium.js(這個指向的是未壓縮版的 IIFE 庫檔案)

你可以把這個完整地址在啟動后粘貼到瀏覽器的地址欄,然后回車,就能看到 CesiumJS 打包后的庫檔案原始碼了,

同理,自帶的 TMS 瓦片資料就存放在 http://localhost:5173/node_modules/cesium/Build/CesiumUnminified/Assets/Textures/NaturalEarthII 地址下,TMS 服務的識別方法就是觀察網路請求有無一個 tilemapresource.xml 檔案:

image

2.4. 打包部署

有了 2.3 小節的解釋,現在要上生產環境了,生產環境也許是 nginx,也許是其它的 Web 服務器,這個時候就沒有 node_modules 了,畢竟 Vite 的開發服務器職責已經在 build 后完成,

這個時候就要作出以下修改:

  • 修改 CESIUM_BASE_URL 為生產環境能訪問的 CesiumJS 庫檔案的地址
  • 修改 TileMapServiceImageryProvider 的離線 TMS 路徑

在修改之前,需要你把 CesiumJS 的四大靜態資源檔案夾從 node_modules 中拷貝出來,跟著做就行,

我把 node_modules/cesium/Build/CesiumUnminified/ 這個未壓縮版本的檔案夾下所有內容,即 AssetsWidgetsWorkersThirdParty 四個檔案夾拷貝到 public/libs/cesium/ 下(沒有就自己創建一下):

image

CesiumJS 的正常運行需要這些靜態檔案,原因在第 3 節會詳細說明,先照做,

然后修改 CESIUM_BASE_URL 和離線 TMS 的地址:

window.CESIUM_BASE_URL = 'libs/cesium/'

new TileMapServiceImageryProvider({
  url: 'libs/cesium/Assets/Textures/NaturalEarthII',
})

此時運行 pnpm dev,依舊是正常的,只不過靜態檔案資源已經從 node_modules/cesium/Build/CesiumUnminified/ 改到了 public/libs/cesium/ 下,

順帶一提,Vite 開發服務器的根路徑,除了掛載了工程的根目錄,還掛載了工程根目錄下的 public 目錄,public 目錄的作用請自己查閱 Vite 檔案,

這個時候就可以使出 pnpm build 然后 pnpm preview 組合了,打包并使用 http 服務預覽構建后的產物:

pnpm build && pnpm preview

我的 CPU 是 i5 13600K,在 7 秒多的打包后緊接著就啟動了 4173 埠的服務:

image

運行起來和開發時無異,

2.5. 有限的優化

有人也許對 Vite 等打包工具比較熟悉,可以配置分包(修改 vite.config.ts 中的配置引數)來辨別打包后的產物各自的體積:

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

// https://vitejs.dev/config/
export default defineConfig({
  plugins: [vue(), splitVendorChunkPlugin()],
  build: {
    rollupOptions: {
      output: {
        manualChunks: {
          cesium: ['cesium']
        }
      }
    }
  }
})

這樣之后打包的產物就略有不同:

image

image

似乎 splitVendorChunkPlugin() 不添加到 plugins 陣列中也可以生效,但是為了盡可能優化打包產物,還是加上了

但是,即便這樣,也只是把 cesium 依賴分拆到一個塊檔案中,并沒有實質性改變如下事實:

  • Vite 仍需對毫無修改的 cesium 依賴包打包一次,CesiumJS 已經在發布 npm 包時進行了構建,其雖然有 ESModule 格式的產物,但是并不支持 Tree-Shaking 減小大小,事實上也沒有必要,CesiumJS 的內部是高度耦合的三維渲染器、各種演算法,這種高度集成的演算法產物保持一致是比較好的(或許官方未來可能有改變,但是至少現在沒有),所以在我這里這 “7秒多” 的打包時間毫無必要,在其它打包工具也是一樣的(Webpack等)

  • 我需要手動復制 node_modules/cesium/Build/CesiumUnminified/ 下的四個靜態資源檔案夾

  • 對多個發布環境仍需要手動修改 CESIUM_BASE_URL,如果切換到 CDN 或內網已有 CesiumJS 在線庫資源,這個改起來就麻煩許多

考慮到真正的專案大概率不會使用自帶的離線二級 TMS 瓦片服務,所以不算作可優化的點,

所以,我將費點篇幅,先介紹 CesiumJS 包 的基本知識,再介紹一些現代前端工具的常識,最后再介紹我認為最合理最靈活的引入方式,

授人以漁,你可以根據這篇文章的內容自己寫一個方便的 Vite 插件,也可以就此為止,如果你不嫌棄上述三個麻煩事兒,

3. CesiumJS 前置知識

3.1. CesiumJS 依賴包中的資料說明

image

通過包管理器下載到 node_modules 下的 cesium 依賴,是 CesiumJS 打包好的“包”,它具備如下資料:

  • 不完整的源代碼,位于 node_modules/cesium/Source/ 目錄下,含一個出口檔案 Cesium.js 和一個 TypeScript 型別定義檔案 Cesium.d.ts,出口檔案匯出的所有模塊,也就是真正的原始碼均來自子包 @cesium/engine@cesium/widgets(于 1.100 版本變動,將代碼分割于子包中)

  • 打包后的庫程式檔案,含 IIFEES-ModuleCommonJS 三種格式,每種格式又有壓縮代碼版本和未壓縮版本,分別存放于 node_modules/cesium/Build/Cesium/node_modules/cesium/Build/CesiumUnminified/ 目錄下,各種格式各有用途,如果是 CommonJS 環境下,會參考 index.cjs,而如果是 ES-Module 環境下,會參考 index.js;剩下的 Cesium.js 則用在 IIFE 環境下,

  • 無論是不完整的原始碼,還是打包后的庫程式檔案,都會附帶所需的靜態資源檔案

應用級別的開發,只需要用到打包后的庫程式檔案以及 TypeScript 型別定義檔案就好了,

我一般選用的是 IIFE 格式里的壓縮版本,即 node_modules/cesium/Build/Cesium/Cesium.js,這個庫檔案只有 3.7 MB,gzip 壓縮后可小于 1 MB,體積控制很不錯,

3.2. 構建后的 CesiumJS 庫組成 - 主庫檔案與四大檔案夾

主庫檔案在 2.1 小節已經說明,壓縮版和未壓縮版均含 CommonJSIIFEES-Module 三種格式的庫檔案,檔案名有所不同,

image

CesiumJS 的源代碼(即 node_modules/cesium/Source/ 的出口檔案,以及這個出口檔案引自的 @cesium/engine@cesium/widgets 子包的代碼模塊)并不是完整的 cesium 庫,cesium 庫還包括:

  • 一套 WebWorker,用于引數幾何的生成、ktx2 紋理解碼、draco 壓縮資料解碼等多執行緒任務
  • 一套 css 檔案,用于 Viewer 下具有 HTML 界面的內置組件的樣式表達,例如時間線等組件
  • 一套靜態資源檔案,用于構造默認場景和內置組件,例如 SkyBox 背景圖、圖示、離線的兩級 TMS 資料等
  • 一些第三方庫,用于 basis 紋理和 draco 資料解碼的 WebAssembly 檔案以及配套的 WebWorker 檔案

僅靠源代碼是不能運行起 Cesium 三維地球場景的,必須使用構建版本的 CesiumJS 庫,而官方構建后的 CesiumJS 庫(即發布在 npm 上的 cesium 包)一定會包含以上四類檔案,即 node_modules/cesium/Build/ 下的壓縮和未壓縮版本檔案夾下的 WorkersWidgetsWidgetsAssets 四大檔案夾,

image

3.3. 鏈接庫檔案和四大檔案夾的 CESIUM_BASE_URL 變數

在 2.2 和 2.3 小節中已經比較完備地解釋了 CESIUM_BASE_URL 的作用,它就是告訴已經運行的 CesiumJS 上哪去找四類靜態資源,

當然,可以設定私有部署的 CesiumJS 庫或者免費的 CDN:

window.CESIUM_BASE_URL = 'http://localhost:8888/cesium/1.103.0/'
window.CESIUM_BASE_URL = 'https://cdn.bootcdn.net/ajax/libs/cesium/1.103.0/'

不再贅述,

4. 現代前端工具的基本常識

4.1. 選擇 Vite 的理由

尤雨溪在某次 B 站直播介紹 Vue3 測驗版(似乎是2020年)時,在介紹完新的 setup 函式后,帶了個貨,即 Vite 的最初始版本,應該是 1.0 時代的東西了,那時還和 Vue 是強依賴的,在 Vite2 時才與具體前端框架解耦,

我在第一時間就去體驗了 Vite1.0,說實話沒什么特別的感覺,還以為是做了一個什么模板,沒想到經過 2.0 的積累更新、3.0、4.0 的快速迭代后,現在的 Vite 已經是我替代 Webpack 的主力前端開發工具了(說實話我很少用 Webpack 為底子的各種腳手架、框架),

Vite 真的很快,上一篇還是 Vite3,現在已經到 Vite4 了,這更新速度...雖然在 API 和配置上基本沒什么變化,應該在 4.x 算是穩定了,

4.2. 為什么外部化引入(External)一個庫

Vite 和 Webpack 類似,都能把一些依賴無視,不參與打包,一旦某個依賴被配置為“外部的”,即 External 化,就不會打包它了,

社區在普通前端的實踐中經常把 Vue、React、Axios 等不需要打包、可以使用高速 CDN 加速的庫都外部化了,

CesiumJS 這個體積如此巨大的庫(壓縮版 + gzip 后主庫檔案至少也有900+KB)按理說也應該外部化,極大減輕打包時的負擔和產物,使用 CDN 還能些許加速首屏性能,

External 化需要一些比較繁瑣的配置,如果讀者認為不需要外部化,任 Vite 把 CesiumJS 再次打包那幾秒鐘、十幾秒鐘也無所謂的話,其實也可以不做這一步,

既然說了最佳化實踐,那我就一定要寫這一步,萬一有人需要呢?

在之后會使用 vite-plugin-externals 插件(注意,有 s 結尾)完成外部化,

4.3. TypeScript 型別提示

沒有型別提示還得自己手動確認傳值型別是否正確,TS 在靜態代碼編輯環境借助代碼編輯器的各種功能,就可以預先檢查出可能存在的錯誤,最大地規避運行時的問題,

cesium 包自帶了型別檔案,位于 node_modules/cesium/Source/Cesium.d.ts,你也可以在其 package.json 中找到型別欄位,

我們創建工程時,模板已經配置好了 TypeScript,默認情況下不需要我們額外配置什么,正常在組件或 ts 檔案中匯入 cesium 包的模塊即可:

import { Viewer } from 'cesium'

這也是官方推薦的匯入方法,這樣匯入是具備 TS 型別提示的,

噢對了,如果你用的是 VSCode,偶爾你會遇到 TS 型別提示不正常的問題,大多數是這 5 個原因:

  • 如果你在用 Volar 插件來智能提示 .vue 檔案,那么你需要去 Vue 官方檔案中配置下 “take over” 模式
  • 沒有安裝 typescript 到開發依賴
  • 安裝了 typescript 到開發依賴但是工程沒有使用開發依賴的 ts,而使用了 VSCode 自己的 ts,這個用 Ctrl + Shift + P 切換一下 ts 版本即可(搜索“Select Typescript” 或直接搜 “Typescript” 選擇版本即可),會寫入 .vscode/settings.json 檔案
  • 上述問題都排除了,也許是 tsconfig.json 沒有包括目標 d.ts 檔案
  • 也有可能某個庫壓根就沒有自帶 d.ts,也沒有對應的型別庫

4.4. 開發服務器的路徑與代碼中的路徑問題

這是一個新手問題,新手在開發工具(例如 Webpack、Vite)的滋潤下能非常熟練地從各種地方 import 各種各樣的資源,例如 ts、js、json、圖片圖示、less/css/sass 等資源模塊,

例如:

import Logo from '@/assets/svg/logo.svg'

這樣的路徑大概率是配置好 @ 指向工程下的 src 目錄,

或者裸模塊匯入:

import { ref } from 'vue'

這些看似“不就是這樣的嗎”的匯入實際上是開發工具做的努力,

然而,在 GIS、三維這些小眾的領域,開發工具就不一定有適配了,例如,你不能把相對目錄或配置好的目錄下的 glTF 模型匯入:

import Duck from './data/duck.gltf'
import Ball from '@/assets/model/duck.glb'

幸運的是對 glTF 模型已經有了 vite 插件,但是我仍然不推薦你這樣引入,

同理,CesiumJS 的 3DTiles 資料集也不要這么做,雖然它的入口檔案是一個 json 檔案,但是瓦片檔案打包器并不會幫你處理,

理清楚匯入問題后,還有一個新手常犯的問題是把“原始碼相對路徑”當作“運行時的路徑”,假設有這么一個代碼檔案 src/views/home.vue 中創建了一個 3DTiles 資料集物件:

// src/views/home.vue
Cesium3DTileset.fromUrl({
  url: '../assets/tileset.json'
})

有的新手把資料就放在了上一級的 src/assets/tileset.json 路徑下,這犯了 2 個低級錯誤:

  • 認為相對于當前代碼檔案的 ../assets/tileset.json 資料檔案路徑在運行時也能正常讀取
  • 認為 CesiumJS 會幫你處理路徑問題

這點就不說怎么解決了,只求一些新手讀者能了解清楚什么是 “源代碼檔案的相對 URL” 和 “運行時 URL” 這些基本區別,

此處塞一行防爬蟲文字,原文出自 @嶺南燈火,常駐知乎博客園,其余博客社交平臺基本有號,想找原文請勞煩搜索一下~~

5. 教程(原理)正文

與其說是教程,不如說是基于第 2 節的繼續優化,優化到最佳實踐,

5.1. 使用 create-vite 在命令列創建工程

這個參考 2.1 和 2.2 小節即可,

5.2. 指定版本安裝 cesium

指定版本安裝在 2.1 小節有說明,若不指定版本安裝:

pnpm add cesium

那么在 package.json 中,cesium 依賴的版本號(首次 add 時的最新版)前面就會多一個 ^

{
  "dependencies": {
    "cesium": "^1.104.0"  
  }
}

除非手動 update,即 pnpm update cesium@具體版本,否則 ^ 后面的版本號是不會改變的,

那如果不指定版本安裝 cesium 會用哪個版本呢?會用第一次 add 的版本,并且會寫進對應包管理器的鎖檔案中,

  • pnpm 是 pnpm-lock.yaml
  • npm 是 package-lock.json
  • yarn 是 yarn.lock

5.3. 包管理工具鎖檔案的取舍

這小節可以與 5.2 一起看,鎖檔案的作用是把各個依賴包的具體版本鎖死,

有鎖檔案的 package 會從鎖檔案中找版本,否則會按 package.json 中的 “版本要求” 來獲取特定版本,

如果 package.json 中各個依賴包的版本都是確定的,專案負責人也能管理起依賴的版本控制,那么其實可以不需要鎖檔案,

我在本文就配置了 不需要鎖檔案,且我在安裝依賴時明確指定了具體版本(主要是 cesium),

對于 pnpm 和 npm,只需在工程根目錄下創建一個(如果不存在).npmrc 檔案,并寫入此配置:

package-lock=false

對于 yarn,則是創建 .yarnrc 檔案并寫入:

--install.no-lockfile true

如果專案有要求,或者版本管理比較差,我建議還是把鎖檔案留著并提交到 git 記錄中,但是 cesium 的版本,我還是強烈建議確定版本安裝

pnpm add [email protected]

5.4. 使用插件外部化 CesiumJS

原理、原因在 4.2 小節,這里主要講配置,

  • 插件① - rollup-plugin-external-globals

外部化依賴有很多插件都可以實作,既然 Vite4 打包時用的是 rollup,用 rollup-plugin-external-globals 插件就可以完成打包時外部化:

pnpm add rollup-plugin-external-globals -D

然后是用法:

import { defineConfig, splitVendorChunkPlugin } from 'vite'
import vue from '@vitejs/plugin-vue'
import externalGlobals from 'rollup-plugin-external-globals'

export default defineConfig({
  plugins: [vue(), splitVendorChunkPlugin()],
  build: {
    rollupOptions: {
      externalGlobals({
        cesium: 'Cesium'
      }),
    },
  },
})

也可以用 Vite 插件:

  • 插件② - vite-plugin-externals(注意有個 s 結尾)
pnpm add vite-plugin-externals -D

用法:

import { defineConfig, splitVendorChunkPlugin } from 'vite'
import vue from '@vitejs/plugin-vue'
import { viteExternalsPlugin } from 'vite-plugin-externals'

export default defineConfig({
  plugins: [
    vue(),
    splitVendorChunkPlugin(),
    vitePluginExternals({
      // key 是要外部化的依賴名,value 是全域訪問的名稱,這里填寫的是 'Cesium'
      // 意味著外部化后的 cesium 依賴可以通過 window['Cesium'] 訪問;
      // 支持鏈式訪問,參考此插件的檔案
      cesium: 'Cesium',
    })
  ],
})

上面兩個插件任選一個均可,只不過 vite-plugin-externals 在開發模式也會起作用,而 rollup-plugin-external-globals 只會在生產模式(NODE_ENV = production 條件,即構建打包時)對 rollup 起作用,

我選用 vite-plugin-externals 插件,因為它兩種模式都能起作用,再次啟動 pnpm dev,打開瀏覽器發現找不到模塊:

image

這是因為在開發模式也把 CesiumJS 外部化了,找不到很正常,

Vite 啟動后會有一個依賴預構建的程序,打開 node_modules/.vite/deps 目錄,這里就是預構建的各種代碼中匯入的依賴包

在開發模式只需配置一下即可避免外部化,而讓 Vite 把 cesium 依賴預構建:

vitePluginExternals({
  cesium: 'Cesium',
}, {
  disableInServe: true, // 開發模式時不外部化
})

執行 pnpm build 后,提升顯著:

image

但是 pnpm preview 時,依然會找不到從 cesium 依賴匯入的類(注意埠,是 preview 默認的 4173):

image

這是因為外部化 CesiumJS 后,便不再打包 cesium 依賴,所以打包后的應用找不到 CesiumJS 的類和 API 了,

怎么辦呢?

總結一下現在的進度:

  • 創建了 Vue3 + TypeScript 專案,并已經在第 2 節通過手動拷貝的方式把四個靜態資源檔案夾拷貝到 public/libs/cesium/ 目錄下,配置好了 CESIUM_BASE_URL 讓 CesiumJS 能訪問到這些靜態資源,并成功看到了具有離線 TMS 瓦片的三維地球

  • 使用插件完成了打包外部化 CesiumJS,極大提高了打包速度、極大減小了構建產物的體積

那么現在遇到了什么問題?

  • 打包后的頁面因為外部化 cesium 找不到 CesiumJS 庫

如何解決問題?

只需打包時把 CesiumJS 的主庫檔案匯入 index.html 不就行了嗎?請緊接著 5.5 小節一起解決問題:

5.5. 使用插件自動在 index.html 引入 Cesium.js 庫檔案

讀者可以手動把 node_modules/cesium/Build/Cesium/Cesium.js 這個壓縮版的 IIFE 格式庫程式檔案復制到 public/libs/cesium/ 下,然后在工程入口檔案 index.html 中添加一行 script 標簽引入庫檔案:

<head>
  <script src="https://www.cnblogs.com/onsummer/archive/2023/04/09/libs/cesium/Cesium.js"></script>
</head>

但是,如果是自己手動寫這個標簽,執行打包時會收到 Vite 的一句警告:

image

為了解決這個問題,最好的辦法就是在 Vite 的組態檔中,用插件的辦法自動插入這個 script 標簽,

有很多插件可以修改 index.html

  • vite-plugin-html
  • vite-plugin-html-config
  • vite-plugin-insert-html

等等,上述三個插件我都有用過,各有特色,按需選擇,

我這里以 vite-plugin-insert-html 插件為例,在 index.html<head> 標簽下插入這個 script 標簽:

import { defineConfig, splitVendorChunkPlugin } from 'vite'
import vue from '@vitejs/plugin-vue'
import { insertHtml, h } from 'vite-plugin-insert-html'

export default defineConfig({
  plugins: [
    vue(),
    splitVendorChunkPlugin(),
    viteExternalsPlugin({
      cesium: 'Cesium',
    }),
    insertHtml({
      head: [
        h('script', {
          src: 'libs/cesium/Cesium.js'
        })
      ]
    })
  ],
}

這樣打包時就是絕對完美的訊息了:

image

但是到此為止,仍然有兩個需要 “手動” 的事情待解決:

  • 四大靜態檔案的復制
  • CesiumJS 庫檔案的復制

巧的是,這些資源檔案都可以從 cesium 包內拷貝,壓縮版的 node_modules/cesium/Build/Cesium,非壓縮版的 node_modules/cesium/Build/CesiumUnminified,請讀者緊接著看 5.6 小節:

5.6. 四大靜態檔案夾與庫檔案的拷貝(CDN或獨立部署了 CesiumJS 庫可省略此步)

這里需要一些插件或者 nodejs 腳本來做檔案的靜態復制,簡單起見,就拿 Vite 的靜態檔案復制插件完成這個目的,

有很多可選插件,靜態檔案復制的插件在 Webpack 也有,叫作 CopyWebpackPlugin,在 Vite 中我選用 vite-plugin-static-copy 插件:

import { viteStaticCopy } from 'vite-plugin-static-copy'

export default defineConfig({
  plugins: [
    vue(),
    splitVendorChunkPlugin(),
    viteExternalsPlugin({
      cesium: 'Cesium',
    }),
    viteStaticCopy({
      targets: [
        {
          src: 'node_modules/cesium/Build/CesiumUnminified/Cesium.js',
          dest: 'libs/cesium/'
        },
        {
          src: 'node_modules/cesium/Build/CesiumUnminified/Assets/*',
          dest: 'libs/cesium/Assets/'
        },
        {
          src: 'node_modules/cesium/Build/CesiumUnminified/ThirdParty/*',
          dest: 'libs/cesium/ThirdParty/'
        },
        {
          src: 'node_modules/cesium/Build/CesiumUnminified/Workers/*',
          dest: 'libs/cesium/Workers/'
        },
        {
          src: 'node_modules/cesium/Build/CesiumUnminified/Widgets/*',
          dest: 'libs/cesium/Widgets/'
        },
      ]
    }),
    insertHtml({
      head: [
        h('script', {
          src: 'libs/cesium/Cesium.js'
        })
      ]
    }),
  ], // End of plugins
}

這個 target 中很多路徑都是相同的,可以通過陣列計算完成,這里就留給讀者自己改進了,dest 是打包后的根路徑的相對路徑,

無論你見到的哪個教程,只要用的是 node_modules 下的 cesium 依賴,你都能看到這四個靜態檔案夾的復制步驟,

5.7. 額外優化 - 使用環境變數配置 CESIUM_BASE_URL 并適配其它配置

至此我認為工程的配置已經滿足非常靈活地運行了,它滿足了:

  • 無論開發或生產環境,外部化了 CesiumJS,讓 Vite 不再打包 cesium 依賴,大大減少打包時間、減少應用代碼體積(從構建產物中剝離 cesium 庫)

  • 無論開發或生產環境,都 自動復制四個靜態資源檔案夾、自動在 index.html 注入 CesiumJS 庫檔案的 script 標簽以加載 CesiumJS

但是,一旦改用局域網或已經部署好的 CesiumJS 庫(這種情況請自己解決跨域),或者使用 CDN,那么安裝在 node_modules 下的 cesium 其實已經沒有必要走 5.6 的靜態檔案復制了,而且注入 index.html 的主庫檔案需要修改,

我以國內 bootcdn 上的 CesiumJS 為例,既然 Vite 內置了不同環境檔案的決議的函式 loadEnv(參考 Vite 官方檔案 - 使用環境變數),我就分 developmentproduction 簡單講一講,

  • 開發模式(NODE_ENV = development),使用 node_modules 下的 cesium 依賴,復制四個靜態檔案和庫檔案
  • 生產模式(NODE_ENV = production),使用 bootcdn 上的 CDN 鏈接

給出最終的 vite.config.ts(注意,默認匯出改成了函式):

import { defineConfig, type PluginOption, splitVendorChunkPlugin, loadEnv } from 'vite'
import vue from '@vitejs/plugin-vue'
import { viteExternalsPlugin } from 'vite-plugin-externals'
import { insertHtml, h } from 'vite-plugin-insert-html'
import { viteStaticCopy } from 'vite-plugin-static-copy'

export default defineConfig((context) => {
  const mode = context.mode
  const envDir = 'env' // 環境變數檔案的檔案夾,相對于專案的路徑,也可以用 nodejs 函式拼接絕對路徑
  const isProd = mode === 'production'

  const env = loadEnv(mode, envDir)
  const cesiumBaseUrl = env['VITE_CESIUM_BASE_URL']
  // 默認 base 是 '/'
  const base = '/'

  const plugins: PluginOption[] = [
    vue(),
    splitVendorChunkPlugin(),
    viteExternalsPlugin({
      cesium: 'Cesium', // 外部化 cesium 依賴,之后全域訪問形式是 window['Cesium']
    }),
    insertHtml({
      head: [
        // 生產模式使用 CDN 或已部署的 CesiumJS 在線庫鏈接,開發模式用拷貝的庫檔案,根據 VITE_CESIUM_BASE_URL 自動拼接
        h('script', {
          // 因為涉及前端路徑訪問,所以開發模式最好顯式拼接 base 路徑,適配不同 base 路徑的情況
          src: isProd ? `${cesiumBaseUrl}Cesium.js` : `${base}${cesiumBaseUrl}Cesium.js`
        })
      ]
    })
  ]
  if (!isProd) {
    // 開發模式,復制 node_modules 下的 cesium 依賴
    const cesiumLibraryRoot = 'node_modules/cesium/Build/CesiumUnminified/'
    const cesiumLibraryCopyToRootPath = 'libs/cesium/' // 相對于打包后的路徑
    const cesiumStaticSourceCopyOptions = ['Assets', 'ThirdParty', 'Workers', 'Widgets'].map((dirName) => {
      return {
        src: `${cesiumLibraryRoot}${dirName}/*`, // 注意后面的 * 字符,檔案夾全量復制
        dest: `${cesiumLibraryCopyToRootPath}${dirName}`
      }
    })
    plugins.push(
      viteStaticCopy({
        targets: [
          // 主庫檔案,開發時選用非壓縮版的 IIFE 格式主庫檔案
          {
            src: `${cesiumLibraryRoot}Cesium.js`,
            dest: cesiumLibraryCopyToRootPath
          },
          // 四大靜態檔案夾
          ...cesiumStaticSourceCopyOptions
        ]
      }),
    )
  }

  return {
    base,
    envDir,
    mode,
    plugins,
  }
})

為了 ts 能提示 import.meta.env.MODE,需要在 src/vite-env.d.ts 中補充型別定義(參考 Vite 檔案):

/// <reference types="vite/client" />

interface ImportMetaEnv {
  readonly VITE_APP_TITLE: string
  // 更多環境變數...
}

interface ImportMeta {
  readonly env: ImportMetaEnv
}

并且告訴 TypeScript 要用由 vite/client 提供的 import.meta 型別,在 tsconfig.node.jsoncompilerOptions 中添加:

{
  "compilerOptions": {
    "types": ["vite/client"]
  }
}

如果是舊版本的 Vite 創建的模板,你可以添加在 tsconfig.json 對應的位置中,

5.9. 額外優化 - 使用 gzip 預先壓縮打包產物

在服務器上使用 gzip 能進一步提升網路傳輸速度,打包時,使用合適的插件即可預先進行 gzip 打包,我選用的是 vite-plugin-compression 插件:

import compress from 'vite-plugin-compression'

// 使用見插件官方檔案

在開發模式這玩意兒沒起作用,就不細談了,

5.8. 如何共享 CesiumJS 的 Viewer 物件

Vue 有 pinia 這個全域狀態大殺器,可以把核心的 Viewer 物件送入全域狀態中,但是要避免 Vue 的回應式劫持,回應式問題可以通過 Vue3 的 shallowRefshallowReactive 來解決:

<script lang="ts" setup>
import { onMounted, shallowRef, ref } from 'vue'
import { Viewer } from 'cesium'

const viewerDivRef = ref<HTMLDivElement>()
const viewerRef = shallowRef<Viewer>()
onMounted(() => {
  viewerRef.value = https://www.cnblogs.com/onsummer/archive/2023/04/09/new Viewer(viewerDivRef.value as HTMLElement, /* ... */)
})
</script>

或者用 shallowReactive

<script lang="ts" setup>
import { onMounted, shallowReactive, ref } from 'vue'
import { Viewer } from 'cesium'

const viewerDivRef = ref<HTMLDivElement>()
const viewerRef = shallowReactive<{
  viewer: Viewer | null
}>({
  viewer: null
})
onMounted(() => {
  viewerRef.viewer = new Viewer(viewerDivRef.value as HTMLElement, /* ... */)
})
</script>

甚至可以更簡單一些:

<script lang="ts" setup>
import { onMounted, ref } from 'vue'
import { Viewer } from 'cesium'

const viewerDivRef = ref<HTMLDivElement>()
let viewer: Viewer | null = null
onMounted(() => {
  viewer = new Viewer(viewerDivRef.value as HTMLElement, /* ... */)
})
</script>

當然也可以用 Vue 的 provide/inject 函式來下發、注入子組件,僅適用于地圖組件在最頂層的情況:

<!-- 頂層組件下發 Viewer -->
<script lang="ts" setup>
import { onMounted, ref, provide } from 'vue'
import { Viewer } from 'cesium'
import { CESIUM_VIEWER } from '@/symbol'

const viewerDivRef = ref<HTMLDivElement>()
let viewer: Viewer | null = null
onMounted(() => {
  viewer = new Viewer(viewerDivRef.value as HTMLElement, /* ... */)
  provide(CESIUM_VIEWER, viewer)
})
</script>

<!-- 下面是子組件呼叫 -->
<script lang="ts" setup>
import { inject } from 'vue'
import type { Viewer } from 'cesium'
import { CESIUM_VIEWER } from '@/symbol'

const viewer = inject<Viewer>(CESIUM_VIEWER)
</script>

這個 CESIUM_VIEWER 是一個 Symbol,來自 src/symbol/index.ts

export const CESIUM_VIEWER = Symbol('CESIUM_VIEWER')

如果業務界面組件與地圖組件是兄弟組件或父子,那只能用三種方式傳遞 Viewer 物件:

  • defineExpose
  • 層層事件冒泡至父級組件,或者使用全域事件庫(如 mitt)
  • 使用全域狀態 pinia 或 vuex

不再展示代碼,請讀者參考各種途徑的官方檔案來傳遞,注意一定要避免回應式劫持

6. 探究 CesiumJS 等庫的前端組件封裝

這里只是以 Vue 為例講個思路,在其它前端框架中也適用,

6.1. 以 CesiumJS 等庫為主的看板式工程

這種工程有一個特點,就是地圖場景會占滿瀏覽器視窗的全部尺寸,并且不可在高度和寬度上出現滾動條,

一般這種就是“XX系統”的原型,這種工程有什么特點呢?那就是地圖/三維場景幾乎占據絕大多數的功能,大多數時候是浮動在地圖場景上的一些 UI 元素在顯示資料、發生互動,也就是說,切換的其實是一些界面組件,地圖組件幾乎不變,反過來看,界面組件大多數時候反而還要去訪問地圖核心物件,像 CesiumJS 是 Viewer,OpenLayers 是 Map 等,

我的建議是,所有業務界面組件應該作為地圖組件的 子組件,在 Vue 中,就有 slot 的設計,

結合前端路由,還能跟隨路由切換(RouteView 也應作為 slot 撰寫在地圖組件中) ,

地圖組件作為最頂層的組件,可以結合前端組件的生命周期特點,當核心物件創建完成后,才通過條件渲染把子組件打開,在 Vue 中利用 provide/inject 實作地圖核心物件的下發和注入,在 React 中使用 useContext 下發也是類似的,

6.2. 后臺管理系統式工程

這種通常是表單的資料通過組件的 props 下傳給地圖,單一地顯示上級操作接收來的資料,這種地圖組件設計就比較簡單,只需設計好 props 的資料結構,在組件掛載時創建核心物件并顯示接收到的資料即可,

7. 示例工程下載

留了兩個版本,讀者可以自己在壓縮包中找自己滿意的,一個是第 2 節的最簡單的,讓 Vite 打包 CesiumJS 的版本,做了分 chunk;另一個則是經過第 5 節完整配置后、具備各種注釋和細節,供讀者自己改造學習的版本,

微云鏈接

轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/549536.html

標籤:其他

上一篇:教程 - 在 Vue3+Ts 中引入 CesiumJS 的最佳實踐@2023

下一篇:精靈圖

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • IEEE1588PTP在數字化變電站時鐘同步方面的應用

    IEEE1588ptp在數字化變電站時鐘同步方面的應用 京準電子科技官微——ahjzsz 一、電力系統時間同步基本概況 隨著對IEC 61850標準研究的不斷深入,國內外學者提出基于IEC61850通信標準體系建設數字化變電站的發展思路。數字化變電站與常規變電站的顯著區別在于程序層傳統的電流/電壓互 ......

    uj5u.com 2020-09-10 03:51:52 more
  • HTTP request smuggling CL.TE

    CL.TE 簡介 前端通過Content-Length處理請求,通過反向代理或者負載均衡將請求轉發到后端,后端Transfer-Encoding優先級較高,以TE處理請求造成安全問題。 檢測 發送如下資料包 POST / HTTP/1.1 Host: ac391f7e1e9af821806e890 ......

    uj5u.com 2020-09-10 03:52:11 more
  • 網路滲透資料大全單——漏洞庫篇

    網路滲透資料大全單——漏洞庫篇漏洞庫 NVD ——美國國家漏洞庫 →http://nvd.nist.gov/。 CERT ——美國國家應急回應中心 →https://www.us-cert.gov/ OSVDB ——開源漏洞庫 →http://osvdb.org Bugtraq ——賽門鐵克 →ht ......

    uj5u.com 2020-09-10 03:52:15 more
  • 京準講述NTP時鐘服務器應用及原理

    京準講述NTP時鐘服務器應用及原理京準講述NTP時鐘服務器應用及原理 安徽京準電子科技官微——ahjzsz 北斗授時原理 授時是指接識訓通過某種方式獲得本地時間與北斗標準時間的鐘差,然后調整本地時鐘使時差控制在一定的精度范圍內。 衛星導航系統通常由三部分組成:導航授時衛星、地面檢測校正維護系統和用戶 ......

    uj5u.com 2020-09-10 03:52:25 more
  • 利用北斗衛星系統設計NTP網路時間服務器

    利用北斗衛星系統設計NTP網路時間服務器 利用北斗衛星系統設計NTP網路時間服務器 安徽京準電子科技官微——ahjzsz 概述 NTP網路時間服務器是一款支持NTP和SNTP網路時間同步協議,高精度、大容量、高品質的高科技時鐘產品。 NTP網路時間服務器設備采用冗余架構設計,高精度時鐘直接來源于北斗 ......

    uj5u.com 2020-09-10 03:52:35 more
  • 詳細解讀電力系統各種對時方式

    詳細解讀電力系統各種對時方式 詳細解讀電力系統各種對時方式 安徽京準電子科技官微——ahjzsz,更多資料請添加VX 衛星同步時鐘是我京準公司開發研制的應用衛星授時時技術的標準時間顯示和發送的裝置,該裝置以M國全球定位系統(GLOBAL POSITIONING SYSTEM,縮寫為GPS)或者我國北 ......

    uj5u.com 2020-09-10 03:52:45 more
  • 如何保證外包團隊接入企業內網安全

    不管企業規模的大小,只要企業想省錢,那么企業的某些服務就一定會采用外包的形式,然而看似美好又經濟的策略,其實也有不好的一面。下面我通過安全的角度來聊聊使用外包團的安全隱患問題。 先看看什么服務會使用外包的,最常見的就是話務/客服這種需要大量重復性、無技術性的服務,或者是一些銷售外包、特殊的職能外包等 ......

    uj5u.com 2020-09-10 03:52:57 more
  • PHP漏洞之【整型數字型SQL注入】

    0x01 什么是SQL注入 SQL是一種注入攻擊,通過前端帶入后端資料庫進行惡意的SQL陳述句查詢。 0x02 SQL整型注入原理 SQL注入一般發生在動態網站URL地址里,當然也會發生在其它地發,如登錄框等等也會存在注入,只要是和資料庫打交道的地方都有可能存在。 如這里http://192.168. ......

    uj5u.com 2020-09-10 03:55:40 more
  • [GXYCTF2019]禁止套娃

    git泄露獲取原始碼 使用GET傳參,引數為exp 經過三層過濾執行 第一層過濾偽協議,第二層過濾帶引數的函式,第三層過濾一些函式 preg_replace('/[a-z,_]+\((?R)?\)/', NULL, $_GET['exp'] (?R)參考當前正則運算式,相當于匹配函式里的引數 因此傳遞 ......

    uj5u.com 2020-09-10 03:56:07 more
  • 等保2.0實施流程

    流程 結論 ......

    uj5u.com 2020-09-10 03:56:16 more
最新发布
  • 使用Django Rest framework搭建Blog

    在前面的Blog例子中我們使用的是GraphQL, 雖然GraphQL的使用處于上升趨勢,但是Rest API還是使用的更廣泛一些. 所以還是決定回到傳統的rest api framework上來, Django rest framework的官網上給了一個很好用的QuickStart, 我參考Qu ......

    uj5u.com 2023-04-20 08:17:54 more
  • 記錄-new Date() 我忍你很久了!

    這里給大家分享我在網上總結出來的一些知識,希望對大家有所幫助 大家平時在開發的時候有沒被new Date()折磨過?就是它的諸多怪異的設定讓你每每用的時候,都可能不小心踩坑。造成程式意外出錯,卻一下子找不到問題出處,那叫一個煩透了…… 下面,我就列舉它的“四宗罪”及應用思考 可惡的四宗罪 1. Sa ......

    uj5u.com 2023-04-20 08:17:47 more
  • 使用Vue.js實作文字跑馬燈效果

    實作文字跑馬燈效果,首先用到 substring()截取 和 setInterval計時器 clearInterval()清除計時器 效果如下: 實作代碼如下: <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta ......

    uj5u.com 2023-04-20 08:12:31 more
  • JavaScript 運算子

    JavaScript 運算子/運算子 在 JavaScript 中,有一些運算子可以使代碼更簡潔、易讀和高效。以下是一些常見的運算子: 1、可選鏈運算子(optional chaining operator) ?.是可選鏈運算子(optional chaining operator)。?. 可選鏈操 ......

    uj5u.com 2023-04-20 08:02:25 more
  • CSS—相對單位rem

    一、概述 rem是一個相對長度單位,它的單位長度取決于根標簽html的字體尺寸。rem即root em的意思,中文翻譯為根em。瀏覽器的文本尺寸一般默認為16px,即默認情況下: 1rem = 16px rem布局原理:根據CSS媒體查詢功能,更改根標簽的字體尺寸,實作rem單位隨螢屏尺寸的變化,如 ......

    uj5u.com 2023-04-20 08:02:21 more
  • 我的第一個NPM包:panghu-planebattle-esm(胖虎飛機大戰)使用說明

    好家伙,我的包終于開發完啦 歡迎使用胖虎的飛機大戰包!! 為你的主頁添加色彩 這是一個有趣的網頁小游戲包,使用canvas和js開發 使用ES6模塊化開發 效果圖如下: (覺得圖片太sb的可以自己改) 代碼已開源!! Git: https://gitee.com/tang-and-han-dynas ......

    uj5u.com 2023-04-20 08:01:50 more
  • 如何在 vue3 中使用 jsx/tsx?

    我們都知道,通常情況下我們使用 vue 大多都是用的 SFC(Signle File Component)單檔案組件模式,即一個組件就是一個檔案,但其實 Vue 也是支持使用 JSX 來撰寫組件的。這里不討論 SFC 和 JSX 的好壞,這個仁者見仁智者見智。本篇文章旨在帶領大家快速了解和使用 Vu ......

    uj5u.com 2023-04-20 08:01:37 more
  • 【Vue2.x原始碼系列06】計算屬性computed原理

    本章目標:計算屬性是如何實作的?計算屬性快取原理以及洋蔥模型的應用?在初始化Vue實體時,我們會給每個計算屬性都創建一個對應watcher,我們稱之為計算屬性watcher ......

    uj5u.com 2023-04-20 08:01:31 more
  • http1.1與http2.0

    一、http是什么 通俗來講,http就是計算機通過網路進行通信的規則,是一個基于請求與回應,無狀態的,應用層協議。常用于TCP/IP協議傳輸資料。目前任何終端之間任何一種通信方式都必須按Http協議進行,否則無法連接。tcp(三次握手,四次揮手)。 請求與回應:客戶端請求、服務端回應資料。 無狀態 ......

    uj5u.com 2023-04-20 08:01:10 more
  • http1.1與http2.0

    一、http是什么 通俗來講,http就是計算機通過網路進行通信的規則,是一個基于請求與回應,無狀態的,應用層協議。常用于TCP/IP協議傳輸資料。目前任何終端之間任何一種通信方式都必須按Http協議進行,否則無法連接。tcp(三次握手,四次揮手)。 請求與回應:客戶端請求、服務端回應資料。 無狀態 ......

    uj5u.com 2023-04-20 08:00:32 more