使用Parcel打包时导入MP3文件返回空对象的问题排查
问题:Parcel打包环境下MP3文件预加载返回空对象的排查与解决
我正在为JavaScript应用实现启动前预加载所有文件的加载页(包含12个MP3文件和5个PNG文件),使用Parcel作为打包工具。之前通过index.html结合选择器加载MP3一切正常,但现在改为在model.js中导入并预加载时,图片加载正常,MP3文件却返回空对象,导致预加载流程卡住。
相关代码如下:
model.js
import favicon from "../img/favicon.png" import css3 from "../img/css3.png" import html5 from "../img/html5.png" import javascript from "../img/javascript.png" import github from "../img/github.png" import blobBtn from "../audio/blobBtn.mp3" import closeBtn from "../audio/closeBtn.mp3" import correctAnswer from "../audio/correctAnswer.mp3" import correctUsername from "../audio/correctUsername.mp3" import deleteRecord from "../audio/deleteRecord.mp3" import emptyUsername from "../audio/emptyUsername.mp3" import gameOver from "../audio/gameOver.mp3" import navBtns from "../audio/navBtns.mp3" import preferencesBtns from "../audio/preferencesBtns.mp3" import restart from "../audio/restart.mp3" import startQuiz from "../audio/startQuiz.mp3" import wrongAnswer from "../audio/wrongAnswer.mp3" export const files ={ audioFiles: [ blobBtn, closeBtn, correctAnswer, correctUsername, deleteRecord, emptyUsername, gameOver, navBtns, preferencesBtns, restart, startQuiz, wrongAnswer, ], imageFiles: [ favicon, css3, html5, javascript, github ], loadedFiles: 0, totalFiles: 0, }
controller.js
const loadFiles = async function() { try { await Promise.all([...model.files.audioFiles, ...model.files.imageFiles].map(loadFile)); console.log('All files are loaded'); // 因audioFiles是空对象数组,此代码无法执行 filesLoaded(); } catch (error) { console.error("There was an error loading the files:", error); } } const loadFile = async function(file) { return new Promise((resolve) => { console.log(file); // 图片正常,MP3显示为空对象 const fileType = file.includes(".mp3") ? "audio" : "image"; const element = fileType === "audio" ? new Audio() : new Image(); element.onload = element.oncanplaythrough = resolve; element.src = file; }); }; const filesLoaded = function() { loadingView.hideWindow(); welcomeView.showWindow(); welcomeView.startHandlers(controlUsername, controlFromWelcomeToPreferences); } const init = function() { model.totalFiles = model.files.audioFiles.length + model.files.imageFiles.length; loadingView.showWindow(); loadingView.renderData() loadFiles() /* loadingView.simulateLoading() */ }()
问题根源
Parcel对音频文件的默认导入逻辑与图片不同:图片文件导入时会直接返回处理后的资源URL,而音频文件默认会被Parcel当作需要特殊处理的资源,导入后返回空对象,导致你的预加载代码无法获取有效文件路径。
解决办法
方法1:使用url:前缀强制返回资源URL
修改model.js中所有MP3文件的导入语句,在路径前添加url:前缀,告诉Parcel将该音频文件视为静态资源并返回其URL:
import blobBtn from "url:../audio/blobBtn.mp3" import closeBtn from "url:../audio/closeBtn.mp3" import correctAnswer from "url:../audio/correctAnswer.mp3" // 其余MP3文件导入同理修改
方法2:全局配置Parcel资源处理规则
如果不想逐个修改导入语句,可以在项目的package.json中添加Parcel配置,指定音频文件的处理方式:
{ "name": "your-project-name", "parcel": { "assets": ["**/*.mp3"] } }
该配置会让Parcel将所有MP3文件当作静态资源处理,导入时直接返回URL。
额外优化建议
为避免音频加载失败时Promise一直处于pending状态,建议在loadFile函数中添加错误处理:
const loadFile = async function(file) { return new Promise((resolve, reject) => { console.log(file); const fileType = file.includes(".mp3") ? "audio" : "image"; const element = fileType === "audio" ? new Audio() : new Image(); element.onload = element.oncanplaythrough = resolve; element.onerror = reject; // 添加错误回调,捕获加载失败情况 element.src = file; }); };
内容的提问来源于stack exchange,提问作者Andrea de Martinis
相关产品推荐
相关产品推荐

