vite+vue3+ts搭建項目八(打包性能優(yōu)化三:使用CDN)
使用vite-plugin-cdn-import
下載npm包
官方github:https://github.com/MMF-FE/vite-plugin-cdn-import
npm install vite-plugin-cdn-import --save-dev
開發(fā)環(huán)境使用本地的npm包,cdn是打包時候才生效
在vite.config.ts中通過importToCDN引入
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import { autoComplete, Plugin as importToCDN } from "vite-plugin-cdn-import";
import { visualizer } from 'rollup-plugin-visualizer';
// https://vitejs.dev/config/
export default defineConfig({
plugins: [
vue(),
importToCDN({
// prodUrl: 'https://cdn.jsdelivr.net/npm/{name}@{version}/{path}',
modules: [
{
name: 'vue',
var: 'Vue',
path: `https://unpkg.com/vue@3.2.45/dist/vue.global.js`,
},
{
name: 'vue-demi',
var: 'VueDemi',
path: `https://unpkg.com/vue-demi@0.13.11`,
},
{
name: 'vue-router',
var: 'VueRouter',
path: `https://unpkg.com/vue-router@4.1.6`,
},
{
name: 'element-plus',
var: 'ElementPlus',
path: 'https://unpkg.com/element-plus@2.3.3/dist/index.full.js',
// css: 'https://unpkg.com/element-plus@2.3.3/dist/index.css'
},
],
}),
],
// build: {
// rollupOptions: {
// external: ['vue', 'vue-demi', 'element-plus'],
// },
// }
})
注意事項:網(wǎng)上很多教程,還需要在build
的rollupOptions
添加對應(yīng)的external
,如上注釋所示,其實是不需要的,vite-plugin-cdn-import
插件會自動幫我們完成這部分工作。
CDN參數(shù)獲取方式
-
name:npm包的名稱
可以到https://www.jsdelivr.com進行查詢,以element-plus為例
-
var:組件(main.ts)引用的名稱
比如ElementPlus
import ElementPlus from 'element-plus' app.use(ElementPlus)
-
path:cdn網(wǎng)站存儲對應(yīng)的js地址
輸入對應(yīng)名稱,會自動跳轉(zhuǎn)到對應(yīng)的js文件,復(fù)制粘貼,需要修改版本,和自己項目的package.json版本一致允許只寫到版本,后面會自動補齊
{ name: 'vue-demi', var: 'VueDemi', path: `https://unpkg.com/vue-demi@0.13.11`, },
-
css:對應(yīng)位置,參考上圖element-plus
需要注意的是,css可以使用本地的,使用本地的就不要添加css,使用遠程cdn的就需要在打包前注釋本地的,否則會出現(xiàn)樣式重疊。
可用的CDN網(wǎng)址
name | pordUrl |
---|---|
jsdelivr | https://cdn.jsdelivr.net/npm/vue@3.2.47/dist/vue.global.min.js(例子) |
unpkg | //unpkg.com/{name}@{version}/{path} |
cdnjs | //cdnjs.cloudflare.com/ajax/libs/{name}/{version}/{path} |
打包并運行
-
打包后
dist/index.html
中自動添加了cdn鏈接 -
打包后放到nginx中運行,查看對應(yīng)依賴的加載地址
-
打包后查看包體積
例如element-plus,已經(jīng)被排除在外了
報錯整理
- 報錯
TypeError: importToCDN is not a function
- 解決方法,修改import引入方式
官方issues:https://github.com/MMF-FE/vite-plugin-cdn-import/issues/22// import importToCDN from "vite-plugin-cdn-import"; import { autoComplete, Plugin as importToCDN } from "vite-plugin-cdn-import";
- 報錯
Uncaught TypeError: Cannot read properties of undefined (reading 'createElementVNode')
可以看到代碼里用到了vue - 解決:將vue也通過cdn引入即可
- 報錯
Uncaught ReferenceError: Vue is not defined
vue-router或某些組件需要依賴vue - 解決:將vue也通過cdn引入即可
-
報錯
Uncaught TypeError: Failed to resolve module specifier "vue". Relative references must start with either "/", "./", or "../".
參考1:https://github.com/MMF-FE/vite-plugin-cdn-import/issues/13
參考2:https://github.com/MMF-FE/vite-plugin-cdn-import/issues/32
參考3:https://blog.csdn.net/qq_51634332/article/details/126325740 -
解決:importToCDN時在引入vue后添加vue-demi,已在vite.config.ts中給出,其他插件在vue-demi之后(順序很重要)
-
vite-plugin-cdn-import
與unplugin-vue-components
和unplugin-auto-import
不兼容
參考:https://github.com/MMF-FE/vite-plugin-cdn-import/issues/13#issuecomment-1226897835
使用importToCDN時,通過下面兩個插件的組件不生效,需要在每個組件單獨寫importimport AutoImport from "unplugin-auto-import/vite" import Components from 'unplugin-vue-components/vite';
- 原因
之所以使用 AutoImport 后就會有問題,是因為 unplugin-auto-import 的 enforce 為 post ,會最后才執(zhí)行,導(dǎo)致通過 AutoImport 的注入的代碼沒有被此插件轉(zhuǎn)換 - 解決方法
目前只能暫時不同時使用這兩組插件,所以如果使用自動引入插件,這個插件不是最佳答案
直接按照下面這張方法是不行的,在vite.config.ts文件中,為importToCDN添加...擴展符
,讓它在其他所有插件之后再加載
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import { autoComplete, Plugin as importToCDN } from "vite-plugin-cdn-import";
import { visualizer } from 'rollup-plugin-visualizer';
import AutoImport from "unplugin-auto-import/vite"
import Components from 'unplugin-vue-components/vite';
export default defineConfig({
plugins: [
vue(),
AutoImport({
imports: ['vue', 'vue-router'],
dts: "src/auto-import.d.ts",
}),
Components({
//默認(rèn)存放位置
//dts: "src/components.d.ts",
}),
{
...importToCDN({
// prodUrl: 'https://cdn.jsdelivr.net/npm/{name}@{version}/{path}',
modules: [
{
name: 'vue',
var: 'Vue',
path: `https://unpkg.com/vue@3.2.45/dist/vue.global.js`,
},
...
],
}),
enforce: 'post',
apply: 'build',
},
],
// build: {
// outDir: 'dist', // 指定輸出路徑
// // minify: 'terser', // 混淆器,terser 構(gòu)建后文件體積更小,'terser' | 'esbuild' ,默認(rèn)為esbuild
// rollupOptions: {
// external: ['vue', 'vue-demi', 'element-plus'],
// },
// }
})
使用rollup-plugin-external-globals(推薦)
為了解決上面的問題,externalGlobals是可以用上面的方法延遲加載的
參考1:https://github.com/ttk-cli/vue3-template/tree/test/cdn1
參考2:https://free_pan.gitee.io/freepan-blog
下載npm包
npm install -D rollup-plugin-external-globals
在vite.config.ts中引入
- 允許設(shè)置延遲加載
- rollupOptions需要設(shè)置external
import externalGlobals from 'rollup-plugin-external-globals'
const externalGlobalsObj = {
vue: 'Vue',
'vue-demi': 'VueDemi',
'vue-router': 'VueRouter',
'element-plus': 'ElementPlus',
}
export default defineConfig({
plugins: [
vue(),
{
...externalGlobals(externalGlobalsObj),
enforce: 'post',
apply: 'build',
},
],
build: {
outDir: 'dist', // 指定輸出路徑
rollupOptions: {
external: Object.keys(externalGlobalsObj),
},
}
})
手動在打包后的index添加CDN
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Vite + Vue + TS</title>
<script src="https://unpkg.com/vue@3.2.45/dist/vue.global.js"></script>
<script src="https://unpkg.com/vue-demi@0.13.11"></script>
<script src="https://unpkg.com/vue-router@4.1.6"></script>
<script src="https://unpkg.com/element-plus@2.3.3/dist/index.full.js"></script>
<script type="module" crossorigin src="/assets/index-c24c670c.js"></script>
<link rel="stylesheet" href="/assets/index-f757e912.css">
</head>
<body>
<div id="app"></div>
</body>
</html>
自動添加CDN
需要用到vite-plugin-html
插件
github官方:https://github.com/vbenjs/vite-plugin-html
參考:https://segmentfault.com/q/1010000041958028
- 安裝
npm i vite-plugin-html -D
- 在vite.config.ts中引入(完整配置文件內(nèi)容)
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import { autoComplete, Plugin as importToCDN } from "vite-plugin-cdn-import";
import { visualizer } from 'rollup-plugin-visualizer';
// 自動導(dǎo)入vue中hook reactive ref等
import AutoImport from "unplugin-auto-import/vite"
// 自動導(dǎo)入ui-組件 比如說ant-design-vue element-plus等
import Components from 'unplugin-vue-components/vite';
import externalGlobals from 'rollup-plugin-external-globals'
import { createHtmlPlugin } from 'vite-plugin-html'
const cdn = {
css: [],
js: [
'https://unpkg.com/vue@3.2.45/dist/vue.global.js',
'https://unpkg.com/vue-demi@0.13.11',
'https://unpkg.com/vue-router@4.1.6',
'https://unpkg.com/element-plus@2.3.3/dist/index.full.js',
],
}
const externalGlobalsObj = {
vue: 'Vue',
'vue-demi': 'VueDemi',
'vue-router': 'VueRouter',
// pinia: 'Pinia',
'element-plus': 'ElementPlus',
}
// https://vitejs.dev/config/
export default defineConfig(({ mode }) => {
const isProduction = mode === 'production';
return {
plugins: [
vue(),
AutoImport({
//安裝兩行后,在組件中不用再導(dǎo)入ref,reactive等
imports: ['vue', 'vue-router'],
dts: "src/auto-import.d.ts",
//element
}),
Components({
//element
//默認(rèn)存放位置
//dts: "src/components.d.ts",
}),
visualizer({
open: true, //注意這里要設(shè)置為true,否則無效
gzipSize: true, //從源代碼中收集 gzip 大小并將其顯示在圖表中
brotliSize: true, //從源代碼中收集 brotli 大小并將其顯示在圖表中
emitFile: true, //在打包完的dist,否則在項目目錄下
filename: "stats.html", //分析圖生成的文件名
}),
createHtmlPlugin({
inject: {
data: {
cdnCss: isProduction ? cdn.css : [],
cdnJs: isProduction ? cdn.js : [],
},
},
}),
{
...externalGlobals(externalGlobalsObj),
enforce: 'post',
apply: 'build',
},
],
build: {
outDir: 'dist', // 指定輸出路徑
// minify: 'terser', // 混淆器,terser 構(gòu)建后文件體積更小,'terser' | 'esbuild' ,默認(rèn)為esbuild
rollupOptions: {
external: Object.keys(externalGlobalsObj),
},
}
}
})
-
在 index.html 中增加 EJS 標(biāo)簽
需要注意的是:這個index.html不是打包后的,是項目的入口index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Vite + Vue + TS</title>
<!-- 使用CDN的CSS文件 -->
<% for (const i of cdnCss) { %>
<link href="<%= i %>" rel="stylesheet" />
<% } %>
<!-- 使用CDN的JS文件 -->
<% for (const i of cdnJs) { %>
<script src="<%= i %>" defer></script>
<% } %>
</head>
<body>
<div id="app"></div>
<script type="module" src="/src/main.ts"></script>
</body>
</html>
環(huán)境變量:https://www.cnblogs.com/yayuya/p/17035869.html
- 打包后的結(jié)果

