
Vitest无法加载Internal Packages
coding十二月 22, 20221mins
Frontend Vitest
所谓的Internal Packages是指一个没有包含tsconfig.json 的Typescript Packages,并且它的main 字段指向的是未编译的源码文件。
在Vite项目中,因为它是支持ESM模块的,所以把main 指向编译后的cjs代码,把module执行未编译的esm代码。这样在Vite是没有问题的,但是vitest无法通过module来加载模块代码。
查找原因H2
调试代码resolve.ts#resolvePackageEntry 会发现,
从根据
config定义的mainFields去加载代码,否则会从main字段加载jsx
if (!entryPoint || entryPoint.endsWith('.mjs')) {for (const field of options.mainFields) {if (field === 'browser') continue // already checked aboveif (typeof data[field] === 'string') {entryPoint = data[field]break}}}entryPoint ||= data.main而config的逻辑为,如果
config配置中的resolve属性为空,则会配置默认值。默认是的Main Fields中包含module,所以在vite中可以加载module定义的代码。jsx
const DEFAULT_MAIN_FIELDS = ['module','jsnext:main','jsnext'];const resolveOptions = {mainFields: config.resolve?.mainFields ?? DEFAULT_MAIN_FIELDS,browserField: config.resolve?.browserField ?? true,conditions: config.resolve?.conditions ?? [],extensions: config.resolve?.extensions ?? DEFAULT_EXTENSIONS$1,dedupe: config.resolve?.dedupe ?? [],preserveSymlinks: config.resolve?.preserveSymlinks ?? false,alias: resolvedAlias};vitest plugin会把mainFields设置为空,也就最终导致了无法加载
module定义的代码jsx
const config: ViteConfig = {esbuild: {sourcemap: 'external',// Enables using ignore hint for coverage providers with @preserve keywordlegalComments: 'inline',},resolve: {// by default Vite resolves `module` field, which not always a native ESM module// setting this option can bypass that and fallback to cjs versionmainFields: [],alias: preOptions.alias,conditions: ['node'],// eslint-disable-next-line @typescript-eslint/prefer-ts-expect-error// @ts-ignore we support Vite ^3.0, but browserField is available in Vite ^3.2browserField: false,},server: {...preOptions.api,watch: {ignored: preOptions.watchExclude,},open,hmr: false,preTransformRequests: false,},}
具体原因
https://github.com/vitest-dev/vitest/issues/1387
解决H2
其实在resolve.ts#resolvePackageEntry 在根据mainFields 加载之前,首先会使用resolve.exports 去加载代码,resolve.exports为多入口的模块提供了统一的方案,这个方案是兼容nodejs中的exports的。
所以最终的解决办法是,在package.json中定义exports
