From 65fc75c0e8309aff2fce36f65a0e74e46b2142c7 Mon Sep 17 00:00:00 2001 From: shulandmimi Date: Mon, 5 Jan 2026 19:16:54 +0800 Subject: [PATCH] feat: keyboard avoiding use translate --- packages/webpack-plugin/lib/global.d.ts | 251 +++++++++++++++++- packages/webpack-plugin/lib/index.js | 7 + packages/webpack-plugin/lib/loader.js | 4 + .../template/wx/component-config/button.js | 2 +- .../react/mpx-keyboard-avoiding-view.tsx | 6 +- .../runtime/components/react/tsconfig.json | 26 ++ packages/webpack-plugin/package.json | 5 +- packages/webpack-plugin/tsconfig.json | 17 +- 8 files changed, 294 insertions(+), 24 deletions(-) create mode 100644 packages/webpack-plugin/lib/runtime/components/react/tsconfig.json diff --git a/packages/webpack-plugin/lib/global.d.ts b/packages/webpack-plugin/lib/global.d.ts index a083325d1d..c79fa8780a 100644 --- a/packages/webpack-plugin/lib/global.d.ts +++ b/packages/webpack-plugin/lib/global.d.ts @@ -1,16 +1,245 @@ +import * as webpack from 'webpack' + +declare module 'webpack' { + interface Compilation { + __mpx__: MpxContext + } + + interface Compiler { + __mpx__?: boolean + } +} declare global { interface MpxWebpackPluginOptions { - style: { - cssCondition?: { - before?: boolean; - after?: boolean; - beforeExclude?: (string | RegExp)[]; - afterExclude?: (string | RegExp)[]; - legacy?: boolean; - afterLegacy?: boolean; - beforeLegacy?: boolean; - } - } + style: { + cssCondition?: { + before?: boolean + after?: boolean + beforeExclude?: (string | RegExp)[] + afterExclude?: (string | RegExp)[] + legacy?: boolean + afterLegacy?: boolean + beforeLegacy?: boolean + } } + } + + type MpxLoaderContext = webpack.LoaderContext & { + getMpx(): MpxContext + } + + interface MpxContext { + /** + * 用于使用 webpack-virtual-modules 功能,目前仅在输出 web 时支持使用 + */ + __vfs: any | null + + /** + * app 信息,便于获取 appName + */ + appInfo: { + resourcePath?: string + name?: string + [key: string]: any + } + + /** + * pageConfig 信息 + */ + pageConfigsMap: Record + + /** + * pages 全局记录,无需区分主包/分包 + */ + pagesMap: Record + + /** + * 组件资源记录,按所属包进行记录(如 componentsMap.main) + */ + componentsMap: Record> + + /** + * 静态资源(图片、字体、独立样式)等,按所属包进行记录 + */ + staticResourcesMap: Record> + + /** + * 用于记录命中 subpackageModulesRules 的 JS 模块分包归属,用于 JS 多分包冗余输出 + */ + subpackageModulesMap: Record> + + /** + * 记录其他资源,如 pluginMain、pluginExport,无需区分主包/分包 + */ + otherResourcesMap: Record + + /** + * 记录独立分包 + */ + independentSubpackagesMap: Record + + subpackagesEntriesMap: Record + postSubpackageEntriesMap: Record + replacePathMap: Record + + /** + * 导出模块集合 + */ + exportModules: Set + + /** + * 记录动态添加入口的分包信息 + */ + dynamicEntryInfo: Record + + /** + * 记录 entryModule 与 entryNode 的对应关系,用于体积分析 + */ + entryNodeModulesMap: Map + + /** + * 记录与 asset 相关联的 modules,用于体积分析 + */ + assetsModulesMap: Map> + + /** + * 记录与 asset 相关联的 AST,用于体积分析和 esCheck,避免重复 parse + */ + assetsASTsMap: Map + + /** + * 记录 RequireExternalDependency 相关资源路径 + */ + externalRequestsMap: Map + + globalComponents: Record + globalComponentsInfo: Record + + /** + * todo: es6 Map 读写性能高于 object,之后会逐步替换 + */ + wxsAssetsCache: Map + addEntryPromiseMap: Map> + currentPackageRoot: string + wxsContentMap: Record + + /** + * 是否强制使用页面构造函数 + */ + forceUsePageCtor: boolean + + resolveMode: string + mode: string + srcMode: string + env: string + externalClasses: string[] + projectRoot: string + autoScopeRules: any + autoVirtualHostRules: any + customTextRules: any + transRpxRules: any + postcssInlineConfig: any + decodeHTMLText: boolean + + /** + * native 文件专用配置 + */ + i18n: any | null + checkUsingComponentsRules: any + forceDisableBuiltInLoader: boolean + + /** + * 默认的应用标题 + */ + appTitle: string + + attributes: any[] + externals: any[] + useRelativePath: boolean + removedChunks: any[] + forceProxyEventRules: any + + /** + * 若配置 disableRequireAsync=true,则全平台构建不支持异步分包 + */ + supportRequireAsync: boolean + partialCompileRules: any + asyncSubpackageRules: any[] + transSubpackageRules: any + optimizeRenderRules: any[] + + addEntryModuleIssuer: (module: string, issuer: string) => void + + /** + * 资源路径的哈希函数(用于生成输出唯一名) + */ + pathHash: (resourcePath: string) => string + + // 缓存与工具 + loaderContentCache: Map + extractedFilesCache: Map + + // 函数接口 + + /** + * 收集动态入口信息(分包、文件名、是否为页面、是否包含异步等) + */ + collectDynamicEntryInfo: (info: { resource: string; packageName: string; filename: string; entryType: string; hasAsync: boolean }) => void + + /** + * 添加入口(包装了 webpack 的 addEntry) + */ + addEntry: (request: string, name: string, callback: (err?: Error, result?: any) => void) => any + + getModuleId: (filePath: string, isApp?: boolean) => string + getEntryNode: (module: any, type?: string) => any + + /** + * 根据资源路径和类型返回输出路径(支持自定义输出、冲突处理等) + */ + getOutputPath: (resourcePath: string, type: string, opts?: { ext?: string; conflictPath?: string }) => string + + /** + * 获取提取后的文件名(支持静态、插件、普通资源) + */ + getExtractedFile: (resource: string, opts?: { error?: (err: Error) => void }) => string + + recordResourceMap: (params: { + resourcePath: string + resourceType: string + outputPath?: string + packageRoot?: string + recordOnly?: boolean + warn?: (e: Error) => void + error?: (e: Error) => void + }) => { outputPath?: string; alreadyOutputted?: boolean } + + getPackageInfo: (params: { + resource: string + resourceType: string + outputPath?: string + issuerResource?: string + warn?: (e: Error) => void + error?: (e: Error) => void + }) => { packageName: string; packageRoot: string; outputPath?: string; alreadyOutputted?: boolean } + + // 运行时信息与注入相关 + runtimeInfo: Record + dynamicSlotDependencies: Record + dynamicTemplateRuleRunner: any + + /** + * 依据 package 注入到 mpx-custom-element-*.json 里面的组件路径 + */ + getPackageInjectedComponentsMap: (packageName?: string) => Record + + getPackageInjectedTemplateConfig: (packageName?: string) => any + injectDynamicSlotDependencies: (usingComponents: string, resourcePath: string) => string + changeHashNameForAstNode: (templateAst: string, componentsMap: any) => string + collectDynamicSlotDependencies: (packageName?: string) => void + + // 其它任意扩展字段 + [key: string]: any + } } diff --git a/packages/webpack-plugin/lib/index.js b/packages/webpack-plugin/lib/index.js index 8e93c8debd..4ddb8395b3 100644 --- a/packages/webpack-plugin/lib/index.js +++ b/packages/webpack-plugin/lib/index.js @@ -87,6 +87,10 @@ const isProductionLikeMode = options => { return options.mode === 'production' || !options.mode } +/** + * @param {import('webpack').NormalModule} module + * @returns + */ const isStaticModule = module => { if (!module.resource) return false const { queryObj } = parseRequest(module.resource) @@ -323,6 +327,9 @@ class MpxWebpackPlugin { } } + /** + * @param {import('webpack').Compiler} compiler + */ apply (compiler) { // 注入 fs 代理 startFSStripForCss(this.options.defs) diff --git a/packages/webpack-plugin/lib/loader.js b/packages/webpack-plugin/lib/loader.js index d7dffed959..cfb6f030a5 100644 --- a/packages/webpack-plugin/lib/loader.js +++ b/packages/webpack-plugin/lib/loader.js @@ -19,6 +19,10 @@ const processWeb = require('./web') const processReact = require('./react') const genMpxCustomElement = require('./runtime-render/gen-mpx-custom-element') +/** + * @this {MpxLoaderContext} + * @param {string} content + */ module.exports = function (content) { this.cacheable() diff --git a/packages/webpack-plugin/lib/platform/template/wx/component-config/button.js b/packages/webpack-plugin/lib/platform/template/wx/component-config/button.js index 2c3151782a..3dba6863fe 100644 --- a/packages/webpack-plugin/lib/platform/template/wx/component-config/button.js +++ b/packages/webpack-plugin/lib/platform/template/wx/component-config/button.js @@ -197,7 +197,7 @@ module.exports = function ({ print }) { qa: qaPropLog }, { - test: /^(lang|from-type|hover-class|send-message-title|send-message-path|send-message-img|app-parameter|show-message-card|phone-number-no-quota-toast|bindgetuserinfo|bindcontact|createliveactivity|bindgetphonenumber|bindgetrealtimephonenumber|binderror|bindopensetting|bindlaunchapp|bindchooseavatar|bindagreeprivacyauthorization)$/, + test: /^(lang|from-type|send-message-title|send-message-path|send-message-img|app-parameter|show-message-card|phone-number-no-quota-toast|bindgetuserinfo|bindcontact|createliveactivity|bindgetphonenumber|bindgetrealtimephonenumber|binderror|bindopensetting|bindlaunchapp|bindchooseavatar|bindagreeprivacyauthorization)$/, ios: iosPropLog, android: androidPropLog, harmony: harmonyPropLog diff --git a/packages/webpack-plugin/lib/runtime/components/react/mpx-keyboard-avoiding-view.tsx b/packages/webpack-plugin/lib/runtime/components/react/mpx-keyboard-avoiding-view.tsx index 6dda7a99b3..44a920df9e 100644 --- a/packages/webpack-plugin/lib/runtime/components/react/mpx-keyboard-avoiding-view.tsx +++ b/packages/webpack-plugin/lib/runtime/components/react/mpx-keyboard-avoiding-view.tsx @@ -25,8 +25,10 @@ const KeyboardAvoidingView = ({ children, style, contentContainerStyle }: Keyboa const isShow = useRef(false) const animatedStyle = useAnimatedStyle(() => ({ - // translate/position top可能会导致底部渲染区域缺失 - marginTop: -offset.value, + // translate/position top+ overflow hidden 在 android 上时因为键盘顶起让页面高度变小,同时元素位置上移 + // 此时最底部的区域是超出了页面高度的,hidden生效就被隐藏掉,因此需要 android 配置聚焦时禁用高度缩小 + // margin-top 因为在 react-native 上和 flex 1 同时存在时,负值只会让容器高度整体变高,不会让元素上移 + transform: [{ translateY: -offset.value }], flexBasis: basic.value as DimensionValue })) diff --git a/packages/webpack-plugin/lib/runtime/components/react/tsconfig.json b/packages/webpack-plugin/lib/runtime/components/react/tsconfig.json new file mode 100644 index 0000000000..67706a4d9f --- /dev/null +++ b/packages/webpack-plugin/lib/runtime/components/react/tsconfig.json @@ -0,0 +1,26 @@ +// 用于 react 生成 +{ + "include": [ + "./" + ], + "exclude": [], + "compilerOptions": { + "target": "esnext", + "module": "esnext", + "outDir": "./dist", + "rootDir": "./", + "noImplicitThis": true, + "noImplicitAny": true, + "skipLibCheck": true, + "strictNullChecks": true, + "moduleResolution": "node", + "declaration": true, + "allowSyntheticDefaultImports": true, + "jsx": "preserve", + "lib": [ + "esnext", + "dom", + "dom.iterable" + ], + } +} diff --git a/packages/webpack-plugin/package.json b/packages/webpack-plugin/package.json index 7f24b03f8e..2939097203 100644 --- a/packages/webpack-plugin/package.json +++ b/packages/webpack-plugin/package.json @@ -80,7 +80,7 @@ "scripts": { "test": "jest --passWithNoTests", "copy-icons": "cp -r ./lib/runtime/components/react/mpx-icon/icons ./lib/runtime/components/react/dist/mpx-icon/icons", - "build": "rimraf ./lib/runtime/components/react/dist && tsc && npm run copy-icons" + "build": "rimraf ./lib/runtime/components/react/dist && tsc -p ./lib/runtime/components/react/tsconfig.json && npm run copy-icons" }, "devDependencies": { "@d11/react-native-fast-image": "^8.6.12", @@ -99,7 +99,8 @@ "react-native-video": "^6.9.0", "react-native-vision-camera": "^4.7.2", "react-native-webview": "^13.12.2", - "rimraf": "^6.0.1" + "rimraf": "^6.0.1", + "webpack": "^5.75.0" }, "engines": { "node": ">=14.14.0" diff --git a/packages/webpack-plugin/tsconfig.json b/packages/webpack-plugin/tsconfig.json index ef92c480d2..3ea8f0e28b 100644 --- a/packages/webpack-plugin/tsconfig.json +++ b/packages/webpack-plugin/tsconfig.json @@ -1,24 +1,25 @@ +// 用于lib下文件的语法检查,ts 类型提示 { "include": [ + "./lib", + ], + "exclude": [ "./lib/runtime/components/react" ], "compilerOptions": { + "module": "nodenext", "target": "esnext", - "module": "esnext", - "outDir": "./lib/runtime/components/react/dist", "noImplicitThis": true, "noImplicitAny": true, "skipLibCheck": true, + "allowJs": true, + "checkJs": false, "strictNullChecks": true, - "moduleResolution": "node", - "declaration": true, - "declarationMap": true, + "moduleResolution": "nodenext", "allowSyntheticDefaultImports": true, - "jsx": "preserve", + "noEmit": true, "lib": [ "esnext", - "dom", - "dom.iterable" ] } }