Files
soul-yongping/.cursor/skills/kbone-miniprogram/troubleshooting.md
2026-02-03 19:17:05 +08:00

838 lines
18 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Kbone 常见问题排查指南
## 从 Next 项目迁移到小程序
**先读**:本技能 `SKILL.md` 中的「Next 项目 → 小程序 最优转化方式」章节。
**要点**
-**newpp** 为 Kbone 构建源,**miniprogram** 为壳,构建后合并产物。
- 必须做 **适配层**`env``request``storage``router`;功能开关与 Next 一致,用同一 API`/api/db/config``features.matchEnabled`)。
- **UI**:在 newpp 内复制并适配 Next 的页面/组件,或通过 webpack alias 引用根目录共享组件(无 Next 专属 API
- **配置**`miniprogram.config.js` 每页单独 router、**不配原生 tabBar**`webpack.mp.config.js``isOptimize = process.env.NODE_ENV === 'production'`,中小型项目建议 `splitChunks: false`
- **底部菜单**Web 端多为自定义底部菜单组件(主页面统一引入、有显隐逻辑),**不要**转为小程序原生 tabBar保留「主页面引入统一菜单组件」显隐与跳转与 Web 一致,跳转用 `wx.reLaunch`
- **样式**Grid 改 Flex`boxSizing`/`lineHeight`;不支持特性用兼容写法或替代。
遇到具体报错时,在下方「配置问题」「编译问题」「运行时问题」「样式问题」中按类型排查。
---
## 配置问题
### 1. redirect 用了不存在的页面名
**现象**:配置了 `redirect.notFound: 'home'``redirect.accessDenied: 'home'`,但 router 里没有名为 `home` 的页面。
**后果**404 或无权时Kbone 可能无法正确跳转到首页。
**解决**redirect 必须使用 **router 里存在的 key**。首页通常是 `index`,不要写 `home`
```javascript
// ❌ 错误
redirect: { notFound: 'home', accessDenied: 'home' }
// ✅ 正确
redirect: { notFound: 'index', accessDenied: 'index' }
```
---
## 编译问题
### 0. Node 17+ OpenSSL 错误ERR_OSSL_EVP_UNSUPPORTED
**错误信息**
```
Error: error:0308010C:digital envelope routines::unsupported
code: 'ERR_OSSL_EVP_UNSUPPORTED'
```
**原因**Node.js 17+ 使用 OpenSSL 3.0,旧版 webpack如 4.x依赖的 MD4 等算法被移出默认提供,导致构建时报错。
**解决方案**
**方案 1在 newpp 的 package.json 脚本中加 NODE_OPTIONS**(推荐)
```json
"scripts": {
"web": "cross-env NODE_OPTIONS=--openssl-legacy-provider NODE_ENV=development webpack-dev-server ...",
"mp": "rimraf dist/mp/common && cross-env NODE_OPTIONS=--openssl-legacy-provider NODE_ENV=development webpack ...",
"build:mp": "rimraf dist/mp/common && cross-env NODE_OPTIONS=--openssl-legacy-provider NODE_ENV=production webpack ..."
}
```
**方案 2当前终端临时设置后再运行**
- Windows PowerShell`$env:NODE_OPTIONS="--openssl-legacy-provider"; cd newpp; npm run web`
- Windows CMD`set NODE_OPTIONS=--openssl-legacy-provider && cd newpp && npm run web`
- Linux/macOS`NODE_OPTIONS=--openssl-legacy-provider npm run web`
**方案 3**:使用 Node.js 16.xLTS运行 newpp 构建,避免 OpenSSL 3.0。
---
### 1. chunk 文件缺失错误
**错误信息**
```
Error: ENOENT: no such file or directory, open 'E:/path/to/default~chapters~index~my.js'
```
**原因**
- Webpack 代码分割splitChunks生成了动态命名的 chunk 文件
- 小程序环境下,动态 chunk 路径可能不稳定
**解决方案**
**方案 1完全禁用代码分割**(推荐中小型项目)
```javascript
// webpack.mp.config.js
optimization: {
runtimeChunk: false,
splitChunks: false, // 完全禁用
}
```
**方案 2固定 chunk 命名**(大型项目)
```javascript
optimization: {
runtimeChunk: false,
splitChunks: {
chunks: 'all',
name: true, // 使用固定命名
cacheGroups: {
vendors: {
name: 'vendors',
test: /[\\/]node_modules[\\/]/,
priority: 10,
},
default: {
name: 'common',
minChunks: 2,
priority: 5,
},
},
},
}
```
**选择建议**
- 项目 <20 页面方案 1稳定性优先
- 项目 >50 页面:方案 2体积优化优先
---
### 2. Babel 编译错误
**错误信息**
```
SyntaxError: Unexpected token ...
```
或具体到某列:`Unexpected token (45:64)`(多为可选链位置)
**原因**
- Babel 配置不正确
- 使用了 Babel 6stage-3不支持的语法**可选链 `?.`、空值合并 `??`**(属 ES2020
- 其他小程序不支持的 ES6+ 语法
**解决方案**
**若为可选链 / 空值合并**(最常见):
```javascript
// ❌ Babel 6 会报错
res.content?.length
x ?? 'default'
// ✅ 兼容写法
(res.content && res.content.length) || 0
x != null ? x : 'default'
```
**Babel 配置**.babelrc 或 babel.config.js
```javascript
{
"presets": [
["env", {
"targets": {
"browsers": ["> 1%", "last 2 versions", "not ie <= 8"]
}
}],
"react",
"stage-3"
],
"plugins": [
"transform-runtime"
]
}
```
---
### 3. 依赖包报错
**错误信息**
```
Module not found: Can't resolve 'xxx'
```
**排查步骤**
1. **检查依赖是否安装**
```bash
npm list [package-name]
```
2. **重新安装依赖**
```bash
rm -rf node_modules package-lock.json
npm install
```
3. **检查 webpack resolve 配置**
```javascript
resolve: {
extensions: ['*', '.js', '.jsx', '.json'],
alias: {
'@': path.resolve(__dirname, 'src'),
},
}
```
---
## 运行时问题
### 0. TypeError: eval is not a function
**错误信息**
```
TypeError: eval is not a function
at Object../src/index.jsx (index.js?...)
```
**原因**`npm run mp` 使用 development 模式时webpack 默认 `devtool: 'eval'`,会注入使用 `eval()` 的代码;小程序环境**不支持** `eval`,因此报错。
**解决方案**:在 **webpack.mp.config.js** 中显式关闭 devtool
```javascript
module.exports = {
mode: process.env.NODE_ENV === 'production' ? 'production' : 'development',
devtool: false, // 小程序环境不支持 eval必须关闭
entry: { ... },
// ...
}
```
重新执行 `npm run mp``npm run build:mp` 后,再在微信开发者工具中预览即可。
---
### 1. URLSearchParams 未定义
**错误信息**
```
ReferenceError: URLSearchParams is not defined
```
**原因**:小程序环境不支持 `URLSearchParams`
**解决方案**
```javascript
// 自定义实现
function buildQueryString(params) {
const parts = []
for (const [key, value] of Object.entries(params)) {
if (value !== undefined && value !== null) {
parts.push(`${encodeURIComponent(key)}=${encodeURIComponent(value)}`)
}
}
return parts.join('&')
}
// 使用示例
const queryString = buildQueryString({
page: 1,
limit: 10,
keyword: '搜索'
})
// 结果: "page=1&limit=10&keyword=%E6%90%9C%E7%B4%A2"
```
---
### 2. localStorage 未定义
**错误信息**
```
ReferenceError: localStorage is not defined
```
**原因**:小程序环境使用 `wx.storage` 而不是 `localStorage`
**解决方案**
```javascript
// adapters/storage.js
function isMiniProgram() {
return typeof wx !== 'undefined' && wx.getSystemInfoSync
}
export const storage = {
get(key) {
if (isMiniProgram()) {
return wx.getStorageSync(key)
} else {
const value = localStorage.getItem(key)
try {
return JSON.parse(value)
} catch {
return value
}
}
},
set(key, value) {
if (isMiniProgram()) {
wx.setStorageSync(key, value)
} else {
localStorage.setItem(key, JSON.stringify(value))
}
},
remove(key) {
if (isMiniProgram()) {
wx.removeStorageSync(key)
} else {
localStorage.removeItem(key)
}
},
clear() {
if (isMiniProgram()) {
wx.clearStorageSync()
} else {
localStorage.clear()
}
},
}
```
---
### 3. window 对象未定义
**错误信息**
```
ReferenceError: window is not defined
```
**原因**:小程序环境没有 `window` 对象
**解决方案**
```javascript
// 环境判断
function isMiniProgram() {
return typeof wx !== 'undefined' && wx.getSystemInfoSync
}
// 使用示例
if (!isMiniProgram()) {
window.addEventListener('resize', handleResize)
}
// 或使用可选链
window?.addEventListener?.('resize', handleResize)
```
---
### 4. document 对象未定义
**错误信息**
```
ReferenceError: document is not defined
```
**原因**:小程序环境没有 `document` 对象
**解决方案**
```javascript
// ❌ 不要直接使用 document
const title = document.title
// ✅ 使用 React 特性
import { useEffect } from 'react'
function MyComponent() {
useEffect(() => {
if (!isMiniProgram()) {
document.title = 'My Page'
} else {
// 小程序使用 wx.setNavigationBarTitle
wx.setNavigationBarTitle({
title: 'My Page'
})
}
}, [])
}
```
---
## 样式问题
### 1. CSS Grid 不生效
**问题描述**:使用 CSS Grid 布局在小程序中显示错乱
**原因**:小程序对 CSS Grid 支持不完整
**解决方案**
```javascript
// ❌ 避免使用 Grid
const badStyles = {
container: {
display: 'grid',
gridTemplateColumns: 'repeat(4, 1fr)',
gap: '10px',
}
}
// ✅ 使用 Flexbox
const goodStyles = {
container: {
display: 'flex',
flexDirection: 'row',
flexWrap: 'wrap',
boxSizing: 'border-box',
},
item: {
flex: '0 0 25%', // 相当于 4 列
boxSizing: 'border-box',
padding: '5px',
}
}
```
---
### 2. 盒模型计算错误
**问题描述**元素尺寸计算不正确padding/border 撑大元素
**原因**:未设置 `box-sizing: border-box`
**解决方案**
```javascript
// ✅ 所有容器都添加 boxSizing
const styles = {
container: {
width: '100%',
padding: '10px',
boxSizing: 'border-box', // 重要!
},
item: {
width: '50%',
border: '1px solid #ccc',
boxSizing: 'border-box', // 重要!
}
}
```
---
### 3. 文字垂直居中问题
**问题描述**:文字没有垂直居中
**原因**:未设置 `line-height`
**解决方案**
```javascript
const styles = {
button: {
height: '44px',
lineHeight: '44px', // 与 height 相同
textAlign: 'center',
},
text: {
lineHeight: '1.5', // 或使用相对值
}
}
```
---
### 4. 标题/头部被胶囊或电池栏遮挡
**问题描述**:自定义导航栏时,标题、返回按钮被右上角胶囊或顶部状态栏遮挡。
**原因**:未预留顶部安全区高度和右侧胶囊留白。
**解决方案**
1. **顶部安全区**:在 `app.js``onLaunch` 中计算并写入 `globalData`
- `statusBarHeight = wx.getSystemInfoSync().statusBarHeight || 44`
- `navBarHeight`:用 `wx.getMenuButtonBoundingClientRect()` 计算 `menuButton.bottom + menuButton.top - statusBarHeight`,无菜单时用 `statusBarHeight + 44`
- `capsulePaddingRight = systemInfo.windowWidth - menuButton.left + 10`
2. **页面占位**:顶部占位条高度设为 `{{ navBarHeight }}px`,内容区 `padding-top: {{ statusBarHeight }}px`;页面 `onLoad`/`onShow``getApp().globalData` 取上述值写入 `data`
3. **标题右侧留白**:头部容器加类 `.safe-header-right { padding-right: 200rpx; box-sizing: border-box; }`,或内联 `padding-right: {{ capsulePaddingRight }}px`,避免标题与胶囊重叠。
详见本目录 `reference.md` 第 7 节「安全区与标题/胶囊避让」。
---
### 5. Flexbox 间距问题
**问题描述**Flexbox 子元素间距不均匀
**解决方案**
```javascript
// 方案 1使用 gap注意兼容性
const styles = {
container: {
display: 'flex',
gap: '10px', // 可能不支持
}
}
// 方案 2使用 margin推荐
const styles = {
container: {
display: 'flex',
margin: '-5px', // 负边距抵消子元素边距
},
item: {
margin: '5px',
}
}
// 方案 3使用伪元素
// CSS: .item:not(:last-child) { margin-right: 10px; }
```
---
## 路由问题
### 1. 页面跳转无效
**问题描述**:点击导航无反应
**排查步骤**
1. **检查 router 配置**
```javascript
// miniprogram.config.js
router: {
index: ['/', '/index.html'],
my: ['/my', '/my.html'], // 确保配置了目标页面
}
```
2. **检查路由适配器**
```javascript
// adapters/router.js
export function navigateTo(path) {
if (isMiniProgram()) {
wx.navigateTo({
url: toMpPath(path),
fail: (err) => console.error('导航失败:', err)
})
} else {
window.location.href = path
}
}
```
3. **检查页面是否存在**
```bash
# 确保入口文件存在
ls src/my.jsx
```
---
### 2. switchTab 报错
**错误信息**
```
navigateTo:fail can not navigateTo a tabbar page
```
**原因**:使用 `wx.navigateTo` 跳转 tabBar 页面
**解决方案**
```javascript
// ❌ 错误
wx.navigateTo({ url: '/pages/index/index' })
// ✅ 正确
wx.switchTab({ url: '/pages/index/index' })
// 或使用 wx.reLaunch不依赖 tabBar 配置)
wx.reLaunch({ url: '/pages/index/index' })
```
---
### 3. 动态路由参数丢失
**问题描述**`/read/:id` 中的 `id` 获取不到
**解决方案**
```javascript
// 小程序环境
if (isMiniProgram()) {
// 从页面 options 获取
const pages = getCurrentPages()
const currentPage = pages[pages.length - 1]
const { id } = currentPage.options
}
// Web 环境
else {
// 从 URL 解析
const pathParts = window.location.pathname.split('/')
const id = pathParts[pathParts.length - 1]
// 或使用 React Router
import { useParams } from 'react-router-dom'
const { id } = useParams()
}
```
---
## 网络问题
### 1. API 请求失败
**错误信息**
```
request:fail url not in domain list
```
**原因**:小程序要求配置服务器域名白名单
**解决方案**
1. **小程序管理后台配置**
- 登录小程序管理后台
- 开发 > 开发设置 > 服务器域名
- 添加你的 API 域名
2. **开发阶段临时方案**
- 微信开发者工具 > 右上角详情
- 勾选"不校验合法域名"
3. **使用代理**
```javascript
// miniprogram.config.js
module.exports = {
origin: 'https://soul.quwanzhi.com', // 本项目线上域名,见开发文档 8、部署
}
```
---
### 2. 跨域问题
**错误信息**
```
Access to fetch at 'xxx' has been blocked by CORS policy
```
**原因**Web 端开发时遇到跨域限制
**解决方案**
**方案 1配置 webpack devServer 代理**
```javascript
// webpack.dev.config.js
devServer: {
proxy: {
'/api': {
target: 'https://your-api.com',
changeOrigin: true,
pathRewrite: { '^/api': '' },
},
},
}
```
**方案 2后端配置 CORS**
```javascript
// Express 示例
app.use(cors({
origin: ['http://localhost:8080', 'https://soul.quwanzhi.com'],
credentials: true,
}))
```
---
## 性能问题
### 1. 首屏加载慢
**排查步骤**
1. **检查包体积**
```bash
# 查看构建产物大小
ls -lh dist/mp/common/
```
2. **启用代码压缩**
```javascript
// webpack.mp.config.js
const isOptimize = process.env.NODE_ENV === 'production'
optimization: {
minimizer: isOptimize ? [
new TerserPlugin(),
new OptimizeCSSAssetsPlugin(),
] : [],
}
```
3. **使用代码分割**(大型项目)
```javascript
optimization: {
splitChunks: {
chunks: 'all',
cacheGroups: {
vendors: {
test: /[\\/]node_modules[\\/]/,
priority: 10,
},
},
},
}
```
---
### 2. 页面卡顿
**常见原因**
1. **渲染列表过长**
```javascript
// ✅ 使用虚拟列表
import VirtualList from 'react-virtual-list'
<VirtualList
items={items}
itemHeight={50}
renderItem={(item) => <Item {...item} />}
/>
```
2. **频繁重渲染**
```javascript
// ✅ 使用 React.memo
const MyComponent = React.memo(({ data }) => {
return <div>{data}</div>
})
// ✅ 使用 useMemo
const expensiveValue = useMemo(() => {
return computeExpensiveValue(data)
}, [data])
```
---
## 调试技巧
### 1. 查看小程序日志
**微信开发者工具**
- 控制台 > Console查看 console.log
- 控制台 > Network查看网络请求
- 控制台 > Storage查看本地存储
---
### 2. 条件断点
```javascript
// 只在小程序环境下打印
if (isMiniProgram()) {
console.log('小程序环境:', data)
}
// 只在 Web 环境下打印
if (!isMiniProgram()) {
console.log('Web 环境:', data)
}
```
---
### 3. 真机调试
1. **开启调试模式**
- 微信开发者工具 > 预览
- 扫码在真机上打开
- 点击右上角 > 打开调试
2. **查看 vConsole**
- 小程序右下角会出现绿色悬浮按钮
- 点击查看日志、网络、存储等信息
---
## 检查清单
遇到问题时,按此清单逐项排查:
### 编译检查
- [ ] 所有依赖已安装(`npm install`
- [ ] entry 配置正确
- [ ] output 配置未修改必需字段
- [ ] splitChunks 配置合理
### 兼容性检查
- [ ] 没有使用 URLSearchParams
- [ ] 没有使用 localStorage改用适配器
- [ ] 没有直接使用 window/document
- [ ] CSS 没有使用 Grid改用 Flexbox
### 配置检查
- [ ] router 每个页面单独配置
- [ ] pages 配置了所有页面
- [ ] 适配器正确处理平台差异
### 运行检查
- [ ] Web 端能正常运行
- [ ] 小程序能正常编译
- [ ] 微信开发者工具无错误
- [ ] 真机预览正常
---
## 获取帮助
### 官方资源
- [Kbone 官方文档](https://wechat-miniprogram.github.io/kbone/docs/)
- [Kbone GitHub Issues](https://github.com/wechat-miniprogram/kbone/issues)
- [小程序官方文档](https://developers.weixin.qq.com/miniprogram/dev/framework/)
### 社区资源
- [Kbone 讨论区](https://github.com/wechat-miniprogram/kbone/discussions)
- [小程序开发者社区](https://developers.weixin.qq.com/community/)
### 调试工具
- 微信开发者工具:[下载地址](https://developers.weixin.qq.com/miniprogram/dev/devtools/download.html)
- React DevTools浏览器扩展
- vConsole真机调试工具小程序内置