這樣就不需要手動引入了,但是需要添加一個新的npm包,實際項目中可以自行選擇是否添加
element-plus相關(guān)問題
使用cdn引入需要全局引入,不要使用AutoImport的按需引入,否則最后生成的包仍然會有本地的element-plus.js
按需引入和CDN只能選擇其一進行打包優(yōu)化
使用CDN則不使用resolvers: [ElementPlusResolver()]
,在main.ts全局引入element-plus即可
AutoImport({
//安裝兩行后,在組件中不用再導(dǎo)入ref,reactive等
imports: ['vue', 'vue-router'],
dts: "src/auto-import.d.ts",
//element
// resolvers: [ElementPlusResolver()],
}),
Components({
//element
//默認(rèn)存放位置
//dts: "src/components.d.ts",
// resolvers: [ElementPlusResolver()],
}),
import 'element-plus/dist/index.css'
import ElementPlus from 'element-plus'
app.use(ElementPlus)
使用CDN未必會加快速度,只能減小打包體積,因為對應(yīng)js和css需要從遠程地址讀取文章來源:http://www.zghlxwxcb.cn/news/detail-432962.html
原文鏈接:http://guohaonan1.github.io/2023/04/12/vite-vue3-ts搭建項目八(打包性能優(yōu)化三:使用CDN)/文章來源地址http://www.zghlxwxcb.cn/news/detail-432962.html
到了這里,關(guān)于vite+vue3+ts搭建項目八(打包性能優(yōu)化三:使用CDN)的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!