简体   繁体   English

桶文件、webpack 和 jest

[英]Barrel files, webpack and jest

I have few questions about barrel files, webpack and jest.我对桶文件、webpack 和 jest 没有什么疑问。 I've never really wondered how they work and now I'm struggling (with jest) to write tests on a bigger application that does not have ones yet.我从来没有真正想过它们是如何工作的,现在我正在努力(开玩笑地)在一个更大的应用程序上编写测试,而这个应用程序还没有。

I have barrel files in big folders (like components ) and they look like this:我在大文件夹(如components )中有桶文件,它们看起来像这样:

/components/index.js /组件/index.js

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

With a setup like this I can easily import those components like this:通过这样的设置,我可以像这样轻松地导入这些组件:

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

instead of writting而不是写作

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

My main question: In my webpack bundled files, will the ComponentB file be included just because I have it in the components/index.js (but I do not really use it)?我的主要问题:在我的 webpack 捆绑文件中,是否会包含 ComponentB 文件只是因为我在components/index.js中有它(但我并没有真正使用它)?

This came to my mind after I started writting tests with jest and it started to throw me errors about files I haven't writted tests yet for.在我开始开玩笑地编写测试后,我想到了这一点,它开始向我抛出有关我尚未为其编写测试的文件的错误。 I've tried to search why, and the only reason I can find is that I have imports from barrel files in bigger files (eg I import ComponentA from a barrel file when building a page - that I'm now trying to test).我试图搜索原因,我能找到的唯一原因是我从桶文件中导入了更大的文件(例如,我在构建页面时从桶文件导入ComponentA - 我现在正在尝试测试)。

Actually yes, all files imported in a barrel file are currently included in the import on Jest.实际上是的,在桶文件中导入的所有文件当前都包含在 Jest 的导入中。 That happens mainly because Jest uses CommonJS and does not do any tree-shaking (which would actually just make everything even slower in this use case).发生这种情况主要是因为 Jest 使用 CommonJS 并且不进行任何 tree-shaking(在这个用例中这实际上只会让一切变得更慢)。

When working on a big project, it seems to be quite common to have Jest test suites run increasingly slow when using barrel files and that is related to the fact that the entire dependency tree has to be resolved before running the tests.在处理大型项目时,使用桶文件时 Jest 测试套件运行速度越来越慢似乎很常见,这与在运行测试之前必须解析整个依赖树这一事实有关。

The quick solution for that is to not use barrel files for imports within the package, either by avoiding them completely or by mocking them using jest.mock .对此的快速解决方案是在 package 中不使用桶文件进行导入,要么完全避免它们,要么使用 jest.mock 使用jest.mock它们。

I personally recommend avoiding imports completely on your modules by using dependency injection instead.我个人建议通过使用依赖注入来完全避免在模块上导入。 If you really want to go the jest.mock way, all you have to do is use it with a factory , like this (from the Jest docs):如果您真的想以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';

Yes, this will magically replace the imported file before it is imported, avoiding the barrel file issue altogether.是的,这将在导入之前神奇地替换导入的文件,完全避免桶文件问题。

Again: I don't like magic code and recommend you use dependency injection instead.再说一遍:我不喜欢魔术代码,建议您改用依赖注入。

Barrel imports should be supported, at least if you are using ts-jest transform.至少如果您使用 ts-jest 转换,应该支持桶导入。 Ref: https://github.com/kulshekhar/ts-jest/issues/1149参考: https://github.com/kulshekhar/ts-jest/issues/1149

but I have encouraged similar problem with barrel type definition src/types/index.d.ts referenced usually as @/types all around in codebase但我鼓励类似的问题与桶类型定义 src/types/index.d.ts 通常在代码库中引用为 @/types

I ended up with configuring extra moduleNameMapper definition我最终配置了额外的 moduleNameMapper 定义

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

Hope this will help someone:)希望这会对某人有所帮助:)

Jest笑话

I've had the same issue: Jest was throwing errors related to files that I didn't use , only because they were exported in a barrel file which was used by the modules I was testing.我遇到了同样的问题: Jest抛出与我未使用的文件相关的错误,只是因为它们是在我正在测试的模块使用的桶文件中导出的。 In my case the issue was with tests on Vuex stores which started to break because of modules using the same stores (probably due to circular dependencies).在我的例子中,问题是 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';

I think that in my case the issue was a circular dependency, anyway to answer your question: yes, Jest imports all the modules in the barrel files even if they are not imported directly.我认为在我的情况下问题是循环依赖,无论如何回答你的问题:是的,Jest 导入桶文件中的所有模块,即使它们不是直接导入的。

In my case the solution was to move the modules that were using Vuex to a separate folder and to create a separate barrel file only for those files.在我的例子中,解决方案是将使用 Vuex 的模块移动到一个单独的文件夹,并仅为这些文件创建一个单独的桶文件。

Webpack网页包

In a different moment I figured out that Webpack is doing the same thing by default.在不同的时刻,我发现Webpack默认情况下正在做同样的事情。 I didn't notice it on a project where modules were small and weren't importing libraries, but on a separate project I had modules importing very large libraries and I noticed that Webpack wasn't doing tree-shaking and wasn't optimizing chunks as it was supposed to do.我没有在一个模块很小并且没有导入库的项目中注意到它,但是在一个单独的项目中我有模块导入非常大的库并且我注意到Webpack没有进行 tree-shaking 并且没有优化块正如它应该做的那样。

I discovered that Webpack imports all the libraries in the barrel file, in a similar way as Jest does.我发现Webpack以与Jest类似的方式导入桶文件中的所有库。 The upside is that you can stop this behavior by disabling side effects on the specific barrel files.好处是您可以通过禁用特定桶文件的副作用来停止此行为。

webpack.config.js

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

You can see the difference using Webpack Bundle Analyzer : when side effects are not turned off, all imports from one specific folder will have the same size.您可以使用Webpack Bundle Analyzer看到不同之处:当没有关闭副作用时,来自一个特定文件夹的所有导入将具有相同的大小。 On the other hand, when side effects are turned off you will see a different size for different imports.另一方面,当关闭副作用时,您会看到不同导入的大小不同。

Default behavior (all imports the same size)默认行为(所有导入相同大小)

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

Side effects turned off (the size depends on which modules you import)关闭副作用(大小取决于您导入的模块)

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

When files in the barrel files import large libraries, the improvements can be even more noticeable (tree-shaking works, chunks are optimized).当桶文件中的文件导入大型库时,改进会更加明显(tree-shaking 工作,优化块)。

You can find more details here: https://github.com/vercel/next.js/issues/12557 and here: Webpack doesn't split a huge vendor file when modules are exported and imported using index files .您可以在此处找到更多详细信息: 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