fix(mini-user): dedupe Taro reactMeta so H5 useDidShow works
CI / verify (pull_request) Has been cancelled

Vite was bundling plugin-framework-react runtime twice, so tab pages crashed with useContext is not a function on enter/switch.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-07-15 19:33:51 +08:00
parent 7062aeb8f8
commit 5a2e8dfcf8
3 changed files with 108 additions and 2 deletions
+35 -2
View File
@@ -1,9 +1,27 @@
import { createRequire } from 'node:module';
import path from 'node:path';
import { defineConfig } from '@tarojs/cli';
/** 小程序/H5 请求的后端 origin(不含 /api);本地联调可用 VITE_API_TARGET 覆盖 */
const API_ORIGIN = process.env.VITE_API_TARGET ?? 'https://dkapi.runxian.top';
const requireFromApp = createRequire(path.resolve(__dirname, '../package.json'));
/** 解析包目录/文件,避免 pnpm/Vite 把同一 runtime 打成两份 → useDidShow 读到空 reactMeta */
function resolvePkgFile(id: string): string {
return requireFromApp.resolve(id);
}
function resolvePkgDir(id: string): string {
return path.dirname(requireFromApp.resolve(`${id}/package.json`));
}
const TARO_FRAMEWORK_RUNTIME = resolvePkgFile('@tarojs/plugin-framework-react/dist/runtime.js');
const REACT_DIR = resolvePkgDir('react');
const REACT_DOM_DIR = resolvePkgDir('react-dom');
const TARO_RUNTIME_DIR = resolvePkgDir('@tarojs/runtime');
const TARO_SHARED_DIR = resolvePkgDir('@tarojs/shared');
export default defineConfig(async () => ({
projectName: 'mini-user',
date: '2026-7-12',
@@ -18,8 +36,13 @@ export default defineConfig(async () => ({
outputRoot: 'dist',
plugins: ['@tarojs/plugin-framework-react', '@tarojs/plugin-html'],
alias: {
react: path.resolve(__dirname, '../node_modules/react'),
'react-dom': path.resolve(__dirname, '../node_modules/react-dom'),
// 指向包目录(不是 index.js),否则 react-dom/client 会变成 index.js/client
react: REACT_DIR,
'react-dom': REACT_DOM_DIR,
'@tarojs/runtime': TARO_RUNTIME_DIR,
'@tarojs/shared': TARO_SHARED_DIR,
'@tarojs/plugin-framework-react/dist/runtime': TARO_FRAMEWORK_RUNTIME,
'@tarojs/plugin-framework-react/dist/runtime.js': TARO_FRAMEWORK_RUNTIME,
},
defineConstants: {
TARO_APP_API_ORIGIN: JSON.stringify(API_ORIGIN),
@@ -43,6 +66,16 @@ export default defineConfig(async () => ({
noDiscovery: true,
include: ['react', 'react-dom', 'react/jsx-runtime'],
},
resolve: {
// 防止 reactMetauseDidShow 依赖)在 vendors 里出现两份
dedupe: [
'react',
'react-dom',
'@tarojs/runtime',
'@tarojs/shared',
'@tarojs/plugin-framework-react',
],
},
build: {
sourcemap: false,
},
+4
View File
@@ -1,8 +1,12 @@
import './lib/text-encoding-polyfill';
import { PropsWithChildren } from 'react';
import WechatShareBootstrap from './components/WechatShareBootstrap';
import { patchTaroH5Hooks } from './lib/patch-taro-h5-hooks';
import './app.css';
// H5:在首屏 page hooks 执行前,把 Taro.useDidShow 等绑到与 createReactApp 同一份 runtime
patchTaroH5Hooks();
function App({ children }: PropsWithChildren) {
return (
<>
@@ -0,0 +1,69 @@
/**
* H5Taro Vite 偶发把 @tarojs/plugin-framework-react/dist/runtime 打成两份,
* 导致 createReactApp 初始化了 B 份 reactMeta,而 Taro.useDidShow 仍绑定 A 份(R={}),
* 页面一进就报 n.useContext is not a function。
*
* 在 App 渲染前,用与 createReactApp 同一份 runtime 的 hooks 覆盖到 Taro 上。
*/
import Taro from '@tarojs/taro';
import {
useAddToFavorites,
useDidHide,
useDidShow,
useError,
useKeyboardHeight,
useLaunch,
useLoad,
useOptionMenuClick,
usePageNotFound,
usePageScroll,
usePullDownRefresh,
usePullIntercept,
useReachBottom,
useReady,
useResize,
useRouter,
useSaveExitState,
useScope,
useShareAppMessage,
useShareTimeline,
useTabItemTap,
useTitleClick,
useUnhandledRejection,
useUnload,
} from '@tarojs/plugin-framework-react/dist/runtime';
const HOOKS = {
useAddToFavorites,
useDidHide,
useDidShow,
useError,
useKeyboardHeight,
useLaunch,
useLoad,
useOptionMenuClick,
usePageNotFound,
usePageScroll,
usePullDownRefresh,
usePullIntercept,
useReachBottom,
useReady,
useResize,
useRouter,
useSaveExitState,
useScope,
useShareAppMessage,
useShareTimeline,
useTabItemTap,
useTitleClick,
useUnhandledRejection,
useUnload,
} as const;
export function patchTaroH5Hooks() {
if (process.env.TARO_ENV !== 'h5') return;
const target = Taro as unknown as Record<string, unknown>;
for (const [key, fn] of Object.entries(HOOKS)) {
target[key] = fn;
}
}