CDN面纱:
CDN是Content Delivery Network的缩写,即内容分发网络。它是一种基于互联网的分布式服务,旨在加快网站内容的加载速度,提升用户访问网站的体验。CDN通过在全球多个地区部署缓存服务器节点,当用户访问网站时,CDN系统会根据用户的地理位置、网络状况以及各节点的负载情况,将用户请求重定向到离用户最近或者响应最快的服务器节点上,从而减少网络延迟并提高内容加载速度。
—— 解释来自通义千问
CDN没用过(没有操作配置和登录管理控制台)的人感觉很神秘,用过的人感觉很简单。
最开始接触CDN是在上家单位,2014年H5非常火爆,可以上下滑动、左右滑动,有炫酷的动画效果,可以开发3D效果,火的一塌糊涂,也是前端在互联网世界崛起的时候。
H5页面是在手机上显示,为了提高用户体验,采取了图片压缩,js、css文件压缩等,学习了前端性能优化之雅虎35条军规。
单位为了通过H5来推广公司业务,也是花了大价钱购入CDN服务,当时每个月还是要几十个W,当时想想真赚钱啊~~
我所要做的操作的就是把开发的静态文件上传到服务器上指定的目录,代码或图片更新后,要登录CDN管理控制台上点击“清理”的按钮。然后,说的最多的一句话就是"清理浏览器缓存再试下"。
Vue配置CDN:
vue3官网上给出了在vue3中使用CDN的方法启用Import maps:
<script type="importmap">
{
"imports": {
"vue": "https://unpkg.com/vue@3/dist/vue.esm-browser.js"
}
}
</script>
<div id="app">{{ message }}</div>
<script type="module">
import { createApp, ref } from 'vue'
createApp({
setup() {
const message = ref('Hello Vue!')
return {
message
}
}
}).mount('#app')
</script>
需要注意:
1. <script>标签的type属性定义为"importmap"来开启
2. 配置中引入Vue的CDN的版本需要根据构建后的代码模块规范来确定,本实例使用的是支持esm的vue版本
问题:
1. import maps功能在vue工程中如何使用?
import maps功能实际上是浏览器默认支持的功能,可以在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</title>
<script type="importmap">
{
"imports": {
"vue": "https://unpkg.com/vue@3/dist/vue.esm-browser.js",
"axios":"https://cdnjs.cloudflare.com/ajax/libs/axios/1.7.2/esm/axios.js"
}
}
</script>
</head>
<body>
<div id="app"></div>
<script type="module" src="/src/main.js"></script>
</body>
</html>
然而,这种方式在npm run dev运行过程中会存在问题:
在app.vue中导入axios(也在main.js中导入了vue),然后导入vue没报错,导入axios却报错了。
解决办法:
1.本地安装vue和axios
2.build.rollupOptions.external添加axios和vue
rollupOptions:{
external:[
'axios','vue'
],
},
这样做的目的是在研发环境环境用的是本地安装的,生产打包用CDN。external是为了生产打包不要把本地的vue和axios依赖构建进去。这样问题完美解决,亲测本地运行没问题,生产打包axios也不会被打包进构建包里。
Vite配置CDN
vite配置CDN的方法在vite的官方网站里并没有给出具体的说明,也没有说明使用哪个插件。
但是社区里推荐的是:vite-plugin-cdn-import
vite-plugin-cdn-import插件:
npm上查找该插件,插件版本是0.3.5版本(1.0.1版本有问题,构建的包会报异常,用最新版本vite重新搭建还会报缺少vue的报错),具体配置如下:
export default defineConfig({
plugins: [vue(),
splitVendorChunkPlugin(),
importToCDN({
modules:[
autoComplete('vue'),
autoComplete('axios')
]
})
],
build:{
rollupOptions:{
external:[
'axios','vue'
],
},
sourcemap:true
},
resolve:{
alias:{
'@': path.join(__dirname,'src')
}
}
})
问题:
同样会报axios加载异常:
解决方案同上 ,本地安装vue和axios,构建编译external排除本地依赖。
总结:
1. 学习官方文档一定不要死记硬背,多动手练习
2. vite-plugin-cdn-import V1.0.1 最新版本存在很多问题,在这里投入了比较多的时间查看文档和验证。当然也是有收获的,比如,在解决问题过程中,通过查看各种文档来解决,练习这种繁琐的解决思路:
a. 根据官方说明进行操作,构建后cdn的引入放在index.html的<script>标签里,但是缺少type="module",因为我构建后的代码支持ES Module。但是官方文档提供一个方法:
generateScriptTag?: (
name: string,
scriptUrl: string,
) => Omit<HtmlTagDescriptor, 'tag' | 'children'>
这段代码是TypeScript定义的函数类型。该方法可以自定义在index.html里的<script>。
Omit<HtmlTagDescriptor, 'tag' | 'children'>的意思是返回值的类型是没有tag和children的HtmlTagDescriptor类型。而HtmlTagDescriptor又是vite里的定制类型接口。通过在代码里输入import {HtmlTagDescriptor} from 'vite' 然后ctrl+点击HtmlTagDescriptor,可以跳转类型接口定义的位置:
interface HtmlTagDescriptor {
tag: string;
attrs?: Record<string, string | boolean | undefined>;
children?: string | HtmlTagDescriptor[];
/**
* default: 'head-prepend'
*/
injectTo?: 'head' | 'body' | 'head-prepend' | 'body-prepend';
}
其中,injectTo的值有四个,‘head-prepend’ 表示放在最前面,这样cdn顺序的问题又可以解决。 vite-plugin-cdn-import V1.0.1版本的vite.config.js配置如下,定义了generateScriptTag函数:
import { defineConfig} from 'vite'
import vue from '@vitejs/plugin-vue'
import cdn from 'vite-plugin-cdn-import'
import path from 'path'
import {HtmlTagDescriptor} from 'vite'
// https://vitejs.dev/config/
export default defineConfig({
plugins: [
vue(),
cdn({
modules: [
{
name: 'vue',
var: 'vue',
path: `https://unpkg.com/vue@3/dist/vue.esm-browser.prod.js`,
},
{
name: 'axios',
var: 'axios',
path: `https://cdnjs.cloudflare.com/ajax/libs/axios/1.7.2/axios.min.js`,
},
],
generateScriptTag(name,scriptUrl){
return {
attrs: {
rel: 'stylesheet',
href: scriptUrl,
type:'module'
},
injectTo: 'head-prepend',
};
}
})
],
build:{
target:"modules",
rollupOptions:{
external:[
'axios','vue'
],
},
sourcemap:'inline'
},
resolve:{
alias:{
'@': path.join(__dirname,'src')
}
}
})
但结果还是报错,页面显示空:
Uncaught ReferenceError: vue is not defined
at u (vue.svg:1:16)
at vue.svg:1:16
虽然,最终使用vite-plugin-cdn-import V1.0.1的验证没有通过,而且投了比较多的时间。但是还是有收获的。