繁体   English   中英

桶文件、webpack 和 jest

[英]Barrel files, webpack and jest

我对桶文件、webpack 和 jest 没有什么疑问。 我从来没有真正想过它们是如何工作的,现在我正在努力(开玩笑地)在一个更大的应用程序上编写测试,而这个应用程序还没有。

我在大文件夹(如components )中有桶文件,它们看起来像这样:

/组件/index.js

export { default as ComponentA } from './ComponentA';
export { default as ComponentB } from './ComponentB';
export { default as ComponentC } from './ComponentC';

通过这样的设置,我可以像这样轻松地导入这些组件:

import { ComponentA, Component C } from '/components';

而不是写作

import Component A from '/components/ComponentA';
import Component C from '/components/ComponentC';

我的主要问题:在我的 webpack 捆绑文件中,是否会包含 ComponentB 文件只是因为我在components/index.js中有它(但我并没有真正使用它)?

在我开始开玩笑地编写测试后,我想到了这一点,它开始向我抛出有关我尚未为其编写测试的文件的错误。 我试图搜索原因,我能找到的唯一原因是我从桶文件中导入了更大的文件(例如,我在构建页面时从桶文件导入ComponentA - 我现在正在尝试测试)。

实际上是的,在桶文件中导入的所有文件当前都包含在 Jest 的导入中。 发生这种情况主要是因为 Jest 使用 CommonJS 并且不进行任何 tree-shaking(在这个用例中这实际上只会让一切变得更慢)。

在处理大型项目时,使用桶文件时 Jest 测试套件运行速度越来越慢似乎很常见,这与在运行测试之前必须解析整个依赖树这一事实有关。

对此的快速解决方案是在 package 中不使用桶文件进行导入,要么完全避免它们,要么使用 jest.mock 使用jest.mock它们。

我个人建议通过使用依赖注入来完全避免在模块上导入。 如果您真的想以jest.mock方式 go ,您所要做的就是将它与工厂一起使用,就像这样(来自 Jest 文档):

jest.mock('../moduleName', () => {
  return jest.fn(() => 42);
});

// This runs the function specified as second argument to `jest.mock`.
const moduleName = require('../moduleName');
moduleName(); // Will return '42';

是的,这将在导入之前神奇地替换导入的文件,完全避免桶文件问题。

再说一遍:我不喜欢魔术代码,建议您改用依赖注入。

至少如果您使用 ts-jest 转换,应该支持桶导入。 参考: https://github.com/kulshekhar/ts-jest/issues/1149

但我鼓励类似的问题与桶类型定义 src/types/index.d.ts 通常在代码库中引用为 @/types

我最终配置了额外的 moduleNameMapper 定义

 moduleNameMapper: {
    // FIXES Could not locate module @/types mapped as: .../src/types.
    '^@/types$': '<rootDir>/src/types/index.d',
  },

希望这会对某人有所帮助:)

笑话

我遇到了同样的问题: Jest抛出与我未使用的文件相关的错误,只是因为它们是在我正在测试的模块使用的桶文件中导出的。 在我的例子中,问题是 Vuex 商店的测试开始中断,因为模块使用相同的商店(可能是由于循环依赖)。

prices.test.js

// the test imports a module
import prices from '@/store/modules/prices';

prices.js

// the module imports a module from a barrel file
import { isObject } from '@/common';

index.js

// this is the imported module
export { default as isObject } from './isObject';
// this is the other module that breaks my tests, even if I'm not importing it
export { default as getPageTitle } from './getPageTitle';

getPageTitle.js

// when the module uses the store, an error is thrown
import store from '@/store/store';

我认为在我的情况下问题是循环依赖,无论如何回答你的问题:是的,Jest 导入桶文件中的所有模块,即使它们不是直接导入的。

在我的例子中,解决方案是将使用 Vuex 的模块移动到一个单独的文件夹,并仅为这些文件创建一个单独的桶文件。

网页包

在不同的时刻,我发现Webpack默认情况下正在做同样的事情。 我没有在一个模块很小并且没有导入库的项目中注意到它,但是在一个单独的项目中我有模块导入非常大的库并且我注意到Webpack没有进行 tree-shaking 并且没有优化块正如它应该做的那样。

我发现Webpack以与Jest类似的方式导入桶文件中的所有库。 好处是您可以通过禁用特定桶文件的副作用来停止此行为。

webpack.config.js

{
  module: {
    rules: [
      // other rules...
      {
        test: [/src\/common\/index.ts/i],
        sideEffects: false,
      }
    ]
  }
}

您可以使用Webpack Bundle Analyzer看到不同之处:当没有关闭副作用时,来自一个特定文件夹的所有导入将具有相同的大小。 另一方面,当关闭副作用时,您会看到不同导入的大小不同。

默认行为(所有导入相同大小)

默认行为(所有导入相同大小)

关闭副作用(大小取决于您导入的模块)

关闭副作用(大小取决于您导入的模块)

当桶文件中的文件导入大型库时,改进会更加明显(tree-shaking 工作,优化块)。

您可以在此处找到更多详细信息: https ://github.com/vercel/next.js/issues/12557 和此处: Webpack doesn't split a huge vendor file when modules are exported and imported using index files

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM