diff --git a/e2e/cases/source/source-include-dependency/index.test.ts b/e2e/cases/source/source-include-dependency/index.test.ts new file mode 100644 index 0000000000..728cc874a6 --- /dev/null +++ b/e2e/cases/source/source-include-dependency/index.test.ts @@ -0,0 +1,27 @@ +import { join } from 'node:path'; +import { expect, test } from '@e2e/helper'; +import { outputFileSync } from 'fs-extra'; + +// https://github.com/web-infra-dev/rsbuild/issues/6372 +test('should include dependency via `source.include` and `require.resolve`', async ({ + build, +}) => { + const packagePath = join(__dirname, 'node_modules', 'test'); + outputFileSync( + join(packagePath, 'index.js'), + 'export const value = window?.value;', + ); + outputFileSync( + join(packagePath, 'package.json'), + JSON.stringify({ name: 'test', main: 'index.js' }), + ); + + const rsbuild = await build({ + catchBuildError: true, + }); + + expect(rsbuild.buildError).toBeFalsy(); + expect( + rsbuild.logs.find((log) => log.includes('Syntax check passed')), + ).toBeTruthy(); +}); diff --git a/e2e/cases/source/source-include-dependency/rsbuild.config.ts b/e2e/cases/source/source-include-dependency/rsbuild.config.ts new file mode 100644 index 0000000000..059cab296d --- /dev/null +++ b/e2e/cases/source/source-include-dependency/rsbuild.config.ts @@ -0,0 +1,13 @@ +import { dirname } from 'node:path'; +import { defineConfig } from '@rsbuild/core'; +import { pluginCheckSyntax } from '@rsbuild/plugin-check-syntax'; + +export default defineConfig({ + plugins: [pluginCheckSyntax()], + source: { + include: [dirname(require.resolve('test'))], + }, + output: { + overrideBrowserslist: ['Chrome >= 51'], + }, +}); diff --git a/e2e/cases/source/source-include-dependency/src/index.js b/e2e/cases/source/source-include-dependency/src/index.js new file mode 100644 index 0000000000..a40425d2d9 --- /dev/null +++ b/e2e/cases/source/source-include-dependency/src/index.js @@ -0,0 +1,3 @@ +import { value } from 'test'; + +console.log(value); diff --git a/packages/core/src/constants.ts b/packages/core/src/constants.ts index 61df39a099..5c4fc99cac 100644 --- a/packages/core/src/constants.ts +++ b/packages/core/src/constants.ts @@ -4,6 +4,7 @@ import { fileURLToPath } from 'node:url'; export const __filename: string = fileURLToPath(import.meta.url); export const __dirname: string = dirname(__filename); export const isDeno: boolean = typeof Deno !== 'undefined'; +export const isWindows: boolean = process.platform === 'win32'; // Paths export const ROOT_DIST_DIR = 'dist'; diff --git a/packages/core/src/helpers/path.ts b/packages/core/src/helpers/path.ts index 364a191977..a5799cbf73 100644 --- a/packages/core/src/helpers/path.ts +++ b/packages/core/src/helpers/path.ts @@ -1,5 +1,6 @@ -import { isAbsolute, join, relative, sep } from 'node:path'; -import { COMPILED_PATH } from '../constants'; +import { isAbsolute, join, relative, sep, win32 } from 'node:path'; +import { COMPILED_PATH, isWindows } from '../constants'; +import type { Rspack } from '../types'; export function toRelativePath(base: string, filepath: string): string { const relativePath = relative(base, filepath); @@ -79,3 +80,23 @@ export const toPosixPath = (filepath: string): string => { } return filepath.replace(/\\/g, '/'); }; + +/** + * Normalize filepaths for `source.include` and `source.exclude` configuration. + * On Windows, `require.resolve` returns paths with posix forward slashes, + * This function normalizes the path to use backslashes. + */ +export const normalizeRuleConditionPath = ( + filepath: Rspack.RuleSetCondition, +): Rspack.RuleSetCondition => { + if ( + isWindows && + typeof filepath === 'string' && + filepath.includes('/') && + win32.isAbsolute(filepath) + ) { + return filepath.replace(/\//g, '\\'); + } + + return filepath; +}; diff --git a/packages/core/src/plugins/rsdoctor.ts b/packages/core/src/plugins/rsdoctor.ts index 9627d731ab..9977abe8bd 100644 --- a/packages/core/src/plugins/rsdoctor.ts +++ b/packages/core/src/plugins/rsdoctor.ts @@ -1,6 +1,7 @@ import { createRequire } from 'node:module'; import { pathToFileURL } from 'node:url'; import type { Configuration } from '@rspack/core'; +import { isWindows } from '../constants'; import { color } from '../helpers'; import { logger } from '../logger'; import type { BundlerPluginInstance, RsbuildPlugin } from '../types'; @@ -65,10 +66,9 @@ export const pluginRsdoctor = (): RsbuildPlugin => ({ let module: RsdoctorExports; try { - const moduleURL = - process.platform === 'win32' - ? pathToFileURL(packagePath).href - : packagePath; + const moduleURL = isWindows + ? pathToFileURL(packagePath).href + : packagePath; module = await import(moduleURL); } catch { logger.error( diff --git a/packages/core/src/plugins/swc.ts b/packages/core/src/plugins/swc.ts index f9a4f49d07..346d29852f 100644 --- a/packages/core/src/plugins/swc.ts +++ b/packages/core/src/plugins/swc.ts @@ -17,6 +17,7 @@ import { isFunction, isWebTarget, } from '../helpers'; +import { normalizeRuleConditionPath } from '../helpers/path'; import type { NormalizedEnvironmentConfig, NormalizedSourceConfig, @@ -55,11 +56,11 @@ function applyScriptCondition({ } for (const condition of config.source.include || []) { - rule.include.add(condition); + rule.include.add(normalizeRuleConditionPath(condition)); } for (const condition of config.source.exclude || []) { - rule.exclude.add(condition); + rule.exclude.add(normalizeRuleConditionPath(condition)); } }