簡體   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