From 5a2e8dfcf8c59010af45bc579bd0ef0c285ec61f Mon Sep 17 00:00:00 2001 From: jacy <18049821889@163.com> Date: Wed, 15 Jul 2026 19:33:51 +0800 Subject: [PATCH] fix(mini-user): dedupe Taro reactMeta so H5 useDidShow works 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 --- apps/mini-user/config/index.ts | 37 +++++++++- apps/mini-user/src/app.tsx | 4 ++ apps/mini-user/src/lib/patch-taro-h5-hooks.ts | 69 +++++++++++++++++++ 3 files changed, 108 insertions(+), 2 deletions(-) create mode 100644 apps/mini-user/src/lib/patch-taro-h5-hooks.ts diff --git a/apps/mini-user/config/index.ts b/apps/mini-user/config/index.ts index dfbeb86..561bb71 100644 --- a/apps/mini-user/config/index.ts +++ b/apps/mini-user/config/index.ts @@ -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: { + // 防止 reactMeta(useDidShow 依赖)在 vendors 里出现两份 + dedupe: [ + 'react', + 'react-dom', + '@tarojs/runtime', + '@tarojs/shared', + '@tarojs/plugin-framework-react', + ], + }, build: { sourcemap: false, }, diff --git a/apps/mini-user/src/app.tsx b/apps/mini-user/src/app.tsx index cb333b4..03f8fd7 100644 --- a/apps/mini-user/src/app.tsx +++ b/apps/mini-user/src/app.tsx @@ -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 ( <> diff --git a/apps/mini-user/src/lib/patch-taro-h5-hooks.ts b/apps/mini-user/src/lib/patch-taro-h5-hooks.ts new file mode 100644 index 0000000..cf84d01 --- /dev/null +++ b/apps/mini-user/src/lib/patch-taro-h5-hooks.ts @@ -0,0 +1,69 @@ +/** + * H5:Taro 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; + for (const [key, fn] of Object.entries(HOOKS)) { + target[key] = fn; + } +}