From bf91e64e6e318b77446fcb4c07b99ce5fa8ad91d Mon Sep 17 00:00:00 2001 From: Timeless0911 <1604889533@qq.com> Date: Thu, 15 Aug 2024 15:09:16 +0800 Subject: [PATCH 1/4] feat: add extension for relative import in bundleless mode --- e2e/cases/bundle-false/index.test.ts | 12 +++++++++ .../relative-import/rslib.config.ts | 18 +++++++++++++ .../bundle-false/relative-import/src/bar.ts | 1 + .../bundle-false/relative-import/src/index.ts | 3 +++ .../relative-import/tsconfig.json | 7 +++++ e2e/scripts/shared.ts | 13 +++++----- packages/core/src/config.ts | 26 +++++++++++++++---- packages/core/src/utils/helper.ts | 6 +++-- packages/core/tests/helper.test.ts | 25 ++++++++++++++++-- 9 files changed, 96 insertions(+), 15 deletions(-) create mode 100644 e2e/cases/bundle-false/relative-import/rslib.config.ts create mode 100644 e2e/cases/bundle-false/relative-import/src/bar.ts create mode 100644 e2e/cases/bundle-false/relative-import/src/index.ts create mode 100644 e2e/cases/bundle-false/relative-import/tsconfig.json diff --git a/e2e/cases/bundle-false/index.test.ts b/e2e/cases/bundle-false/index.test.ts index 48fb66de..598ee4f0 100644 --- a/e2e/cases/bundle-false/index.test.ts +++ b/e2e/cases/bundle-false/index.test.ts @@ -39,3 +39,15 @@ test('single file', async () => { ] `); }); + +test('auto add extension for relative import', async () => { + const fixturePath = join(__dirname, 'relative-import'); + const { contents } = await buildAndGetResults(fixturePath); + + expect(Object.values(contents.esm)[1]).toContain( + 'import * as __WEBPACK_EXTERNAL_MODULE__bar_js__ from "./bar.js";', + ); + expect(Object.values(contents.cjs)[1]).toContain( + 'var external_bar_js_namespaceObject = require("./bar.js");', + ); +}); diff --git a/e2e/cases/bundle-false/relative-import/rslib.config.ts b/e2e/cases/bundle-false/relative-import/rslib.config.ts new file mode 100644 index 00000000..c5d9857f --- /dev/null +++ b/e2e/cases/bundle-false/relative-import/rslib.config.ts @@ -0,0 +1,18 @@ +import { generateBundleCjsConfig, generateBundleEsmConfig } from '@e2e/helper'; +import { defineConfig } from '@rslib/core'; + +export default defineConfig({ + lib: [ + generateBundleEsmConfig(__dirname, { + bundle: false, + }), + generateBundleCjsConfig(__dirname, { + bundle: false, + }), + ], + source: { + entry: { + main: ['./src/**'], + }, + }, +}); diff --git a/e2e/cases/bundle-false/relative-import/src/bar.ts b/e2e/cases/bundle-false/relative-import/src/bar.ts new file mode 100644 index 00000000..9f173868 --- /dev/null +++ b/e2e/cases/bundle-false/relative-import/src/bar.ts @@ -0,0 +1 @@ +export const bar = 'bar'; diff --git a/e2e/cases/bundle-false/relative-import/src/index.ts b/e2e/cases/bundle-false/relative-import/src/index.ts new file mode 100644 index 00000000..56f92330 --- /dev/null +++ b/e2e/cases/bundle-false/relative-import/src/index.ts @@ -0,0 +1,3 @@ +import { bar } from './bar'; + +export const foo = 'foo' + bar; diff --git a/e2e/cases/bundle-false/relative-import/tsconfig.json b/e2e/cases/bundle-false/relative-import/tsconfig.json new file mode 100644 index 00000000..888d3e46 --- /dev/null +++ b/e2e/cases/bundle-false/relative-import/tsconfig.json @@ -0,0 +1,7 @@ +{ + "extends": "@rslib/tsconfig/base", + "compilerOptions": { + "baseUrl": "./" + }, + "include": ["src"] +} diff --git a/e2e/scripts/shared.ts b/e2e/scripts/shared.ts index fa328c6c..2bee9296 100644 --- a/e2e/scripts/shared.ts +++ b/e2e/scripts/shared.ts @@ -55,7 +55,6 @@ type BuildResult = { export async function getResults( rslibConfig: RslibConfig, - fixturePath: string, type: 'js' | 'dts', ): Promise> { const files: Record = {}; @@ -81,7 +80,9 @@ export async function getResults( ignore: ['**/*.map'], }); - const fileSet = Object.keys(content).filter((file) => regex.test(file)); + const fileSet = Object.keys(content) + .filter((file) => regex.test(file)) + .sort(); const filterContent: Record = {}; for (const key of fileSet) { if (content[key]) { @@ -90,7 +91,7 @@ export async function getResults( } if (fileSet.length) { - files[libConfig.format!] = fileSet.sort(); + files[libConfig.format!] = fileSet; contents[libConfig.format!] = filterContent; } @@ -131,8 +132,8 @@ export async function buildAndGetResults( origin: { bundlerConfigs, rsbuildConfig }, } = await rsbuildInstance.inspectConfig({ verbose: true }); if (type === 'all') { - const jsResults = await getResults(rslibConfig, fixturePath, 'js'); - const dtsResults = await getResults(rslibConfig, fixturePath, 'dts'); + const jsResults = await getResults(rslibConfig, 'js'); + const dtsResults = await getResults(rslibConfig, 'dts'); return { js: { contents: jsResults.contents, @@ -155,7 +156,7 @@ export async function buildAndGetResults( }; } - const results = await getResults(rslibConfig, fixturePath, type); + const results = await getResults(rslibConfig, type); return { contents: results.contents, files: results.files, diff --git a/packages/core/src/config.ts b/packages/core/src/config.ts index 1d065fc1..af64136d 100644 --- a/packages/core/src/config.ts +++ b/packages/core/src/config.ts @@ -26,6 +26,7 @@ import { calcLongestCommonPath, color, isObject, + isRelativePath, nodeBuiltInModules, readPackageJson, } from './utils/helper'; @@ -241,6 +242,7 @@ const composeAutoExtensionConfig = ( pkgJson?: PkgJson, ): { config: RsbuildConfig; + jsExtension: string; dtsExtension: string; } => { const { jsExtension, dtsExtension } = getDefaultExtension({ @@ -257,6 +259,7 @@ const composeAutoExtensionConfig = ( }, }, }, + jsExtension, dtsExtension, }; }; @@ -381,7 +384,10 @@ const composeEntryConfig = async ( }; }; -const composeBundleConfig = (bundle = true): RsbuildConfig => { +const composeBundleConfig = ( + jsExtension: string, + bundle = true, +): RsbuildConfig => { if (bundle) return {}; return { @@ -391,7 +397,14 @@ const composeBundleConfig = (bundle = true): RsbuildConfig => { // Issuer is not empty string when the module is imported by another module. // Prevent from externalizing entry modules here. if (data.contextInfo.issuer) { - return callback(null, data.request); + // Node.js ECMAScript module loader does no extension searching. + // So we add a file extension here when data.request is a relative path + return callback( + null, + isRelativePath(data.request) + ? `${data.request}${jsExtension}` + : data.request, + ); } callback(); }, @@ -474,9 +487,12 @@ async function composeLibRsbuildConfig( const { format, autoExtension = true, autoExternal = true } = config; const formatConfig = composeFormatConfig(format!); - const { config: autoExtensionConfig, dtsExtension } = - composeAutoExtensionConfig(format!, autoExtension, pkgJson); - const bundleConfig = composeBundleConfig(config.bundle); + const { + config: autoExtensionConfig, + jsExtension, + dtsExtension, + } = composeAutoExtensionConfig(format!, autoExtension, pkgJson); + const bundleConfig = composeBundleConfig(jsExtension, config.bundle); const targetConfig = composeTargetConfig(config.output?.target); const syntaxConfig = composeSyntaxConfig( config.output?.syntax, diff --git a/packages/core/src/utils/helper.ts b/packages/core/src/utils/helper.ts index b4d43352..ab01d89f 100644 --- a/packages/core/src/utils/helper.ts +++ b/packages/core/src/utils/helper.ts @@ -71,7 +71,7 @@ export const nodeBuiltInModules: Array = [ 'pnpapi', ]; -async function calcLongestCommonPath( +export async function calcLongestCommonPath( absPaths: string[], ): Promise { if (absPaths.length === 0) { @@ -126,4 +126,6 @@ export const readPackageJson = (rootPath: string): undefined | PkgJson => { export const isObject = (obj: unknown): obj is Record => Object.prototype.toString.call(obj) === '[object Object]'; -export { color, calcLongestCommonPath }; +export const isRelativePath = (p: string): boolean => /^\.\.?($|[\\/])/.test(p); + +export { color }; diff --git a/packages/core/tests/helper.test.ts b/packages/core/tests/helper.test.ts index 15fd5fdc..d116b332 100644 --- a/packages/core/tests/helper.test.ts +++ b/packages/core/tests/helper.test.ts @@ -1,6 +1,6 @@ import { join } from 'node:path'; -import { expect, it, vi } from 'vitest'; -import { readPackageJson } from '../src/utils/helper'; +import { describe, expect, it, test, vi } from 'vitest'; +import { isRelativePath, readPackageJson } from '../src/utils/helper'; vi.mock('rslog'); @@ -11,3 +11,24 @@ it('readPackageJson correctly', async () => { type: 'module', }); }); + +describe('isRelativePath', () => { + test('should return true for relative paths', () => { + expect(isRelativePath('../Documents/file.txt')).toBe(true); + expect(isRelativePath('./file.txt')).toBe(true); + }); + + test('should return false for absolute paths', () => { + expect(isRelativePath('file.txt')).toBe(false); + expect(isRelativePath('/Users/username/Documents/file.txt')).toBe(false); + expect(isRelativePath('C:\\Users\\username\\Documents\\file.txt')).toBe( + false, + ); + }); + + test('should handle edge cases', () => { + expect(isRelativePath('')).toBe(false); // empty path + expect(isRelativePath('.')).toBe(true); // current directory + expect(isRelativePath('./')).toBe(true); // current directory + }); +}); From 4af6d0d1a3266680f43813f03e0d5ce83c8751d3 Mon Sep 17 00:00:00 2001 From: Timeless0911 <1604889533@qq.com> Date: Thu, 15 Aug 2024 15:52:52 +0800 Subject: [PATCH 2/4] chore: update --- packages/core/src/config.ts | 2 +- packages/core/src/utils/helper.ts | 2 -- packages/core/tests/helper.test.ts | 25 ++----------------------- 3 files changed, 3 insertions(+), 26 deletions(-) diff --git a/packages/core/src/config.ts b/packages/core/src/config.ts index af64136d..660613e2 100644 --- a/packages/core/src/config.ts +++ b/packages/core/src/config.ts @@ -401,7 +401,7 @@ const composeBundleConfig = ( // So we add a file extension here when data.request is a relative path return callback( null, - isRelativePath(data.request) + data.request[0] === '.' ? `${data.request}${jsExtension}` : data.request, ); diff --git a/packages/core/src/utils/helper.ts b/packages/core/src/utils/helper.ts index ab01d89f..58585736 100644 --- a/packages/core/src/utils/helper.ts +++ b/packages/core/src/utils/helper.ts @@ -126,6 +126,4 @@ export const readPackageJson = (rootPath: string): undefined | PkgJson => { export const isObject = (obj: unknown): obj is Record => Object.prototype.toString.call(obj) === '[object Object]'; -export const isRelativePath = (p: string): boolean => /^\.\.?($|[\\/])/.test(p); - export { color }; diff --git a/packages/core/tests/helper.test.ts b/packages/core/tests/helper.test.ts index d116b332..15fd5fdc 100644 --- a/packages/core/tests/helper.test.ts +++ b/packages/core/tests/helper.test.ts @@ -1,6 +1,6 @@ import { join } from 'node:path'; -import { describe, expect, it, test, vi } from 'vitest'; -import { isRelativePath, readPackageJson } from '../src/utils/helper'; +import { expect, it, vi } from 'vitest'; +import { readPackageJson } from '../src/utils/helper'; vi.mock('rslog'); @@ -11,24 +11,3 @@ it('readPackageJson correctly', async () => { type: 'module', }); }); - -describe('isRelativePath', () => { - test('should return true for relative paths', () => { - expect(isRelativePath('../Documents/file.txt')).toBe(true); - expect(isRelativePath('./file.txt')).toBe(true); - }); - - test('should return false for absolute paths', () => { - expect(isRelativePath('file.txt')).toBe(false); - expect(isRelativePath('/Users/username/Documents/file.txt')).toBe(false); - expect(isRelativePath('C:\\Users\\username\\Documents\\file.txt')).toBe( - false, - ); - }); - - test('should handle edge cases', () => { - expect(isRelativePath('')).toBe(false); // empty path - expect(isRelativePath('.')).toBe(true); // current directory - expect(isRelativePath('./')).toBe(true); // current directory - }); -}); From 0f41f81198fe1c70c8113b6e315372341e83cc1b Mon Sep 17 00:00:00 2001 From: Timeless0911 <1604889533@qq.com> Date: Thu, 15 Aug 2024 15:54:26 +0800 Subject: [PATCH 3/4] chore: update --- packages/core/src/config.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/core/src/config.ts b/packages/core/src/config.ts index 660613e2..51fc3768 100644 --- a/packages/core/src/config.ts +++ b/packages/core/src/config.ts @@ -26,7 +26,6 @@ import { calcLongestCommonPath, color, isObject, - isRelativePath, nodeBuiltInModules, readPackageJson, } from './utils/helper'; From 9047db47221175e254ca7e035c2aaeb2bb82167a Mon Sep 17 00:00:00 2001 From: Timeless0911 <1604889533@qq.com> Date: Thu, 15 Aug 2024 16:13:23 +0800 Subject: [PATCH 4/4] chore: update --- e2e/cases/bundle-false/index.test.ts | 2 +- e2e/cases/bundle-false/relative-import/package.json | 6 ++++++ pnpm-lock.yaml | 2 ++ 3 files changed, 9 insertions(+), 1 deletion(-) create mode 100644 e2e/cases/bundle-false/relative-import/package.json diff --git a/e2e/cases/bundle-false/index.test.ts b/e2e/cases/bundle-false/index.test.ts index 598ee4f0..daffa7bc 100644 --- a/e2e/cases/bundle-false/index.test.ts +++ b/e2e/cases/bundle-false/index.test.ts @@ -48,6 +48,6 @@ test('auto add extension for relative import', async () => { 'import * as __WEBPACK_EXTERNAL_MODULE__bar_js__ from "./bar.js";', ); expect(Object.values(contents.cjs)[1]).toContain( - 'var external_bar_js_namespaceObject = require("./bar.js");', + 'var external_bar_cjs_namespaceObject = require("./bar.cjs");', ); }); diff --git a/e2e/cases/bundle-false/relative-import/package.json b/e2e/cases/bundle-false/relative-import/package.json new file mode 100644 index 00000000..c09fcee2 --- /dev/null +++ b/e2e/cases/bundle-false/relative-import/package.json @@ -0,0 +1,6 @@ +{ + "name": "bundle-false-relative-import-test", + "version": "1.0.0", + "private": true, + "type": "module" +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index e3132490..3f70aab7 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -138,6 +138,8 @@ importers: specifier: ^18.3.1 version: 18.3.1 + e2e/cases/bundle-false/relative-import: {} + e2e/cases/dts/bundle-false/auto-extension: {} e2e/cases/dts/bundle/abort-on-error: {}