didi / didi/mpx

[Bug report]webpack ≥ 5.10x 时 dev 模式下 setup 页面 data 恒为空:`global` 被编译为字面量 globalThis,被产物头部 `var globalThis = {}` 胶水遮蔽,currentInject 跨文件交接断裂

Open
#2,579 0 comments 0 reactions 0 assignees View on GitHub
Dominant language
JavaScript
Stars
3.9k
Forks
392
Avg merge
3d 12h
Merged PRs (30d)
15

Description

## 环境

- @mpxjs/core 2.10.19 / @mpxjs/webpack-plugin 2.10.19(已复核最新 2.11.1 源码同样存在)
- @mpxjs/mpx-cli-service 2.2.16 / @mpxjs/vue-cli-plugin-mpx
- webpack 5.110.3(问题在 5.110 引入,5.101.3 正常;webpack 声明支持范围 ^5.75.0 内)
- 目标平台:微信小程序(dev 模式)
- Node 24 / npm 11

## 复现步骤

1. 新建或使用任意带 `setup()` 页面的 MPX 项目
2. 重装依赖使 webpack 解析到 ≥5.110(lockfile 未入库或手动 `npm update webpack`)
3. `npm run dev` 启动,微信开发者工具打开

## 实际表现

- 所有 `createPage({ setup() {...} })` 页面 data 恒为 `{}`:模板绑定全部为空,事件绑定全部失效
- 控制台**无任何报错**
- `npm run build`(生产模式)**完全正常**,极难定位

## 期望表现

dev 与 build 行为一致,setup 返回的数据正常注入页面。

## 根因分析

**1. webpack 5.110 行为变化**(`webpack/lib/NodeStuffPlugin.js`):

```js
// 5.110:environment.globalThis 为 true(默认)时,`global` 被替换为字面量
const getGlobalDep = (expr) => {
if (compilation.outputOptions.environment.globalThis) {
return new ConstDependency("globalThis", expr.range);
}
return new ConstDependency(RuntimeGlobals.global, expr.range, [RuntimeGlobals.global]);
};
```

5.101.3 中 `global` 一律编译为 `RuntimeGlobals.global`(`__webpack_require__.g`,运行时解析为真实全局对象,不受局部声明遮蔽);5.110 起改为字面量 `globalThis`。

**2. 与 mpx webpack-plugin 的 chunk 胶水冲突**(`@mpxjs/webpack-plugin/lib/index.js` processChunk,约 :1815):

```js
source.add(`\nvar ${globalObject} = {};\n`)
```

dev 模式下 `globalObject` 为 webpack 默认值 `globalThis`,即每个产物文件(bundle.js、每个页面 chunk)头部都被注入 `var globalThis = {};`。

**3. 遮蔽导致交接断裂**:loader 生成的 `global.currentCtor` / `global.currentInject`(@mpxjs/webpack-plugin/lib/loader.js :228 附近)被 1 编译为字面量 `globalThis.xxx`,写入的是**本文件局部 shadow 对象**;而 `@mpxjs/core` 的 transferOptions.js 在 bundle.js 中读取 `globalThis.currentInject`(同样读 bundle 自己的 shadow)。页面写、bundle 读,对象不是同一个 → `currentInject` 永远拿不到 → 页面 data 恒为 `{}`。

**4. 为什么 build 正常**:生产 + optimizeSize 时插件把 `globalObject` 重命名为 `'g'`(:389-395),shadow 变成无害的 `var g = {}`,真实 `globalThis` 未被遮蔽。

## 临时解法

项目 `mpx.config.js` 中关闭该开关,使 webpack 退回 `__webpack_require__.g` 编译方式(单例、跨文件共享,不受胶水影响),已在 webpack 5.110.3 上验证 dev/build 均恢复正常:

```js
export default {
configureWebpack: {
output: {
environment: {
globalThis: false
}
}
}
}
```

修复后产物特征:`dist/wx/bundle.js` 中 currentInject 的前缀从 `globalThis.`(坏)变为 `__webpack_require__.g.`(好)。

## 修复建议(任一)

1. processChunk 注入胶水时感知 `output.environment.globalThis`(该开关开启时字面量会被遮蔽);
2. 或在插件内自动设置 `output.environment.globalThis = false`;
3. 或在文档中标注 webpack ≥5.110 需要此配置。

Contributor guide

No contributing guide indexed for this repository

Research direction

Start with processChunk in @mpxjs/webpack-plugin/lib/index.js around line 1815, then trace the global.currentCtor/currentInject references in @mpxjs/webpack-plugin/lib/loader.js around line 228 and transferOptions.js. Reproduce dev mode with webpack 5.110.3 and inspect bundle.js and page chunks. Done means setup page data and events work in dev as they do in build, without the cross-file currentInject split.

Written by the indexing model from the issue text.

Assessment

Tech stack
javascript, webpack
Domain
build-system
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Active
Clarity
Clearly specified
Newbie friendliness
55/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.