From 5a31cd403d0e76f74d51be4b05af37553e3e6764 Mon Sep 17 00:00:00 2001 From: Greg Signal Date: Sat, 13 Jul 2024 23:57:23 +0200 Subject: [PATCH] fix: don't resolve tsconfig for externals Original issue: https://github.com/privatenumber/esbuild-loader/issues/363, esbuild-loader would attempt to resolve typescript configs for external sources under some conditions, and cause problems (in this case, the resolved tsconfig.json referenced a config that is not in the dependency tree and thus unresolvable) tsconfig fix: warn on tsconfig resolution error, continue transform --- src/loader.ts | 17 +++++++-- tests/specs/tsconfig.ts | 76 ++++++++++++++++++++++++++++++++++++++++- 2 files changed, 90 insertions(+), 3 deletions(-) diff --git a/src/loader.ts b/src/loader.ts index c8453b3..fe63d0b 100644 --- a/src/loader.ts +++ b/src/loader.ts @@ -81,8 +81,21 @@ async function ESBuildLoader( } else { /* Detect tsconfig file */ - // Webpack shouldn't be loading the same path multiple times so doesn't need to be cached - const tsconfig = getTsconfig(resourcePath, 'tsconfig.json', tsconfigCache); + let tsconfig; + + try { + // Webpack shouldn't be loading the same path multiple times so doesn't need to be cached + tsconfig = getTsconfig(resourcePath, 'tsconfig.json', tsconfigCache); + } catch (error) { + if (resourcePath.split(path.sep).includes('node_modules')) { + this.emitWarning( + new Error(`[esbuild-loader] Error while discovering tsconfig.json in dependency: "${error?.toString()}"`), + ); + } else { + throw error; + } + } + if (tsconfig) { const fileMatcher = createFilesMatcher(tsconfig); transformOptions.tsconfigRaw = fileMatcher(resourcePath) as TransformOptions['tsconfigRaw']; diff --git a/tests/specs/tsconfig.ts b/tests/specs/tsconfig.ts index 57e6a28..38ef915 100644 --- a/tests/specs/tsconfig.ts +++ b/tests/specs/tsconfig.ts @@ -2,7 +2,7 @@ import path from 'path'; import { createRequire } from 'node:module'; import { testSuite, expect } from 'manten'; import { createFixture } from 'fs-fixture'; -import { execa } from 'execa'; +import { execa, type ExecaError } from 'execa'; import { tsconfigJson } from '../utils.js'; const require = createRequire(import.meta.url); @@ -262,6 +262,80 @@ export default testSuite(({ describe }) => { const code2 = await fixture.readFile('dist/index2.js', 'utf8'); expect(code2).toMatch('__publicField(this, "foo", 100);'); }); + + test('ignores tsconfig.json in third party dependencies', async () => { + await using fixture = await createFixture({ + // Fake external dependency + node_modules: { + 'fake-lib': { + 'index.ts': 'export function testFn(): string { return "Hi!" }', + 'package.json': JSON.stringify({ + name: 'fake-lib', + }), + 'tsconfig.json': tsconfigJson({ + extends: 'something-imaginary', + }), + }, + }, + // Our project + src: { + 'index.ts': ` + import { testFn } from "fake-lib"; + + export default testFn;`, + }, + 'webpack.config.js': ` + module.exports = { + mode: 'production', + + optimization: { + minimize: false, + }, + + resolveLoader: { + alias: { + 'esbuild-loader': ${JSON.stringify(esbuildLoader)}, + }, + }, + + resolve: { + extensions: ['.ts', '.js'], + }, + + module: { + rules: [ + { + test: /.[tj]sx?$/, + loader: 'esbuild-loader', + options: { + target: 'es2015', + } + } + ], + }, + + entry: { + index: './src/index.ts', + }, + }; + `, + }); + + let result; + + try { + result = await execa(webpackCli, { + cwd: fixture.path, + }); + } catch (error) { + result = error as ExecaError; + } + const { exitCode, stdout } = result; + + // We log this as a warning, and continue the transform + expect(stdout).toMatch("Error while discovering tsconfig.json in dependency: \"Error: File 'something-imaginary' not found.\""); + expect(exitCode).toEqual(0); + }); }); describe('plugin', ({ test }) => {