diff --git a/e2e/cases/server/overlay-type-errors/index.test.ts b/e2e/cases/server/overlay-type-errors/index.test.ts new file mode 100644 index 0000000000..18fed604b8 --- /dev/null +++ b/e2e/cases/server/overlay-type-errors/index.test.ts @@ -0,0 +1,33 @@ +import { dev, proxyConsole } from '@e2e/helper'; +import { expect, test } from '@playwright/test'; + +const cwd = __dirname; + +test('should display type errors on overlay correctly', async ({ page }) => { + const { restore } = proxyConsole(); + + const rsbuild = await dev({ + cwd, + page, + }); + + const errorOverlay = page.locator('rsbuild-error-overlay'); + + await expect(errorOverlay.locator('.title')).toHaveText('Build failed'); + + // The first span is "TS2322: " + const firstSpan = errorOverlay.locator('span').first(); + expect(await firstSpan.textContent()).toEqual('TS2322: '); + expect(await firstSpan.getAttribute('style')).toEqual('color:#888'); + + // The first link is "/src/index.ts:3:1" + const firstLink = errorOverlay.locator('.file-link').first(); + expect(await firstLink.getAttribute('class')).toEqual('file-link'); + expect( + (await firstLink.textContent())?.endsWith('/src/index.ts:3:1'), + ).toBeTruthy(); + + await rsbuild.close(); + + restore(); +}); diff --git a/e2e/cases/server/overlay-type-errors/rsbuild.config.ts b/e2e/cases/server/overlay-type-errors/rsbuild.config.ts new file mode 100644 index 0000000000..6e1e061f9e --- /dev/null +++ b/e2e/cases/server/overlay-type-errors/rsbuild.config.ts @@ -0,0 +1,6 @@ +import { defineConfig } from '@rsbuild/core'; +import { pluginTypeCheck } from '@rsbuild/plugin-type-check'; + +export default defineConfig({ + plugins: [pluginTypeCheck()], +}); diff --git a/e2e/cases/server/overlay-type-errors/src/index.ts b/e2e/cases/server/overlay-type-errors/src/index.ts new file mode 100644 index 0000000000..9a0048bf68 --- /dev/null +++ b/e2e/cases/server/overlay-type-errors/src/index.ts @@ -0,0 +1,3 @@ +// This is a type error +let num = 1; +num = '2'; diff --git a/e2e/cases/server/overlay-type-errors/tsconfig.json b/e2e/cases/server/overlay-type-errors/tsconfig.json new file mode 100644 index 0000000000..0cad3cc272 --- /dev/null +++ b/e2e/cases/server/overlay-type-errors/tsconfig.json @@ -0,0 +1,12 @@ +{ + "compilerOptions": { + "target": "ES2020", + "lib": ["DOM", "ES2020"], + "module": "ESNext", + "strict": true, + "skipLibCheck": true, + "isolatedModules": true, + "moduleResolution": "Bundler" + }, + "include": ["src"] +} diff --git a/e2e/package.json b/e2e/package.json index 0589741676..ebe399dc31 100644 --- a/e2e/package.json +++ b/e2e/package.json @@ -35,6 +35,7 @@ "@rsbuild/plugin-stylus": "workspace:*", "@rsbuild/plugin-svelte": "workspace:*", "@rsbuild/plugin-svgr": "workspace:*", + "@rsbuild/plugin-type-check": "^1.2.0", "@rsbuild/plugin-webpack-swc": "workspace:*", "@rsbuild/plugin-vue": "workspace:*", "@rsbuild/plugin-vue-jsx": "^1.1.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index a21e1772ab..e8182b4900 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -126,6 +126,9 @@ importers: '@rsbuild/plugin-svgr': specifier: workspace:* version: link:../packages/plugin-svgr + '@rsbuild/plugin-type-check': + specifier: ^1.2.0 + version: 1.2.0(@rsbuild/core@packages+core)(@rspack/core@1.1.8(@swc/helpers@0.5.15))(typescript@5.7.2) '@rsbuild/plugin-vue': specifier: workspace:* version: link:../packages/plugin-vue @@ -2533,6 +2536,14 @@ packages: peerDependencies: '@rsbuild/core': 1.x + '@rsbuild/plugin-type-check@1.2.0': + resolution: {integrity: sha512-bx+WmtK7K5Jc07IQn2cBDqcP/Kt98u16NiW3EyxqJGhQ1OgFvK6ewc70+AJnBvtjE+MMB70NAXEl8MNOtSxz6g==} + peerDependencies: + '@rsbuild/core': 1.x + peerDependenciesMeta: + '@rsbuild/core': + optional: true + '@rsbuild/plugin-vue-jsx@1.1.0': resolution: {integrity: sha512-ZvYXPs00bG5mMhAFsJ5cVbHgF7Kz+rRpMlRHOJQhKGihFEiUK1Wx8Qfmn5ZrMBIgIGp0BaOnHoGSPH7fVQikCA==} peerDependencies: @@ -6289,6 +6300,16 @@ packages: resolution: {integrity: sha512-kr8SKKw94OI+xTGOkfsvwZQ8mWoikZDd2n8XZHjJVZUARZT+4/VV6cacRS6CLsH9bNm+HFIPU1Zx4CnNnb4qlQ==} engines: {node: '>=6'} + ts-checker-rspack-plugin@1.1.0: + resolution: {integrity: sha512-nhUzSuSjfgVAJjc+vJa9q8uE7MxAbustG9InRp4ylMfIbkqyJjh7gSuEcL//l76ZSwoKcCod+5lv2mNO0Ugh8g==} + engines: {node: '>=16.0.0'} + peerDependencies: + '@rspack/core': ^1.0.0 + typescript: '>=3.8.0' + peerDependenciesMeta: + '@rspack/core': + optional: true + ts-interface-checker@0.1.13: resolution: {integrity: sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==} @@ -8187,6 +8208,18 @@ snapshots: reduce-configs: 1.1.0 sass-embedded: 1.83.0 + '@rsbuild/plugin-type-check@1.2.0(@rsbuild/core@packages+core)(@rspack/core@1.1.8(@swc/helpers@0.5.15))(typescript@5.7.2)': + dependencies: + deepmerge: 4.3.1 + json5: 2.2.3 + reduce-configs: 1.1.0 + ts-checker-rspack-plugin: 1.1.0(@rspack/core@1.1.8(@swc/helpers@0.5.15))(typescript@5.7.2) + optionalDependencies: + '@rsbuild/core': link:packages/core + transitivePeerDependencies: + - '@rspack/core' + - typescript + '@rsbuild/plugin-vue-jsx@1.1.0(@babel/core@7.26.0)(@rsbuild/core@packages+core)': dependencies: '@rsbuild/plugin-babel': 1.0.3(@rsbuild/core@packages+core) @@ -12322,6 +12355,18 @@ snapshots: dependencies: matchit: 1.1.0 + ts-checker-rspack-plugin@1.1.0(@rspack/core@1.1.8(@swc/helpers@0.5.15))(typescript@5.7.2): + dependencies: + '@babel/code-frame': 7.26.2 + '@rspack/lite-tapable': 1.0.1 + chokidar: 3.6.0 + memfs: 4.14.0 + minimatch: 9.0.5 + picocolors: 1.1.1 + typescript: 5.7.2 + optionalDependencies: + '@rspack/core': 1.1.8(@swc/helpers@0.5.15) + ts-interface-checker@0.1.13: {} tsconfig-paths-webpack-plugin@4.2.0: