skip to content
LOGO CLUE
目录

项目背景

在使用 UniApp + TypeScript + Vue 3 开发微信小程序时,我尝试集成 MQTT 协议用于消息传递。但在编译与真机调试过程中,遇到了模块加载和连接异常等一系列问题。以下是我的问题定位与解决思路,希望能帮助到遇到类似困扰的开发者。


一、问题描述

1. 编译时报错

app.js错误:
Error: module 'common/xtend.js' is not defined, require args is 'xtend'
at q (WASubContext.js?t=wechat&s=1745889438316&v=3.8.2:1)
at n (WASubContext.js?t=wechat&s=1745889438316&v=3.8.2:1)
at vendor.js:31
at WASubContext.js?t=wechat&s=1745889438316&v=3.8.2:1
at _.runWith (WASubContext.js?t=wechat&s=1745889438316&v=3.8.2:1)
at q (WASubContext.js?t=wechat&s=1745889438316&v=3.8.2:1)
at n (WASubContext.js?t=wechat&s=1745889438316&v=3.8.2:1)
at app.js:7
at WASubContext.js?t=wechat&s=1745889438316&v=3.8.2:1
at _.runWith (WASubContext.js?t=wechat&s=1745889438316&v=3.8.2:1)(env: Windows,mp,1.06.2412050; lib: 3.8.2)

原因:微信小程序编译环境未能识别 mqtt 包内的部分依赖,导致加载失败。

2. TypeScript 类型缺失

import mqtt from 'mqtt/dist/mqtt.min.js'

此处改为引入压缩版 SDK,但编译时报错:

无法找到模块 “mqtt/dist/mqtt.min.js” 的声明文件。

3. 真机调试无法连接

  • 在微信开发者工具模拟环境中,MQTT 连接正常。
  • 切换至真机调试时,控制台显示 Provisional headers are shown,请求未真正发出。

二、原因分析

  1. 模块依赖未打包 直接 import mqtt from 'mqtt' 会将原始代码及其所有依赖导入,但微信小程序打包器无法处理部分文件,导致编译错误。

  2. 类型声明缺失 引用压缩包 mqtt/dist/mqtt.min.js 后,TypeScript 无对应 .d.ts 文件,因而报缺少类型声明。

  3. 文件上传过滤 微信开发者工具默认会 过滤“无依赖” 文件,打包时将 mqtt.min.js 误判为无依赖文件,因而未上传至真机,导致连接失败。


三、解决方案

1. 引入压缩版 SDK

在小程序中引用:

import mqtt from 'mqtt/dist/mqtt.min.js';

相较于原始包,压缩版不含无法解析的模块引入,能正常编译。

2. 增加类型声明

在项目 src/types 文件夹下新建 mqtt.d.ts,内容示例:

declare module 'mqtt/dist/mqtt.min.js' {
export class MqttClient {
constructor(url: string, options?: object);
connect(options?: object): Promise<void>;
subscribe(topic: string, options?: object): Promise<void>;
publish(topic: string, message: string, options?: object): void;
end(force?: boolean): void;
on(event: string, callback: (...args: any[]) => void): void;
}
export function connect(url: string, options?: object): MqttClient;
}

这样即可消除 TypeScript 编译时报“找不到声明文件”的错误。

3. 关闭文件过滤

在微信开发者工具 “详情” 面板内,取消勾选:

上传时过滤无依赖文件

此项取消后,mqtt.min.js 可随同小程序包一起上传,真机调试时即可正常建立 MQTT 连接。


四、示例代码

以下为简化的 index.vue 示例,演示连接与订阅流程:

<template>
<view class="content">
<button @click="connect">连接</button>
<button @click="subscribe">订阅</button>
</view>
</template>
<script setup lang="ts">
import { ref } from 'vue';
// 引入压缩版 SDK
import mqtt from 'mqtt/dist/mqtt.min.js';
const client = ref<any>(null);
// 连接 MQTT
const connect = () => {
client.value = mqtt.connect('wxs://127.0.0.1:8083/mqtt', {
clientId: 'mqttwx_' + Math.random().toString(16).slice(2),
clean: true,
connectTimeout: 4000,
username: 'test',
password: 'test',
});
client.value.on('connect', () => {
uni.showToast({ title: '连接成功', icon: 'success', duration: 2000 });
console.log('连接成功');
});
client.value.on('error', (err: any) => {
uni.showToast({ title: '连接失败', icon: 'none', duration: 2000 });
console.error('连接错误:', err);
});
};
// 订阅主题
const subscribe = () => {
if (!client.value) {
return console.error('MQTT 客户端未连接');
}
client.value.subscribe('/publish/zk_topic/24587c8f92ec', { qos: 1 }, (err: any, granted: any) => {
if (err) return console.error('订阅失败:', err);
console.log('订阅成功:', granted);
});
client.value.on('message', (topic: string, message: Uint8Array) => {
console.log('收到消息:', topic, JSON.parse(message.toString()));
});
};
</script>

五、总结

  1. 使用压缩版 SDK (mqtt/dist/mqtt.min.js),避免编译环境识别问题;
  2. 自定义类型声明,解决 TypeScript 编译报错;
  3. 关闭“上传时过滤无依赖文件”,确保真机环境也能加载 MQTT 库。

通过以上三步,成功消除了模块加载与真机连接障碍,使得 UniApp 小程序中的 MQTT 通信能够稳定运行。希望本文能为您的开发带来帮助,节省调试时间。