javascript技巧

关注公众号 jb51net

关闭
首页 > 网络编程 > JavaScript > javascript技巧 > SSR下Nuxt2引入Gif.js

Nuxt2引入Gif.js与SSR环境下部署遇到的问题解决

作者:咕咕一

gif.js是一个纯JavaScript实现的GIF编码器,专门设计用于在浏览器环境中将图像序列转换为动态GIF,这篇文章主要介绍了Nuxt2引入Gif.js与SSR环境下部署遇到问题的解决办法,文中通过代码介绍的非常详细,需要的朋友可以参考下

一 背景需求

基于 gif.js 库实现的客户端 GIF 生成工具。负责将 360 度的产品序列图合成单产品GIF和多产品GIF。

核心技术栈

1. Canvas API (2D Context) :

export function drawFrame(ctx, img, backgroundColor, bgImg, maxWidth = GIF_WIDTH, maxHeight = GIF_HEIGHT) {// 绘制单帧图片
	ctx.fillStyle = backgroundColor || '#ffffff'
	ctx.fillRect(0, 0, maxWidth, maxHeight)

	if (bgImg) {
		ctx.drawImage(bgImg, 0, 0, maxWidth, maxHeight)// 绘制背景图
	}

	const { drawWidth, drawHeight, offsetX, offsetY } = calculateDrawParams(img, maxWidth, maxHeight)
	ctx.drawImage(img, offsetX, offsetY, drawWidth, drawHeight)// 绘制当前帧图片	
}
for (let i = 0; i < orderedImgs.length; i++) {
		const img = orderedImgs[i]
		const canvas = document.createElement('canvas')
		canvas.width = GIF_WIDTH
		canvas.height = GIF_HEIGHT
		const ctx = canvas.getContext('2d')

		drawFrame(ctx, img, backgroundColor, bgImg)
		// 直接获取 ImageData 数据并传递给 gif.js,避免 canvas 引用带来的潜在问题
		const imageData = ctx.getImageData(0, 0, GIF_WIDTH, GIF_HEIGHT)
		gif.addFrame(imageData, { delay: adjustedDelay })
		console.log(`添加第${i + 1}帧成功`)
}

2. Web Workers (LZW 编码) :

3. 动态资源加载 (Dynamic Script/Import) :

// 辅助函数:根据当前页面路径自动探测并返回可能的本地资源路径
function getPossibleLocalPaths(fileRelativePath) {
	if (typeof window === 'undefined') return [fileRelativePath];// 服务端环境直接返回相对路径

	const origin = window.location.origin;// 获取当前页面的域名,例如 https://www.xxx.com
	const pathname = window.location.pathname; // 获取当前页面的路径名
	const segments = pathname.split('/').filter(Boolean); 

	const paths = [
		origin + fileRelativePath, // 1. 绝对根路径: /worker/gif.js
	];

	// 2. 逐级向上探测路径 (解决子目录部署问题)
	let currentBase = origin;
	for (const segment of segments) {
		currentBase += '/' + segment;
		paths.push(currentBase + fileRelativePath);
	}

	// 3. 相对路径 (针对当前深层路由的情况)
	paths.push('.' + fileRelativePath);
	paths.push('..' + fileRelativePath);
	paths.push('../../' + fileRelativePath);
	paths.push('../../../' + fileRelativePath);

	// 去重并返回
	return Array.from(new Set(paths));
}

4. 并发控制与采样优化 :

export function calculateFrameParams(totalFrames, maxFrames = GIF_MAX_FRAMES) {
	const frames = Math.min(maxFrames, totalFrames)
	const step = Math.ceil(totalFrames / frames)
	const frameCount = Math.ceil(totalFrames / step) 
	return { frames, step, frameCount }// 返回实际生成的帧数、步长和总帧数
}

二、 解决的关键问题

1. 部署路径与 404 故障排查

gif.js和gif.worker.js放到static/worker,部署上去就无法合成gif, 经过排查发现测试服务该目录下gif.js始终不存在

原因:

如何证明与解决?

方案1:验证文件是否存在,直接在浏览器地址栏输入: 域名/worker/gif.js 。

方案2:gif.js放到assets/js

将 JS 文件放入 assets 还是 static 文件夹,在 Nuxt/Webpack 项目中有着本质的区别,特别是对于 gif.js 这种涉及 Web Worker 的库

1. 编译冲突(Babel 报错)

gif.js 和 gif.worker.js 是已经经过高度压缩和混淆的二进制/生产级代码。

2. Web Worker 的路径限制**

gif.js 的工作原理是启动一个独立的浏览器线程(Worker):

2. Nuxt SSR 兼容性 ( navigator is not defined )

针对方案2:

// 动态导入 gif.js,避免 SSR 时 navigator is not defined
const GIFModule = await import('@/assets/js/gif.js');
// 排除 assets/js 目录下已经压缩过的库文件,防止编译报错 
build: {
  babel: {
    exclude: [
      /[\\/]assets[\\/]js[\\/]gif\.js/
    ]
  }
}

3. 跨域安全限制 (CORS & Tainted Canvas)

4. 图像加载鲁棒性

export async function ImagetryLoad(src, maxAttempts = 3) {
	if (typeof window === 'undefined') return null

	for (let attempt = 1; attempt <= maxAttempts; attempt++) {
		const url = attempt === 1 ? src : `${src}${src.includes('?') ? '&' : '?'}_r=${Date.now()}_${attempt}` // 避免缓存问题
		try {
			const img = await new Promise((resolve, reject) => {
				const i = new Image()
				i.crossOrigin = 'anonymous' // 跨域加载图片
				i.onload = () => {
					if (i.naturalWidth > 0 && i.naturalHeight > 0) resolve(i)
					else reject(new Error('invalid image'))
				}
				i.onerror = () => reject(new Error('load error'))
				i.src = url
			})
			return img
		} catch (e) {}
	}
	return null
}

三、 潜在风险与优化点

到此这篇关于Nuxt2引入Gif.js与SSR环境下部署遇到的问题解决的文章就介绍到这了,更多相关SSR下Nuxt2引入Gif.js内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
阅读全文