sinon.spy on "import * as Module" 在更新到 Webpack 5 后失败
sinon.spy on "import * as Module" fails after updating to Webpack 5
我正在将应用程序从 Webpack 4 升级到 Webpack 5。它使用 babel-loader。我的生产代码可以正常工作,但在升级到 karma-webpack v5.
后卡在了我们的 Karma/Sinon 集成测试中
此代码以前有效,但现在抛出错误:
// useEditUI.ts
export default function useEditUI() {}
// integration.ts
import sinon from 'sinon';
import * as useEditUI from 'useEditUI';
const spy = sinon.spy(useEditUI, 'default');
我的理解是发生这种情况是因为 import/export 是如何在幕后进行管理的:
以前,间谍逻辑正在查看一个值设置为默认导出的可配置对象。现在,该对象不可配置,没有值 属性,而是有一个映射到默认函数
的 getter
这会破坏 sinon.spy 功能。
研究问题一段时间后,我发现了几个可能有用的库:
- https://www.npmjs.com/package/babel-plugin-rewire
- https://www.npmjs.com/package/babel-plugin-add-module-exports
- https://www.npmjs.com/package/proxyquire
None 这些库似乎“正常工作”,其中一些似乎已被废弃。一般来说,他们似乎强制要求使用 commonjs 模块语法。所有其他研究的结果都是将解决方案宣布为 import * as Module
的帖子,这就是原始解决方案最初存在的方式。
在使用 Jest 等更现代的测试工具时,我没有遇到这个问题。这只是我试图减轻的 sinon 的限制。
这里有人有可行的指导吗?谢谢
哎呀呀呀。我花了一些时间在这里找到正确的答案,但我找到了一个有效的答案!它有点脆弱,可能会在未来版本的 webpack 上崩溃,但在撰写本文时适用于最新版本 (5.72.0)
首先,创建一个新的 ad-hoc 插件。使用它来重写 Webpack 生成的源代码。寻找管理导出的代码位并重写源代码,使其包含 configurable: true
AllowMutateEsmExports.prototype.apply = function (compiler) {
compiler.hooks.compilation.tap(
'AllowMutateEsmExports', function (compilation) {
compilation.hooks.processAssets.tapPromise(
{
name: 'AllowMutateEsmExports',
stage: compiler.webpack.Compilation.PROCESS_ASSETS_STAGE_ADDITIONAL,
additionalAssets: true,
},
async (assets) => {
const oldSource = assets['runtime.js'];
const { ReplaceSource } = compiler.webpack.sources;
const newSource = new ReplaceSource(oldSource, 'AllowMutateEsmExports');
const oldCode = 'Object.defineProperty(exports, key, { enumerable: true, get: definition[key] });';
const newCode = 'Object.defineProperty(exports, key, { configurable: true, enumerable: true, get: definition[key] });';
const start = oldSource.source().indexOf(oldCode);
const end = start + oldCode.length;
newSource.replace(start, end, newCode, 'AllowMutateEsmExports');
await compilation.updateAsset('runtime.js', newSource);
}
);
}
);
};
确保插件已加载
plugins: [
new AllowMutateEsmExports(),
],
使用 * 符号导入受影响的模块。重写默认导出并为其指定一个传统值 self-referential。这仅在 属性 首先可配置时才有效。
import * as useEditUI from 'useEditUI';
Object.defineProperty(useEditUI, 'default', {
writable: true,
value: useEditUI.default,
});
Spy 现在可以正常工作了。 :)
const spy = sinon.spy(useEditUI, 'default');
我正在将应用程序从 Webpack 4 升级到 Webpack 5。它使用 babel-loader。我的生产代码可以正常工作,但在升级到 karma-webpack v5.
后卡在了我们的 Karma/Sinon 集成测试中此代码以前有效,但现在抛出错误:
// useEditUI.ts
export default function useEditUI() {}
// integration.ts
import sinon from 'sinon';
import * as useEditUI from 'useEditUI';
const spy = sinon.spy(useEditUI, 'default');
我的理解是发生这种情况是因为 import/export 是如何在幕后进行管理的:
以前,间谍逻辑正在查看一个值设置为默认导出的可配置对象。现在,该对象不可配置,没有值 属性,而是有一个映射到默认函数
的 getter这会破坏 sinon.spy 功能。
研究问题一段时间后,我发现了几个可能有用的库:
- https://www.npmjs.com/package/babel-plugin-rewire
- https://www.npmjs.com/package/babel-plugin-add-module-exports
- https://www.npmjs.com/package/proxyquire
None 这些库似乎“正常工作”,其中一些似乎已被废弃。一般来说,他们似乎强制要求使用 commonjs 模块语法。所有其他研究的结果都是将解决方案宣布为 import * as Module
的帖子,这就是原始解决方案最初存在的方式。
在使用 Jest 等更现代的测试工具时,我没有遇到这个问题。这只是我试图减轻的 sinon 的限制。
这里有人有可行的指导吗?谢谢
哎呀呀呀。我花了一些时间在这里找到正确的答案,但我找到了一个有效的答案!它有点脆弱,可能会在未来版本的 webpack 上崩溃,但在撰写本文时适用于最新版本 (5.72.0)
首先,创建一个新的 ad-hoc 插件。使用它来重写 Webpack 生成的源代码。寻找管理导出的代码位并重写源代码,使其包含 configurable: true
AllowMutateEsmExports.prototype.apply = function (compiler) {
compiler.hooks.compilation.tap(
'AllowMutateEsmExports', function (compilation) {
compilation.hooks.processAssets.tapPromise(
{
name: 'AllowMutateEsmExports',
stage: compiler.webpack.Compilation.PROCESS_ASSETS_STAGE_ADDITIONAL,
additionalAssets: true,
},
async (assets) => {
const oldSource = assets['runtime.js'];
const { ReplaceSource } = compiler.webpack.sources;
const newSource = new ReplaceSource(oldSource, 'AllowMutateEsmExports');
const oldCode = 'Object.defineProperty(exports, key, { enumerable: true, get: definition[key] });';
const newCode = 'Object.defineProperty(exports, key, { configurable: true, enumerable: true, get: definition[key] });';
const start = oldSource.source().indexOf(oldCode);
const end = start + oldCode.length;
newSource.replace(start, end, newCode, 'AllowMutateEsmExports');
await compilation.updateAsset('runtime.js', newSource);
}
);
}
);
};
确保插件已加载
plugins: [
new AllowMutateEsmExports(),
],
使用 * 符号导入受影响的模块。重写默认导出并为其指定一个传统值 self-referential。这仅在 属性 首先可配置时才有效。
import * as useEditUI from 'useEditUI';
Object.defineProperty(useEditUI, 'default', {
writable: true,
value: useEditUI.default,
});
Spy 现在可以正常工作了。 :)
const spy = sinon.spy(useEditUI, 'default');