Skip to content

Commit af26637

Browse files
authored
feat: add js extension for relative import in bundleless mode (#90)
1 parent fc45a6c commit af26637

File tree

10 files changed

+78
-13
lines changed

10 files changed

+78
-13
lines changed

e2e/cases/bundle-false/index.test.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,3 +39,15 @@ test('single file', async () => {
3939
]
4040
`);
4141
});
42+
43+
test('auto add extension for relative import', async () => {
44+
const fixturePath = join(__dirname, 'relative-import');
45+
const { contents } = await buildAndGetResults(fixturePath);
46+
47+
expect(Object.values(contents.esm)[1]).toContain(
48+
'import * as __WEBPACK_EXTERNAL_MODULE__bar_js__ from "./bar.js";',
49+
);
50+
expect(Object.values(contents.cjs)[1]).toContain(
51+
'var external_bar_cjs_namespaceObject = require("./bar.cjs");',
52+
);
53+
});
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
{
2+
"name": "bundle-false-relative-import-test",
3+
"version": "1.0.0",
4+
"private": true,
5+
"type": "module"
6+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import { generateBundleCjsConfig, generateBundleEsmConfig } from '@e2e/helper';
2+
import { defineConfig } from '@rslib/core';
3+
4+
export default defineConfig({
5+
lib: [
6+
generateBundleEsmConfig(__dirname, {
7+
bundle: false,
8+
}),
9+
generateBundleCjsConfig(__dirname, {
10+
bundle: false,
11+
}),
12+
],
13+
source: {
14+
entry: {
15+
main: ['./src/**'],
16+
},
17+
},
18+
});
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export const bar = 'bar';
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
import { bar } from './bar';
2+
3+
export const foo = 'foo' + bar;
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{
2+
"extends": "@rslib/tsconfig/base",
3+
"compilerOptions": {
4+
"baseUrl": "./"
5+
},
6+
"include": ["src"]
7+
}

e2e/scripts/shared.ts

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,6 @@ type BuildResult = {
5555

5656
export async function getResults(
5757
rslibConfig: RslibConfig,
58-
fixturePath: string,
5958
type: 'js' | 'dts',
6059
): Promise<Omit<BuildResult, 'rspackConfig' | 'rsbuildConfig' | 'isSuccess'>> {
6160
const files: Record<string, string[]> = {};
@@ -81,7 +80,9 @@ export async function getResults(
8180
ignore: ['**/*.map'],
8281
});
8382

84-
const fileSet = Object.keys(content).filter((file) => regex.test(file));
83+
const fileSet = Object.keys(content)
84+
.filter((file) => regex.test(file))
85+
.sort();
8586
const filterContent: Record<string, string> = {};
8687
for (const key of fileSet) {
8788
if (content[key]) {
@@ -90,7 +91,7 @@ export async function getResults(
9091
}
9192

9293
if (fileSet.length) {
93-
files[libConfig.format!] = fileSet.sort();
94+
files[libConfig.format!] = fileSet;
9495
contents[libConfig.format!] = filterContent;
9596
}
9697

@@ -131,8 +132,8 @@ export async function buildAndGetResults(
131132
origin: { bundlerConfigs, rsbuildConfig },
132133
} = await rsbuildInstance.inspectConfig({ verbose: true });
133134
if (type === 'all') {
134-
const jsResults = await getResults(rslibConfig, fixturePath, 'js');
135-
const dtsResults = await getResults(rslibConfig, fixturePath, 'dts');
135+
const jsResults = await getResults(rslibConfig, 'js');
136+
const dtsResults = await getResults(rslibConfig, 'dts');
136137
return {
137138
js: {
138139
contents: jsResults.contents,
@@ -155,7 +156,7 @@ export async function buildAndGetResults(
155156
};
156157
}
157158

158-
const results = await getResults(rslibConfig, fixturePath, type);
159+
const results = await getResults(rslibConfig, type);
159160
return {
160161
contents: results.contents,
161162
files: results.files,

packages/core/src/config.ts

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -241,6 +241,7 @@ const composeAutoExtensionConfig = (
241241
pkgJson?: PkgJson,
242242
): {
243243
config: RsbuildConfig;
244+
jsExtension: string;
244245
dtsExtension: string;
245246
} => {
246247
const { jsExtension, dtsExtension } = getDefaultExtension({
@@ -257,6 +258,7 @@ const composeAutoExtensionConfig = (
257258
},
258259
},
259260
},
261+
jsExtension,
260262
dtsExtension,
261263
};
262264
};
@@ -381,7 +383,10 @@ const composeEntryConfig = async (
381383
};
382384
};
383385

384-
const composeBundleConfig = (bundle = true): RsbuildConfig => {
386+
const composeBundleConfig = (
387+
jsExtension: string,
388+
bundle = true,
389+
): RsbuildConfig => {
385390
if (bundle) return {};
386391

387392
return {
@@ -391,7 +396,14 @@ const composeBundleConfig = (bundle = true): RsbuildConfig => {
391396
// Issuer is not empty string when the module is imported by another module.
392397
// Prevent from externalizing entry modules here.
393398
if (data.contextInfo.issuer) {
394-
return callback(null, data.request);
399+
// Node.js ECMAScript module loader does no extension searching.
400+
// So we add a file extension here when data.request is a relative path
401+
return callback(
402+
null,
403+
data.request[0] === '.'
404+
? `${data.request}${jsExtension}`
405+
: data.request,
406+
);
395407
}
396408
callback();
397409
},
@@ -474,9 +486,12 @@ async function composeLibRsbuildConfig(
474486

475487
const { format, autoExtension = true, autoExternal = true } = config;
476488
const formatConfig = composeFormatConfig(format!);
477-
const { config: autoExtensionConfig, dtsExtension } =
478-
composeAutoExtensionConfig(format!, autoExtension, pkgJson);
479-
const bundleConfig = composeBundleConfig(config.bundle);
489+
const {
490+
config: autoExtensionConfig,
491+
jsExtension,
492+
dtsExtension,
493+
} = composeAutoExtensionConfig(format!, autoExtension, pkgJson);
494+
const bundleConfig = composeBundleConfig(jsExtension, config.bundle);
480495
const targetConfig = composeTargetConfig(config.output?.target);
481496
const syntaxConfig = composeSyntaxConfig(
482497
config.output?.syntax,

packages/core/src/utils/helper.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ export const nodeBuiltInModules: Array<string | RegExp> = [
7171
'pnpapi',
7272
];
7373

74-
async function calcLongestCommonPath(
74+
export async function calcLongestCommonPath(
7575
absPaths: string[],
7676
): Promise<string | null> {
7777
if (absPaths.length === 0) {
@@ -126,4 +126,4 @@ export const readPackageJson = (rootPath: string): undefined | PkgJson => {
126126
export const isObject = (obj: unknown): obj is Record<string, any> =>
127127
Object.prototype.toString.call(obj) === '[object Object]';
128128

129-
export { color, calcLongestCommonPath };
129+
export { color };

pnpm-lock.yaml

Lines changed: 2 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)