nx/e2e/vite/src/vite.test.ts
Konstantin Kai b6d41b617e
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>
2024-12-12 20:08:53 +00:00

244 lines
7.2 KiB
TypeScript

import {
cleanupProject,
killProcessAndPorts,
newProject,
readJson,
runCLI,
runCommandUntil,
uniq,
updateFile,
updateJson,
} from '@nx/e2e/utils';
import { ChildProcess } from 'child_process';
import { names } from '@nx/devkit';
const myApp = uniq('my-app');
const myVueApp = uniq('my-vue-app');
describe('@nx/vite/plugin', () => {
let proj: string;
let originalEnv: string;
beforeAll(() => {
originalEnv = process.env.NX_ADD_PLUGINS;
process.env.NX_ADD_PLUGINS = 'true';
});
afterAll(() => {
process.env.NX_ADD_PLUGINS = originalEnv;
cleanupProject();
});
describe('with react', () => {
beforeAll(() => {
proj = newProject({
packages: ['@nx/react', '@nx/vue'],
});
runCLI(
`generate @nx/react:app ${myApp} --directory=apps/${myApp} --bundler=vite --unitTestRunner=vitest`
);
runCLI(
`generate @nx/vue:app ${myVueApp} --directory=apps/${myVueApp} --unitTestRunner=vitest`
);
});
afterAll(() => {
cleanupProject();
});
describe('build and test React app', () => {
it('should build application', () => {
expect(() => runCLI(`build ${myApp}`)).not.toThrow();
}, 200_000);
it('should test application', () => {
expect(() => runCLI(`test ${myApp} --watch=false`)).not.toThrow();
}, 200_000);
});
describe('build and test Vue app', () => {
it('should build application', () => {
expect(() => runCLI(`build ${myVueApp}`)).not.toThrow();
}, 200_000);
it('should test application', () => {
expect(() => runCLI(`test ${myVueApp} --watch=false`)).not.toThrow();
}, 200_000);
});
describe('should support buildable libraries', () => {
it('should build the library and application successfully', () => {
const myApp = uniq('myapp');
runCLI(
`generate @nx/react:app ${myApp} --directory=apps/${myApp} --bundler=vite --unitTestRunner=vitest`
);
const myBuildableLib = uniq('mybuildablelib');
runCLI(
`generate @nx/react:library ${myBuildableLib} --directory=libs/${myBuildableLib} --bundler=vite --unitTestRunner=vitest --buildable`
);
const exportedLibraryComponent = names(myBuildableLib).className;
updateFile(
`apps/${myApp}/src/app/App.tsx`,
`import NxWelcome from './nx-welcome';
import { ${exportedLibraryComponent} } from '@proj/${myBuildableLib}';
export function App() {
return (
<div>
<${exportedLibraryComponent} />
<NxWelcome title="viteib" />
</div>
);
}
export default App;`
);
updateFile(
`apps/${myApp}/vite.config.ts`,
`/// <reference types='vitest' />
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
import { nxViteTsPaths } from '@nx/vite/plugins/nx-tsconfig-paths.plugin';
export default defineConfig({
root: __dirname,
cacheDir: '../../node_modules/.vite/${myApp}',
server: {
port: 4200,
host: 'localhost',
},
preview: {
port: 4300,
host: 'localhost',
},
plugins: [react(), nxViteTsPaths({buildLibsFromSource: false})],
build: {
outDir: '../../dist/${myApp}',
emptyOutDir: true,
reportCompressedSize: true,
commonjsOptions: {
transformMixedEsModules: true,
},
},
});`
);
expect(() => runCLI(`build ${myApp}`)).not.toThrow();
});
});
it('should run serve-static', async () => {
let process: ChildProcess;
const port = 8081;
try {
process = await runCommandUntil(
`serve-static ${myApp} --port=${port}`,
(output) => {
return output.includes(`http://localhost:${port}`);
}
);
} catch (err) {
console.error(err);
}
// port and process cleanup
if (process && process.pid) {
await killProcessAndPorts(process.pid, port);
}
});
it('should support importing .js and .css files in tsconfig path', () => {
const mylib = uniq('mylib');
runCLI(
`generate @nx/react:library libs/${mylib} --bundler=none --unitTestRunner=vitest`
);
updateFile(`libs/${mylib}/src/styles.css`, `.foo {}`);
updateFile(`libs/${mylib}/src/foo.mjs`, `export const foo = 'foo';`);
updateFile(
`libs/${mylib}/src/foo.spec.ts`,
`
import styles from '~/styles.css?inline';
import { foo } from '~/foo.mjs';
test('should work', () => {
expect(styles).toBeDefined();
expect(foo).toBeDefined();
});
`
);
updateJson('tsconfig.base.json', (json) => {
json.compilerOptions.paths['~/*'] = [`libs/${mylib}/src/*`];
return json;
});
expect(() => runCLI(`test ${mylib}`)).not.toThrow();
});
it('should support importing files with "." in the name in tsconfig path', () => {
const mylib = uniq('mylib');
runCLI(
`generate @nx/react:library libs/${mylib} --bundler=none --unitTestRunner=vitest`
);
updateFile(`libs/${mylib}/src/styles.module.css`, `.foo {}`);
updateFile(`libs/${mylib}/src/foo.enum.ts`, `export const foo = 'foo';`);
updateFile(`libs/${mylib}/src/bar.enum.ts`, `export const bar = 'bar';`);
updateFile(
`libs/${mylib}/src/foo.spec.ts`,
`
import styles from '~/styles.module.css';
import { foo } from '~/foo.enum.ts';
import { bar } from '~/bar.enum';
test('should work', () => {
expect(styles).toBeDefined();
expect(foo).toBeDefined();
expect(bar).toBeDefined();
});
`
);
updateJson('tsconfig.base.json', (json) => {
json.compilerOptions.paths['~/*'] = [`libs/${mylib}/src/*`];
return json;
});
expect(() => runCLI(`test ${mylib}`)).not.toThrow();
});
});
describe('react with vitest only', () => {
const reactVitest = uniq('reactVitest');
beforeAll(() => {
proj = newProject({
packages: ['@nx/vite', '@nx/react'],
});
runCLI(
`generate @nx/react:app ${reactVitest} --bundler=webpack --unitTestRunner=vitest --e2eTestRunner=none`
);
});
afterAll(() => {
cleanupProject();
});
it('should contain targets build, test and lint', () => {
const nxJson = readJson('nx.json');
const vitePlugin = nxJson.plugins.find(
(p) => p.plugin === '@nx/vite/plugin'
);
expect(vitePlugin).toBeDefined();
expect(vitePlugin.options.buildTargetName).toEqual('build');
expect(vitePlugin.options.testTargetName).toEqual('test');
});
it('project.json should not contain test target', () => {
const projectJson = readJson(`${reactVitest}/project.json`);
expect(projectJson.targets.test).toBeUndefined();
});
});
});