diff --git a/e2e/vite/src/vite.test.ts b/e2e/vite/src/vite.test.ts
index 49d3a24912f48..ef4fd932563f0 100644
--- a/e2e/vite/src/vite.test.ts
+++ b/e2e/vite/src/vite.test.ts
@@ -5,6 +5,7 @@ import {
directoryExists,
exists,
fileExists,
+ getPackageManagerCommand,
killPorts,
listFiles,
newProject,
@@ -14,12 +15,14 @@ import {
removeFile,
rmDist,
runCLI,
+ runCommand,
runCLIAsync,
runCommandUntil,
tmpProjPath,
uniq,
updateFile,
updateJson,
+ checkFilesExist,
} from '@nx/e2e/utils';
import { join } from 'path';
@@ -282,7 +285,7 @@ export function App() {
<${buildableLibCmp} />
<${nonBuildableLibCmp} />
{${buildableJsLibFn}()}
-
+
);
}
@@ -354,7 +357,7 @@ export default App;
it('should collect coverage', () => {
runCLI(`generate @nx/react:lib ${lib} --unitTestRunner=vitest`);
updateFile(`libs/${lib}/vite.config.ts`, () => {
- return `///
+ return `///
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
import { nxViteTsPaths } from '@nx/vite/plugins/nx-tsconfig-paths.plugin';
@@ -475,4 +478,71 @@ export default defineConfig({
expect(result.combinedOutput).toContain(`1 passed`);
}, 100_000);
});
+
+ describe('ESM-only apps', () => {
+ beforeAll(() => {
+ newProject({ unsetProjectNameAndRootFormat: false });
+ });
+
+ it('should support ESM-only plugins in vite.config.ts for root apps (#NXP-168)', () => {
+ // ESM-only plugin to test with
+ updateFile(
+ 'foo/package.json',
+ JSON.stringify({
+ name: '@acme/foo',
+ type: 'module',
+ version: '1.0.0',
+ main: 'index.js',
+ })
+ );
+ updateFile(
+ 'foo/index.js',
+ `
+ export default function fooPlugin() {
+ return {
+ name: 'foo-plugin',
+ configResolved() {
+ console.log('Foo plugin');
+ }
+ }
+ }`
+ );
+ updateJson('package.json', (json) => {
+ json.devDependencies['@acme/foo'] = 'file:./foo';
+ return json;
+ });
+ runCommand(getPackageManagerCommand().install);
+
+ const rootApp = uniq('root');
+ runCLI(
+ `generate @nx/react:app ${rootApp} --rootProject --bundler=vite --unitTestRunner=none --e2eTestRunner=none --style=css --no-interactive`
+ );
+ updateJson(`package.json`, (json) => {
+ // This allows us to use ESM-only packages in vite.config.ts.
+ json.type = 'module';
+ return json;
+ });
+ updateFile(
+ `vite.config.ts`,
+ `
+ import fooPlugin from '@acme/foo';
+ import { defineConfig } from 'vite';
+ import react from '@vitejs/plugin-react';
+ import { nxViteTsPaths } from '@nx/vite/plugins/nx-tsconfig-paths.plugin';
+
+ export default defineConfig({
+ cacheDir: './node_modules/.vite/root-app',
+ server: {
+ port: 4200,
+ host: 'localhost',
+ },
+ plugins: [react(), nxViteTsPaths(), fooPlugin()],
+ });`
+ );
+
+ runCLI(`build ${rootApp}`);
+
+ checkFilesExist(`dist/${rootApp}/index.html`);
+ });
+ });
});
diff --git a/packages/vite/src/utils/options-utils.ts b/packages/vite/src/utils/options-utils.ts
index 90808de828f80..63502e87e4c5a 100644
--- a/packages/vite/src/utils/options-utils.ts
+++ b/packages/vite/src/utils/options-utils.ts
@@ -89,10 +89,10 @@ export function getViteSharedConfig(
const projectRoot =
context.projectsConfigurations.projects[context.projectName].root;
- const root = relative(
- context.cwd,
- joinPathFragments(context.root, projectRoot)
- );
+ const root =
+ projectRoot === '.'
+ ? process.cwd()
+ : relative(context.cwd, joinPathFragments(context.root, projectRoot));
return {
mode: options.mode,