8.5 KiB
8.5 KiB
HBuilderX小程序编译错误解决方案
错误信息
[vite]: Rollup failed to resolve import "@dcloudio/uni-ui/lib/uni-button/uni-button.vue" from "components/MsgTips/MsgTips.vue".
[@vue/compiler-sfc] `defineExpose` is a compiler macro and no longer needs to be imported.
[@vue/compiler-sfc] `defineProps` is a compiler macro and no longer needs to be imported.
[@vue/compiler-sfc] `defineEmits` is a compiler macro and no longer needs to be imported.
问题分析
问题1:uni-button 组件未安装
原因:
uni-button
不是 uni-app 的内置组件- 项目中使用了
<uni-button>
但没有安装@dcloudio/uni-ui
完整包 - 只安装了部分组件(uni-popup、uni-icons等)
解决方案:
使用原生 <button>
替代 <uni-button>
问题2:Vue编译器宏错误导入
原因:
defineProps
、defineEmits
、defineExpose
是 Vue 3 的编译器宏- 它们由编译器自动注入,不需要从 vue 中导入
- 在
<script setup>
中可以直接使用
错误写法:
import { defineProps, defineEmits, defineExpose } from 'vue'
正确写法:
// 无需导入,直接使用
const props = defineProps({...})
const emit = defineEmits([...])
defineExpose({...})
✅ 已修复的文件
1. components/MsgTips/MsgTips.vue
修改内容:
- ✅ 将
<uni-button>
替换为<button>
- ✅ 添加了 button 样式重置
修改前:
<uni-button class="popup-button" @click="close">确定</uni-button>
修改后:
<button class="popup-button" @click="close">确定</button>
样式重置:
button {
padding: 0;
margin: 0;
border: none;
background: none;
font-size: inherit;
line-height: inherit;
}
button::after {
border: none;
}
2. pages/chat/components/ai-paging.vue
修改内容:
- ✅ 移除
defineProps
和defineEmits
的导入
修改前:
import {
ref,
defineProps,
defineEmits,
// ...
} from 'vue';
修改后:
import {
ref,
// 移除了 defineProps 和 defineEmits
// ...
} from 'vue';
3. components/tabbar/midell-box.vue
修改内容:
- ✅ 移除
defineProps
的导入
4. pages/chat/components/popupbadFeeback.vue
修改内容:
- ✅ 移除
defineEmits
的导入
5. components/selectJobs/selectJobs.vue
修改内容:
- ✅ 移除
defineExpose
的导入
6. components/renderJobs/renderJobsCheckBox.vue
修改内容:
- ✅ 移除
defineExpose
的导入
📋 Vue 3 Composition API 编译器宏
什么是编译器宏?
编译器宏是 Vue 3 在 <script setup>
中提供的特殊函数,由编译器在编译时处理,不是运行时的函数。
常用编译器宏
宏名称 | 作用 | 是否需要导入 |
---|---|---|
defineProps |
定义组件 props | ❌ 不需要 |
defineEmits |
定义组件事件 | ❌ 不需要 |
defineExpose |
暴露组件方法/属性 | ❌ 不需要 |
withDefaults |
为 props 设置默认值 | ❌ 不需要 |
defineOptions |
定义组件选项 | ❌ 不需要 |
defineSlots |
定义插槽类型 | ❌ 不需要 |
defineModel |
定义 v-model | ❌ 不需要 |
正确使用示例
<script setup>
// ✅ 正确:直接使用,无需导入
const props = defineProps({
name: String,
age: Number
})
const emit = defineEmits(['update', 'change'])
defineExpose({
open,
close
})
// ❌ 错误:不要从 vue 导入
// import { defineProps } from 'vue'
</script>
🔧 替代方案
如果确实需要 uni-ui
如果项目中大量使用了 uni-ui 组件,可以安装完整的 uni-ui:
npm install @dcloudio/uni-ui
然后在 pages.json
中配置:
{
"easycom": {
"autoscan": true,
"custom": {
"^uni-(.*)": "@dcloudio/uni-ui/lib/uni-$1/uni-$1.vue"
}
}
}
使用原生组件的优势
- ✅ 更小的包体积 - 不需要引入额外的库
- ✅ 更好的兼容性 - 原生组件在所有平台都可用
- ✅ 更快的编译速度 - 减少依赖解析
- ✅ 更灵活的样式 - 可以完全自定义
🎯 button vs uni-button 对比
原生 button
<button class="custom-btn" @click="handleClick">
点击我
</button>
<style>
.custom-btn {
width: 100%;
height: 80rpx;
background: #256BFA;
color: white;
border-radius: 12rpx;
border: none;
}
button::after {
border: none; /* 移除默认边框 */
}
</style>
优点:
- ✅ 无需安装依赖
- ✅ 完全自定义样式
- ✅ 支持所有平台
- ✅ 性能更好
缺点:
- ⚠️ 需要手动重置样式
- ⚠️ 需要自己实现 loading、disabled 等状态
uni-button
<uni-button type="primary" @click="handleClick">
点击我
</uni-button>
优点:
- ✅ 内置多种样式
- ✅ 自带 loading、disabled 状态
- ✅ 统一的UI风格
缺点:
- ❌ 需要安装 uni-ui
- ❌ 增加包体积
- ❌ 自定义样式受限
📝 button 样式重置模板
推荐在全局样式中添加 button 重置:
/* App.vue 或 common.css */
/* 重置 button 默认样式 */
button {
padding: 0;
margin: 0;
border: none;
background: none;
font-size: inherit;
font-family: inherit;
color: inherit;
line-height: inherit;
text-align: inherit;
cursor: pointer;
box-sizing: border-box;
}
/* 移除微信小程序 button 的默认边框 */
button::after {
border: none;
}
/* 移除 button 按下时的背景色 */
button:active {
background-color: inherit;
}
/* 通用按钮样式 */
.btn {
display: inline-block;
padding: 20rpx 40rpx;
border-radius: 12rpx;
text-align: center;
transition: all 0.3s;
}
.btn-primary {
background: linear-gradient(135deg, #13C57C 0%, #0FA368 100%);
color: #FFFFFF;
box-shadow: 0 8rpx 20rpx rgba(19, 197, 124, 0.3);
}
.btn-secondary {
background: #F7F8FA;
color: #666666;
}
⚠️ 注意事项
1. 编译器宏的特殊性
// ❌ 错误:不能解构或重命名
import { defineProps as props } from 'vue'
// ❌ 错误:不能在条件语句中使用
if (someCondition) {
defineProps({...})
}
// ✅ 正确:直接在顶层使用
const props = defineProps({...})
2. TypeScript 支持
如果使用 TypeScript,编译器宏会自动获得类型支持:
<script setup lang="ts">
// 自动获得类型提示
const props = defineProps<{
name: string
age?: number
}>()
const emit = defineEmits<{
update: [value: string]
change: [id: number]
}>()
</script>
3. 在非 setup 语法中
如果不使用 <script setup>
,需要用传统方式:
<script>
export default {
props: {
name: String
},
emits: ['update'],
setup(props, { emit, expose }) {
// ...
expose({ open, close })
}
}
</script>
✅ 验证修复
修复后,重新编译项目应该看到:
- ✅ 没有 "Rollup failed to resolve import" 错误
- ✅ 没有 "defineXxx is a compiler macro" 警告
- ✅ 小程序正常编译和运行
- ✅ 按钮样式显示正常
🔍 排查步骤
如果修复后仍然有问题:
1. 清除缓存
HBuilderX:
运行 → 停止运行
工具 → 清除缓存
重新运行
2. 检查所有文件
使用全局搜索检查是否还有遗漏:
Ctrl + Shift + F
搜索: import.*defineProps
搜索: import.*defineEmits
搜索: import.*defineExpose
3. 检查 pages.json
确保 easycom 配置正确:
{
"easycom": {
"autoscan": true,
"custom": {
"^uni-(.*)": "@dcloudio/uni-ui/lib/uni-$1/uni-$1.vue"
}
}
}
4. 重新安装依赖
# 删除 node_modules 和 lock 文件
rm -rf node_modules
rm package-lock.json
# 重新安装
npm install
📚 相关文档
🎉 总结
问题
- 使用了未安装的
uni-button
组件 - 错误地从 vue 导入了编译器宏
解决
- ✅ 将
<uni-button>
替换为<button>
- ✅ 移除所有编译器宏的 import 语句
- ✅ 添加 button 样式重置
最佳实践
- 优先使用原生组件
- 不要导入 Vue 编译器宏
- 保持依赖简洁
- 定期清理未使用的代码
所有错误已修复! 🎉
现在可以正常编译和运行小程序了。