前言
最近vue3+vite项目需求是只把网站的图片打包发布到CDN。因为用到的是七牛云CDN,相关的文章内容寥寥无几。下面说说关于实现的过程,以及踩的一些坑。
开整
前期调研
看了一些别人的实现的过程,都是通过七牛云的node.js SDK 实现,主要思路是通过自己写一个脚本,遍历打包目录下的各个文件利用七牛云的node.js SDK进行上传。写完后自己还得写一个执行脚本命令,在vite打包完之后去执行(感兴趣的可以通过传送门去了解)。看起来就有点繁琐的样子的,那有没有更方便快捷的方式呢?既然webpack都有相关的插件,vite应该也会有的吧。带着疑惑又是一通查找各种资料,果然还是有的!
这个插件支持上传到七牛云和aws,并且重复刷新上传和增量更新,看起来就非常nice!哒!哒!哒!一顿操作猛如虎。嘿嘿嘿,果然上传到七牛云CDN了,而且已经存在的图片也不会重复上传。针不戳!给这个插件的作者加个鸡腿!
主要是配置以下内容
js
import qiniu from 'qiniu';
import { qiniuPlugin } from '@puhaha/vite-plugin-upload-oss'
const qiniuConfig = {
sdk: qiniu,
accessKey: '',
secretKey: '',
bucket: '', // 七牛空间名
filePath: './dist/assets/images', // 本地文件夹路径
remoteFilePath: 'imageassets/', // 七牛cdn服务器的文件夹路径,不写就七牛云那边就没有,但是图片都会以imageassets+数字命名的
uploadTarget: "./dist/assets/images", // 打包生成的目录地址,需手动填写path.resolve(__dirname, './dist')
openConfirm: false, // 是否打开上传前的提示
publicCdnPath: '', // cdn基础地址
enabledRefresh: true, //是否刷新文件
excludeHtml: true //是否排除html文件上传
}
export default defineConfig({
plugins: [
qiniuPlugin(qiniuConfig),
]
})
然而,问题来了。上传完之后我的图片的引用路径咋改?那么多图片,CV工程师一把摔掉手中的键盘,不干了。哈哈哈,开玩笑的,还是得干。
一开始到看到是别人通过build的在 beforeWrite.writeBundle 函数中,使用 glob 包获取构建后的文件列表,遍历文件列表,查找并替换所有引用的图片路径(传送门),但是这种似乎不适合我。因为项目的图片引用乱七八糟的,没有办法实现准确的路径替换。
也尝试过通过手写一个插件在vite的transform(src, id)阶段进行文件路径替换,但是这个方式打包出来后的项目运行图片获取会报错。而且如果是只有几十字节的图片并没有打包上传到七牛但是路径全部替换完了,因此有些小图片在七牛没有对应的图片不会显示出来。 通过查找在vite官网看到以下内容
小于4KB的图片都被内联了,因此为了能正常显示,我手动设置了
js
build: {
assetsInlineLimit: 0, // 打包禁止内联
}
我想有没有直接替换路径的插件,结果发现还真的有一个。 vite-plugin-replace-image-url,但是这个插件似乎不太完善,用的时候它只能替换到设置的文件夹下的图片,文件夹子目录中的文件无法实现替换,查看了他了的源码,发现它用的是vite的createFilter来实现include文件的查找的,似乎看起俩也没啥毛病,但是就是只能替换当前目录的图片。算了,放弃这个方案了。
最后,敲重点!!!找到一位兄弟分享的方案(传送门),但他对于这段代码的解释我觉得真的不太对,不应该说是部署,应该是替换部署图片的引用路径。可能也是我的理解问题,一开始他的方案不行我就丢一边去了,后面需要替换CDN部署图片的路径的时候回头看发现这才是正解。简单又方便,美滋滋!在vite官网在进阶基础路径选项即可看到关于CDN的路径替换说明。好哇,原来藏得这么深,我找到你找的好苦哇!测试了一下上面关于打包限制的会被内联的问题,使用这个方案也不需要担心,内联的图片可以正常展示。
js
// vite.config.js
// https://vitejs.dev/config/
export default defineConfig({
//......其他配置
build: {
rollupOptions: {
output: {
assetFileNames: (chunkInfo) => {
// 用后缀名称进行区别处理
// 处理其他资源文件名 e.g. css png 等
if (
chunkInfo.name?.endsWith('.webp') ||
chunkInfo.name?.endsWith('.png') ||
chunkInfo.name?.endsWith('.jpg') ||
chunkInfo.name?.endsWith('.gif')
) {
return `assets/images/[name].[ext]`; // 图片通通打包到dist/assets/images下
}
return `assets/[name].[hash].[ext]`;
},
},
},
},
experimental: {
renderBuiltUrl(filename: string) {
if (
filename.endsWith('.webp') ||
filename.endsWith('.png') ||
filename.endsWith('.jpg') ||
filename.endsWith('.gif')
) {
const name = filename.replace('assets/images/', ''); //获取dist/assets/images下图片文件名
return `https://cdnURL/images/${name}`;
}
return filename;
},
},
})
完结,撒花✿✿✿,真是一次酣畅淋漓的学习!
总结
兜兜转转一圈,才发现官网啥都写了,只是个人没有相关的知识储备,才兜了一个大圈,vite的官网还是需要细细研究。