fix(vite): resolves files with dot suffixes correctly (#28518)
Use `basename` for retrieving the filename in `findFile` function from `nx-tsconfig-paths.plugin` that previously led to an unresolved error for files with dot suffixes e.g.`/dir/file.suffix.ext` <!-- Please make sure you have read the submission guidelines before posting an PR --> <!-- https://github.com/nrwl/nx/blob/master/CONTRIBUTING.md#-submitting-a-pr --> <!-- Please make sure that your commit message follows our format --> <!-- Example: `fix(nx): must begin with lowercase` --> <!-- If this is a particularly complex change or feature addition, you can request a dedicated Nx release for this pull request branch. Mention someone from the Nx team or the `@nrwl/nx-pipelines-reviewers` and they will confirm if the PR warrants its own release for testing purposes, and generate it for you if appropriate. --> ## Current Behavior For files that have the same name but one of them has a suffix, e.g. ```ts - lib1 - file.ts - file.i18n.ts - apps - app1 - main.ts - tsconfig.base.json // with { "paths": { "@lib1/*": ["lib1/*"] }} ``` The resolving process is incorrect because the `import value from '@lib1/file.i18n'` from `apps/app1/main.ts` every time resolves to `file.ts,` and the `parse` method from the `node:path` splits away the suffix from the name. ## Expected Behavior `import value from '@lib1/file.i18n'` should work correctly if you import them from another package ## Related Issue(s) <!-- Please link the issue being fixed so it gets closed when this is merged. --> Fixes #27852 --------- Co-authored-by: Colum Ferry <cferry09@gmail.com>
This commit is contained in:
parent
fca739e5b5
commit
b6d41b617e
@ -158,7 +158,7 @@ describe('@nx/vite/plugin', () => {
|
||||
`generate @nx/react:library libs/${mylib} --bundler=none --unitTestRunner=vitest`
|
||||
);
|
||||
updateFile(`libs/${mylib}/src/styles.css`, `.foo {}`);
|
||||
updateFile(`libs/${mylib}/src/foo.mts`, `export const foo = 'foo';`);
|
||||
updateFile(`libs/${mylib}/src/foo.mjs`, `export const foo = 'foo';`);
|
||||
updateFile(
|
||||
`libs/${mylib}/src/foo.spec.ts`,
|
||||
`
|
||||
|
||||
@ -5,7 +5,7 @@ import {
|
||||
workspaceRoot,
|
||||
} from '@nx/devkit';
|
||||
import { copyFileSync, existsSync } from 'node:fs';
|
||||
import { join, parse, relative, resolve } from 'node:path';
|
||||
import { join, relative, resolve } from 'node:path';
|
||||
import {
|
||||
loadConfig,
|
||||
createMatchPath,
|
||||
@ -18,6 +18,7 @@ import {
|
||||
} from '@nx/js/src/utils/buildable-libs-utils';
|
||||
import { Plugin } from 'vite';
|
||||
import { nxViteBuildCoordinationPlugin } from './nx-vite-build-coordination.plugin';
|
||||
import { findFile } from '../src/utils/nx-tsconfig-paths-find-file';
|
||||
import { isUsingTsSolutionSetup } from '@nx/js/src/utils/typescript/ts-solution-setup';
|
||||
|
||||
export interface nxViteTsPathsOptions {
|
||||
@ -243,33 +244,12 @@ There should at least be a tsconfig.base.json or tsconfig.json in the root of th
|
||||
);
|
||||
|
||||
resolvedFile = findFile(
|
||||
importPath.replace(normalizedImport, joinedPath)
|
||||
importPath.replace(normalizedImport, joinedPath),
|
||||
options.extensions
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return resolvedFile;
|
||||
}
|
||||
|
||||
function findFile(path: string): string {
|
||||
for (const ext of options.extensions) {
|
||||
// Support file with "." in the name.
|
||||
let resolvedPath = resolve(path + ext);
|
||||
if (existsSync(resolvedPath)) {
|
||||
return resolvedPath;
|
||||
}
|
||||
|
||||
// Support file extensions such as .css and .js in the import path.
|
||||
const { dir, name } = parse(path);
|
||||
resolvedPath = resolve(dir, name + ext);
|
||||
if (existsSync(resolvedPath)) {
|
||||
return resolvedPath;
|
||||
}
|
||||
|
||||
const resolvedIndexPath = resolve(path, `index${ext}`);
|
||||
if (existsSync(resolvedIndexPath)) {
|
||||
return resolvedIndexPath;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
123
packages/vite/src/utils/nx-tsconfig-paths-find-file.spec.ts
Normal file
123
packages/vite/src/utils/nx-tsconfig-paths-find-file.spec.ts
Normal file
@ -0,0 +1,123 @@
|
||||
import { findFile as findFileMain } from './nx-tsconfig-paths-find-file';
|
||||
|
||||
describe('@nx/vite nx-tsconfig-paths-find-file', () => {
|
||||
const extensions = ['.ts', '.js', '.mts'];
|
||||
const fs = new Set<string>();
|
||||
const existsSyncImpl = (path: string) => fs.has(path);
|
||||
const findFile = (path: string, exts: string[] = extensions): string =>
|
||||
findFileMain(path, exts, existsSyncImpl);
|
||||
|
||||
beforeAll(() => {
|
||||
[
|
||||
'/dir1/file.ts',
|
||||
'/dir1/file.suffix.ts',
|
||||
'/dir2/inner/index.ts',
|
||||
'/dir2/inner/index.js',
|
||||
'/dir3/file.js',
|
||||
'/dir4/file.css',
|
||||
'/dir5/file.suffix.ts.js',
|
||||
'/dir6/inner.suffix/index.ts',
|
||||
'/file1.mts',
|
||||
].forEach((item) => fs.add(item));
|
||||
});
|
||||
|
||||
afterAll(() => {
|
||||
fs.clear();
|
||||
});
|
||||
|
||||
const cases: Array<{
|
||||
title: string;
|
||||
path: string;
|
||||
expected: string | undefined;
|
||||
extensions?: string[];
|
||||
}> = [
|
||||
{
|
||||
title: 'Should return undefined for missing file',
|
||||
path: '/dir10/file',
|
||||
expected: undefined,
|
||||
},
|
||||
{
|
||||
title: 'Should return undefined for missing index file',
|
||||
path: '/dir10/inner',
|
||||
expected: undefined,
|
||||
},
|
||||
{
|
||||
title: 'Should return existing file path with extension',
|
||||
path: '/dir1/file',
|
||||
expected: '/dir1/file.ts',
|
||||
},
|
||||
{
|
||||
title:
|
||||
'Should return correct file in case with same filename but one with suffix',
|
||||
path: '/dir1/file.suffix',
|
||||
expected: '/dir1/file.suffix.ts',
|
||||
},
|
||||
{
|
||||
title: 'Should return existing file with dir request',
|
||||
path: '/dir2/inner',
|
||||
expected: '/dir2/inner/index.ts',
|
||||
},
|
||||
{
|
||||
title: 'Should return existing file with index request',
|
||||
path: '/dir2/inner/index',
|
||||
expected: '/dir2/inner/index.ts',
|
||||
},
|
||||
{
|
||||
title: 'Should return existing file with js extension',
|
||||
path: '/dir3/file',
|
||||
expected: '/dir3/file.js',
|
||||
},
|
||||
{
|
||||
title: 'Should return undefined for non presented extension',
|
||||
path: '/dir4/file',
|
||||
expected: undefined,
|
||||
},
|
||||
{
|
||||
title: 'Should return undefined for unknown file',
|
||||
path: '/dir5/file.suffix',
|
||||
expected: undefined,
|
||||
},
|
||||
{
|
||||
title: 'Should return js file with strange suffix filename',
|
||||
path: '/dir5/file.suffix.ts',
|
||||
expected: '/dir5/file.suffix.ts.js',
|
||||
},
|
||||
{
|
||||
title: 'Should return index file for dir with suffixed name',
|
||||
path: '/dir6/inner.suffix',
|
||||
expected: '/dir6/inner.suffix/index.ts',
|
||||
},
|
||||
{
|
||||
title: 'Should return file for import with extension',
|
||||
path: '/dir1/file.ts',
|
||||
expected: '/dir1/file.ts',
|
||||
},
|
||||
{
|
||||
title: 'Should return file with .js ext instead of .ts',
|
||||
path: '/dir2/inner/index.js',
|
||||
expected: '/dir2/inner/index.js',
|
||||
},
|
||||
{
|
||||
title: 'Should return css file that imported with query',
|
||||
path: '/dir4/file.css?inline',
|
||||
expected: '/dir4/file.css',
|
||||
extensions: ['.js', '.css'],
|
||||
},
|
||||
{
|
||||
title: 'Should return file with .mts',
|
||||
path: '/file1.mts',
|
||||
expected: '/file1.mts',
|
||||
},
|
||||
{
|
||||
title: 'Should return file',
|
||||
path: '/file1',
|
||||
expected: '/file1.mts',
|
||||
},
|
||||
];
|
||||
|
||||
cases.forEach(({ title, path, expected, extensions }) => {
|
||||
it(title, () => {
|
||||
expect(findFile(path, extensions)).toEqual(expected);
|
||||
});
|
||||
});
|
||||
});
|
||||
27
packages/vite/src/utils/nx-tsconfig-paths-find-file.ts
Normal file
27
packages/vite/src/utils/nx-tsconfig-paths-find-file.ts
Normal file
@ -0,0 +1,27 @@
|
||||
import { existsSync } from 'node:fs';
|
||||
import { resolve, basename, dirname } from 'node:path';
|
||||
|
||||
export function findFile(
|
||||
path: string,
|
||||
extensions: string[],
|
||||
existsSyncImpl: typeof existsSync = existsSync
|
||||
): string {
|
||||
const queryLessPath = path.replace(/\?\S*$/, '');
|
||||
|
||||
for (const ext of extensions) {
|
||||
const dir = dirname(path);
|
||||
// Support file extensions such as .css and .js in the import path.
|
||||
// While still allowing for '.suffix'
|
||||
const name = basename(queryLessPath, ext);
|
||||
|
||||
const resolvedPath = resolve(dir, name + ext);
|
||||
if (existsSyncImpl(resolvedPath)) {
|
||||
return resolvedPath;
|
||||
}
|
||||
|
||||
const resolvedIndexPath = resolve(path, `index${ext}`);
|
||||
if (existsSyncImpl(resolvedIndexPath)) {
|
||||
return resolvedIndexPath;
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user