diff --git a/.nx/workflows/dynamic-changesets.yaml b/.nx/workflows/dynamic-changesets.yaml
index 8580c122f8c9c..7e93d24e912e2 100644
--- a/.nx/workflows/dynamic-changesets.yaml
+++ b/.nx/workflows/dynamic-changesets.yaml
@@ -25,17 +25,11 @@ assignment-rules:
- e2e-next
- e2e-web
- e2e-eslint
+ - e2e-remix
+ - e2e-cypress
+ - e2e-docker
targets:
- - e2e-ci**react-package**
- - e2e-ci**react.test**
- - e2e-ci**react-router-ts-solution**
- - e2e-ci**next-e2e-and-snapshots**
- - e2e-ci**next-generation**
- - e2e-ci**next-ts-solutions**
- - e2e-ci**next-webpack**
- - e2e-ci**web**
- - e2e-ci**remix-ts-solution**
- - e2e-ci**linter**
+ - e2e-ci**
run-on:
- agent: linux-large
parallelism: 1
diff --git a/e2e/web/src/web-decorator-babel.test.ts b/e2e/web/src/web-decorator-babel.test.ts
new file mode 100644
index 0000000000000..61614565ec8f7
--- /dev/null
+++ b/e2e/web/src/web-decorator-babel.test.ts
@@ -0,0 +1,84 @@
+import { readFile, runCLI, uniq, updateFile } from '@nx/e2e-utils';
+import { setupWebTest } from './web-setup';
+
+describe('Web Components Applications', () => {
+ setupWebTest();
+
+ it('should emit decorator metadata when --compiler=babel and it is enabled in tsconfig', async () => {
+ const appName = uniq('app');
+ runCLI(
+ `generate @nx/web:app apps/${appName} --bundler=webpack --compiler=babel --no-interactive --unitTestRunner=vitest --linter=eslint`
+ );
+
+ updateFile(`apps/${appName}/src/app/app.element.ts`, (content) => {
+ const newContent = `${content}
+ function enumerable(value: boolean) {
+ return function (
+ target: any,
+ propertyKey: string,
+ descriptor: PropertyDescriptor
+ ) {
+ descriptor.enumerable = value;
+ };
+ }
+ function sealed(target: any) {
+ return target;
+ }
+
+ @sealed
+ class Foo {
+ @enumerable(false) bar() {}
+ }
+ `;
+ return newContent;
+ });
+
+ updateFile(`apps/${appName}/src/app/app.element.ts`, (content) => {
+ const newContent = `${content}
+ // bust babel and nx cache
+ `;
+ return newContent;
+ });
+ setPluginOption(
+ `apps/${appName}/webpack.config.js`,
+ 'outputHashing',
+ 'none'
+ );
+ runCLI(`build ${appName}`);
+
+ expect(readFile(`dist/apps/${appName}/main.js`)).toMatch(
+ /Reflect\.metadata/
+ );
+
+ // Turn off decorator metadata
+ updateFile(`apps/${appName}/tsconfig.app.json`, (content) => {
+ const json = JSON.parse(content);
+ json.compilerOptions.emitDecoratorMetadata = false;
+ return JSON.stringify(json);
+ });
+
+ setPluginOption(
+ `apps/${appName}/webpack.config.js`,
+ 'outputHashing',
+ 'none'
+ );
+ runCLI(`build ${appName}`);
+
+ expect(readFile(`dist/apps/${appName}/main.js`)).not.toMatch(
+ /Reflect\.metadata/
+ );
+ }, 120000);
+});
+
+function setPluginOption(
+ webpackConfigPath: string,
+ option: string,
+ value: string | boolean
+): void {
+ updateFile(webpackConfigPath, (content) => {
+ return content.replace(
+ new RegExp(`${option}: .+`),
+ `${option}: ${typeof value === 'string' ? `'${value}'` : value},`
+ );
+ });
+}
diff --git a/e2e/web/src/web-decorator-swc.test.ts b/e2e/web/src/web-decorator-swc.test.ts
new file mode 100644
index 0000000000000..7411628cc3212
--- /dev/null
+++ b/e2e/web/src/web-decorator-swc.test.ts
@@ -0,0 +1,66 @@
+import { readFile, runCLI, uniq, updateFile } from '@nx/e2e-utils';
+import { setupWebTest } from './web-setup';
+
+describe('Web Components Applications', () => {
+ setupWebTest();
+
+ it('should emit decorator metadata when using --compiler=swc', async () => {
+ const appName = uniq('app');
+ runCLI(
+ `generate @nx/web:app apps/${appName} --bundler=webpack --compiler=swc --no-interactive --unitTestRunner=vitest --linter=eslint`
+ );
+
+ updateFile(`apps/${appName}/src/app/app.element.ts`, (content) => {
+ const newContent = `${content}
+ function enumerable(value: boolean) {
+ return function (
+ target: any,
+ propertyKey: string,
+ descriptor: PropertyDescriptor
+ ) {
+ descriptor.enumerable = value;
+ };
+ }
+ function sealed(target: any) {
+ return target;
+ }
+
+ @sealed
+ class Foo {
+ @enumerable(false) bar() {}
+ }
+ `;
+ return newContent;
+ });
+
+ updateFile(`apps/${appName}/src/app/app.element.ts`, (content) => {
+ const newContent = `${content}
+ // bust babel and nx cache
+ `;
+ return newContent;
+ });
+ setPluginOption(
+ `apps/${appName}/webpack.config.js`,
+ 'outputHashing',
+ 'none'
+ );
+ runCLI(`build ${appName}`);
+
+ expect(readFile(`dist/apps/${appName}/main.js`)).toMatch(
+ /Foo=.*?_decorate/
+ );
+ }, 120000);
+});
+
+function setPluginOption(
+ webpackConfigPath: string,
+ option: string,
+ value: string | boolean
+): void {
+ updateFile(webpackConfigPath, (content) => {
+ return content.replace(
+ new RegExp(`${option}: .+`),
+ `${option}: ${typeof value === 'string' ? `'${value}'` : value},`
+ );
+ });
+}
diff --git a/e2e/web/src/web-env-variables.test.ts b/e2e/web/src/web-env-variables.test.ts
new file mode 100644
index 0000000000000..272160c0227fd
--- /dev/null
+++ b/e2e/web/src/web-env-variables.test.ts
@@ -0,0 +1,125 @@
+import {
+ cleanupProject,
+ newProject,
+ readFile,
+ runCLI,
+ uniq,
+ updateFile,
+} from '@nx/e2e-utils';
+
+describe('CLI - Environment Variables', () => {
+ it('should automatically load workspace and per-project environment variables', async () => {
+ newProject();
+
+ const appName = uniq('app');
+ //test if the Nx CLI loads root .env vars
+ updateFile(
+ `.env`,
+ 'NX_PUBLIC_WS_BASE=ws-base\nNX_PUBLIC_SHARED_ENV=shared-in-workspace-base'
+ );
+ updateFile(
+ `.env.local`,
+ 'NX_PUBLIC_WS_ENV_LOCAL=ws-env-local\nNX_PUBLIC_SHARED_ENV=shared-in-workspace-env-local'
+ );
+ updateFile(
+ `.local.env`,
+ 'NX_PUBLIC_WS_LOCAL_ENV=ws-local-env\nNX_PUBLIC_SHARED_ENV=shared-in-workspace-local-env'
+ );
+ updateFile(
+ `apps/${appName}/.env`,
+ 'NX_PUBLIC_APP_BASE=app-base\nNX_PUBLIC_SHARED_ENV=shared-in-app-base'
+ );
+ updateFile(
+ `apps/${appName}/.env.local`,
+ 'NX_PUBLIC_APP_ENV_LOCAL=app-env-local\nNX_PUBLIC_SHARED_ENV=shared-in-app-env-local'
+ );
+ updateFile(
+ `apps/${appName}/.local.env`,
+ 'NX_PUBLIC_APP_LOCAL_ENV=app-local-env\nNX_PUBLIC_SHARED_ENV=shared-in-app-local-env'
+ );
+ const main = `apps/${appName}/src/main.ts`;
+ const newCode = `
+ const envVars = [process.env.NODE_ENV, process.env.NX_PUBLIC_WS_BASE, process.env.NX_PUBLIC_WS_ENV_LOCAL, process.env.NX_PUBLIC_WS_LOCAL_ENV, process.env.NX_PUBLIC_APP_BASE, process.env.NX_PUBLIC_APP_ENV_LOCAL, process.env.NX_PUBLIC_APP_LOCAL_ENV, process.env.NX_PUBLIC_SHARED_ENV];
+ const nodeEnv = process.env.NODE_ENV;
+ const nxWsBase = process.env.NX_PUBLIC_WS_BASE;
+ const nxWsEnvLocal = process.env.NX_PUBLIC_WS_ENV_LOCAL;
+ const nxWsLocalEnv = process.env.NX_PUBLIC_WS_LOCAL_ENV;
+ const nxAppBase = process.env.NX_PUBLIC_APP_BASE;
+ const nxAppEnvLocal = process.env.NX_PUBLIC_APP_ENV_LOCAL;
+ const nxAppLocalEnv = process.env.NX_PUBLIC_APP_LOCAL_ENV;
+ const nxSharedEnv = process.env.NX_PUBLIC_SHARED_ENV;
+ `;
+
+ runCLI(
+ `generate @nx/web:app apps/${appName} --bundler=webpack --no-interactive --compiler=babel --unitTestRunner=vitest --linter=eslint`
+ );
+
+ const content = readFile(main);
+
+ updateFile(main, `${newCode}\n${content}`);
+
+ const appName2 = uniq('app');
+
+ updateFile(
+ `apps/${appName2}/.env`,
+ 'NX_PUBLIC_APP_BASE=app2-base\nNX_PUBLIC_SHARED_ENV=shared2-in-app-base'
+ );
+ updateFile(
+ `apps/${appName2}/.env.local`,
+ 'NX_PUBLIC_APP_ENV_LOCAL=app2-env-local\nNX_PUBLIC_SHARED_ENV=shared2-in-app-env-local'
+ );
+ updateFile(
+ `apps/${appName2}/.local.env`,
+ 'NX_PUBLIC_APP_LOCAL_ENV=app2-local-env\nNX_PUBLIC_SHARED_ENV=shared2-in-app-local-env'
+ );
+ const main2 = `apps/${appName2}/src/main.ts`;
+ const newCode2 = `const envVars = [process.env.NODE_ENV, process.env.NX_PUBLIC_WS_BASE, process.env.NX_PUBLIC_WS_ENV_LOCAL, process.env.NX_PUBLIC_WS_LOCAL_ENV, process.env.NX_PUBLIC_APP_BASE, process.env.NX_PUBLIC_APP_ENV_LOCAL, process.env.NX_PUBLIC_APP_LOCAL_ENV, process.env.NX_PUBLIC_SHARED_ENV];`;
+
+ runCLI(
+ `generate @nx/web:app apps/${appName2} --bundler=webpack --no-interactive --compiler=babel --unitTestRunner=vitest --linter=eslint`
+ );
+
+ const content2 = readFile(main2);
+
+ updateFile(main2, `${newCode2}\n${content2}`);
+
+ setPluginOption(
+ `apps/${appName}/webpack.config.js`,
+ 'outputHashing',
+ 'none'
+ );
+ setPluginOption(`apps/${appName}/webpack.config.js`, 'optimization', false);
+ setPluginOption(
+ `apps/${appName2}/webpack.config.js`,
+ 'outputHashing',
+ 'none'
+ );
+ setPluginOption(
+ `apps/${appName2}/webpack.config.js`,
+ 'optimization',
+ false
+ );
+ runCLI(`run-many --target build --node-env=test`);
+ expect(readFile(`dist/apps/${appName}/main.js`)).toContain(
+ 'const envVars = ["test", "ws-base", "ws-env-local", "ws-local-env", "app-base", "app-env-local", "app-local-env", "shared-in-app-env-local"];'
+ );
+ expect(readFile(`dist/apps/${appName2}/main.js`)).toContain(
+ 'const envVars = ["test", "ws-base", "ws-env-local", "ws-local-env", "app2-base", "app2-env-local", "app2-local-env", "shared2-in-app-env-local"];'
+ );
+
+ cleanupProject();
+ });
+});
+
+function setPluginOption(
+ webpackConfigPath: string,
+ option: string,
+ value: string | boolean
+): void {
+ updateFile(webpackConfigPath, (content) => {
+ return content.replace(
+ new RegExp(`${option}: .+`),
+ `${option}: ${typeof value === 'string' ? `'${value}'` : value},`
+ );
+ });
+}
diff --git a/e2e/web/src/web-generate.test.ts b/e2e/web/src/web-generate.test.ts
new file mode 100644
index 0000000000000..ac7a491d7208f
--- /dev/null
+++ b/e2e/web/src/web-generate.test.ts
@@ -0,0 +1,117 @@
+import {
+ checkFilesExist,
+ isNotWindows,
+ killPorts,
+ listFiles,
+ readFile,
+ runCLI,
+ runCLIAsync,
+ runE2ETests,
+ tmpProjPath,
+ uniq,
+ updateFile,
+} from '@nx/e2e-utils';
+import { join } from 'path';
+import { copyFileSync } from 'fs';
+import { setupWebTest } from './web-setup';
+
+describe('Web Components Applications', () => {
+ setupWebTest();
+
+ it('should be able to generate a web app', async () => {
+ const appName = uniq('app');
+ runCLI(
+ `generate @nx/web:app apps/${appName} --bundler=webpack --no-interactive --unitTestRunner=vitest --linter=eslint`
+ );
+
+ const lintResults = runCLI(`lint ${appName}`);
+ expect(lintResults).toContain('Successfully ran target lint');
+
+ const testResults = await runCLIAsync(`test ${appName}`);
+
+ expect(testResults.combinedOutput).toContain(
+ `Successfully ran target test for project ${appName}`
+ );
+ const lintE2eResults = runCLI(`lint ${appName}-e2e`);
+
+ expect(lintE2eResults).toContain('Successfully ran target lint');
+
+ if (isNotWindows() && runE2ETests()) {
+ const e2eResults = runCLI(`e2e ${appName}-e2e`);
+ expect(e2eResults).toContain('Successfully ran target e2e for project');
+ await killPorts();
+ }
+
+ copyFileSync(
+ join(__dirname, 'test-fixtures/inlined.png'),
+ join(tmpProjPath(), `apps/${appName}/src/app/inlined.png`)
+ );
+ copyFileSync(
+ join(__dirname, 'test-fixtures/emitted.png'),
+ join(tmpProjPath(), `apps/${appName}/src/app/emitted.png`)
+ );
+ updateFile(
+ `apps/${appName}/src/app/app.element.ts`,
+ `
+ // @ts-ignore
+ import inlined from './inlined.png';
+ // @ts-ignore
+ import emitted from './emitted.png';
+ export class AppElement extends HTMLElement {
+ public static observedAttributes = [];
+ connectedCallback() {
+ this.innerHTML = \`
+
+
+ \`;
+ }
+ }
+ customElements.define('app-root', AppElement);
+ `
+ );
+ setPluginOption(
+ `apps/${appName}/webpack.config.js`,
+ 'outputHashing',
+ 'none'
+ );
+ runCLI(`build ${appName}`);
+ const images = listFiles(`dist/apps/${appName}`).filter((f) =>
+ f.endsWith('.png')
+ );
+ checkFilesExist(
+ `dist/apps/${appName}/index.html`,
+ `dist/apps/${appName}/runtime.js`,
+ `dist/apps/${appName}/main.js`,
+ `dist/apps/${appName}/styles.css`
+ );
+ expect(images.some((f) => f.startsWith('emitted.'))).toBe(true);
+ expect(images.some((f) => f.startsWith('inlined.'))).toBe(false);
+
+ expect(readFile(`dist/apps/${appName}/main.js`)).toContain(
+ 'data:image/png;base64'
+ );
+ // Should not be a JS module but kept as a PNG
+ expect(
+ readFile(
+ `dist/apps/${appName}/${images.find((f) => f.startsWith('emitted.'))}`
+ )
+ ).not.toContain('export default');
+
+ expect(readFile(`dist/apps/${appName}/index.html`)).toContain(
+ ''
+ );
+ }, 500000);
+});
+
+function setPluginOption(
+ webpackConfigPath: string,
+ option: string,
+ value: string | boolean
+): void {
+ updateFile(webpackConfigPath, (content) => {
+ return content.replace(
+ new RegExp(`${option}: .+`),
+ `${option}: ${typeof value === 'string' ? `'${value}'` : value},`
+ );
+ });
+}
diff --git a/e2e/web/src/web-html-interpolation.test.ts b/e2e/web/src/web-html-interpolation.test.ts
new file mode 100644
index 0000000000000..0b045f4e9b652
--- /dev/null
+++ b/e2e/web/src/web-html-interpolation.test.ts
@@ -0,0 +1,51 @@
+import { createFile, readFile, runCLI, uniq, updateFile } from '@nx/e2e-utils';
+import { setupWebTest } from './web-setup';
+
+describe('index.html interpolation', () => {
+ setupWebTest();
+
+ test('should interpolate environment variables', async () => {
+ const appName = uniq('app');
+
+ runCLI(
+ `generate @nx/web:app apps/${appName} --bundler=webpack --no-interactive --unitTestRunner=vitest --linter=eslint`
+ );
+
+ const srcPath = `apps/${appName}/src`;
+ const indexPath = `${srcPath}/index.html`;
+ const indexContent = `
+
+
+ Nx Variable: foo<\/div>/);
+ });
+});
diff --git a/e2e/web/src/web-new-format.test.ts b/e2e/web/src/web-new-format.test.ts
new file mode 100644
index 0000000000000..2e0e279e428c2
--- /dev/null
+++ b/e2e/web/src/web-new-format.test.ts
@@ -0,0 +1,27 @@
+import { checkFilesExist, runCLI, uniq } from '@nx/e2e-utils';
+import { setupWebTest } from './web-setup';
+
+describe('Web Components Applications', () => {
+ setupWebTest();
+
+ it('should support generating applications with the new name and root format', () => {
+ const appName = uniq('app1');
+
+ runCLI(
+ `generate @nx/web:app ${appName} --bundler=webpack --no-interactive --unitTestRunner=vitest --linter=eslint`
+ );
+
+ // check files are generated without the layout directory ("apps/") and
+ // using the project name as the directory when no directory is provided
+ checkFilesExist(`${appName}/src/main.ts`);
+ // check build works
+ expect(runCLI(`build ${appName}`)).toContain(
+ `Successfully ran target build for project ${appName}`
+ );
+ // check tests pass
+ const appTestResult = runCLI(`test ${appName}`);
+ expect(appTestResult).toContain(
+ `Successfully ran target test for project ${appName}`
+ );
+ }, 500_000);
+});
diff --git a/e2e/web/src/web-setup.ts b/e2e/web/src/web-setup.ts
new file mode 100644
index 0000000000000..833d6a4996eab
--- /dev/null
+++ b/e2e/web/src/web-setup.ts
@@ -0,0 +1,6 @@
+import { cleanupProject, newProject } from '@nx/e2e-utils';
+
+export function setupWebTest() {
+ beforeAll(() => newProject({ packages: ['@nx/web'] }));
+ afterAll(() => cleanupProject());
+}
diff --git a/e2e/web/src/web-vite.test.ts b/e2e/web/src/web-vite-generate.test.ts
similarity index 50%
rename from e2e/web/src/web-vite.test.ts
rename to e2e/web/src/web-vite-generate.test.ts
index a17000b83e13d..6c11100d9e1da 100644
--- a/e2e/web/src/web-vite.test.ts
+++ b/e2e/web/src/web-vite-generate.test.ts
@@ -1,20 +1,16 @@
import {
- checkFilesDoNotExist,
checkFilesExist,
- cleanupProject,
- createFile,
isNotWindows,
killPorts,
- newProject,
runCLI,
runCLIAsync,
runE2ETests,
uniq,
} from '@nx/e2e-utils';
+import { setupWebViteTest } from './web-vite-setup';
describe('Web Components Applications with bundler set as vite', () => {
- beforeEach(() => newProject({ packages: ['@nx/web', '@nx/react'] }));
- afterEach(() => cleanupProject());
+ setupWebViteTest();
it('should be able to generate a web app', async () => {
const appName = uniq('app');
@@ -44,31 +40,4 @@ describe('Web Components Applications with bundler set as vite', () => {
await killPorts();
}
}, 500000);
-
- it('should remove previous output before building', async () => {
- const appName = uniq('app');
- const libName = uniq('lib');
-
- runCLI(
- `generate @nx/web:app apps/${appName} --bundler=vite --no-interactive --linter=eslint --unitTestRunner=vitest`
- );
- runCLI(
- `generate @nx/react:lib libs/${libName} --bundler=vite --no-interactive --unitTestRunner=vitest --linter=eslint`
- );
-
- createFile(`dist/apps/${appName}/_should_remove.txt`);
- createFile(`dist/libs/${libName}/_should_remove.txt`);
- createFile(`dist/apps/_should_not_remove.txt`);
- checkFilesExist(
- `dist/apps/${appName}/_should_remove.txt`,
- `dist/apps/_should_not_remove.txt`
- );
- runCLI(`build ${appName} --emptyOutDir`);
- runCLI(`build ${libName} --emptyOutDir`);
- checkFilesDoNotExist(
- `dist/apps/${appName}/_should_remove.txt`,
- `dist/libs/${libName}/_should_remove.txt`
- );
- checkFilesExist(`dist/apps/_should_not_remove.txt`);
- }, 120000);
});
diff --git a/e2e/web/src/web-vite-output.test.ts b/e2e/web/src/web-vite-output.test.ts
new file mode 100644
index 0000000000000..558774976e592
--- /dev/null
+++ b/e2e/web/src/web-vite-output.test.ts
@@ -0,0 +1,39 @@
+import {
+ checkFilesDoNotExist,
+ checkFilesExist,
+ createFile,
+ runCLI,
+ uniq,
+} from '@nx/e2e-utils';
+import { setupWebViteTest } from './web-vite-setup';
+
+describe('Web Components Applications with bundler set as vite', () => {
+ setupWebViteTest();
+
+ it('should remove previous output before building', async () => {
+ const appName = uniq('app');
+ const libName = uniq('lib');
+
+ runCLI(
+ `generate @nx/web:app apps/${appName} --bundler=vite --no-interactive --linter=eslint --unitTestRunner=vitest`
+ );
+ runCLI(
+ `generate @nx/react:lib libs/${libName} --bundler=vite --no-interactive --unitTestRunner=vitest --linter=eslint`
+ );
+
+ createFile(`dist/apps/${appName}/_should_remove.txt`);
+ createFile(`dist/libs/${libName}/_should_remove.txt`);
+ createFile(`dist/apps/_should_not_remove.txt`);
+ checkFilesExist(
+ `dist/apps/${appName}/_should_remove.txt`,
+ `dist/apps/_should_not_remove.txt`
+ );
+ runCLI(`build ${appName} --emptyOutDir`);
+ runCLI(`build ${libName} --emptyOutDir`);
+ checkFilesDoNotExist(
+ `dist/apps/${appName}/_should_remove.txt`,
+ `dist/libs/${libName}/_should_remove.txt`
+ );
+ checkFilesExist(`dist/apps/_should_not_remove.txt`);
+ }, 120000);
+});
diff --git a/e2e/web/src/web-vite-setup.ts b/e2e/web/src/web-vite-setup.ts
new file mode 100644
index 0000000000000..bf9993e5691d5
--- /dev/null
+++ b/e2e/web/src/web-vite-setup.ts
@@ -0,0 +1,6 @@
+import { cleanupProject, newProject } from '@nx/e2e-utils';
+
+export function setupWebViteTest() {
+ beforeEach(() => newProject({ packages: ['@nx/web', '@nx/react'] }));
+ afterEach(() => cleanupProject());
+}
diff --git a/e2e/web/src/web.test.ts b/e2e/web/src/web.test.ts
deleted file mode 100644
index 9f1a3a388c03d..0000000000000
--- a/e2e/web/src/web.test.ts
+++ /dev/null
@@ -1,407 +0,0 @@
-import {
- checkFilesDoNotExist,
- checkFilesExist,
- cleanupProject,
- createFile,
- isNotWindows,
- killPorts,
- listFiles,
- newProject,
- readFile,
- runCLI,
- runCLIAsync,
- runE2ETests,
- tmpProjPath,
- uniq,
- updateFile,
- updateJson,
-} from '@nx/e2e-utils';
-import { join } from 'path';
-import { copyFileSync } from 'fs';
-
-describe('Web Components Applications', () => {
- beforeAll(() => newProject({ packages: ['@nx/web'] }));
- afterAll(() => cleanupProject());
-
- it('should be able to generate a web app', async () => {
- const appName = uniq('app');
- runCLI(
- `generate @nx/web:app apps/${appName} --bundler=webpack --no-interactive --unitTestRunner=vitest --linter=eslint`
- );
-
- const lintResults = runCLI(`lint ${appName}`);
- expect(lintResults).toContain('Successfully ran target lint');
-
- const testResults = await runCLIAsync(`test ${appName}`);
-
- expect(testResults.combinedOutput).toContain(
- `Successfully ran target test for project ${appName}`
- );
- const lintE2eResults = runCLI(`lint ${appName}-e2e`);
-
- expect(lintE2eResults).toContain('Successfully ran target lint');
-
- if (isNotWindows() && runE2ETests()) {
- const e2eResults = runCLI(`e2e ${appName}-e2e`);
- expect(e2eResults).toContain('Successfully ran target e2e for project');
- await killPorts();
- }
-
- copyFileSync(
- join(__dirname, 'test-fixtures/inlined.png'),
- join(tmpProjPath(), `apps/${appName}/src/app/inlined.png`)
- );
- copyFileSync(
- join(__dirname, 'test-fixtures/emitted.png'),
- join(tmpProjPath(), `apps/${appName}/src/app/emitted.png`)
- );
- updateFile(
- `apps/${appName}/src/app/app.element.ts`,
- `
- // @ts-ignore
- import inlined from './inlined.png';
- // @ts-ignore
- import emitted from './emitted.png';
- export class AppElement extends HTMLElement {
- public static observedAttributes = [];
- connectedCallback() {
- this.innerHTML = \`
-

-

- \`;
- }
- }
- customElements.define('app-root', AppElement);
- `
- );
- setPluginOption(
- `apps/${appName}/webpack.config.js`,
- 'outputHashing',
- 'none'
- );
- runCLI(`build ${appName}`);
- const images = listFiles(`dist/apps/${appName}`).filter((f) =>
- f.endsWith('.png')
- );
- checkFilesExist(
- `dist/apps/${appName}/index.html`,
- `dist/apps/${appName}/runtime.js`,
- `dist/apps/${appName}/main.js`,
- `dist/apps/${appName}/styles.css`
- );
- expect(images.some((f) => f.startsWith('emitted.'))).toBe(true);
- expect(images.some((f) => f.startsWith('inlined.'))).toBe(false);
-
- expect(readFile(`dist/apps/${appName}/main.js`)).toContain(
- 'data:image/png;base64'
- );
- // Should not be a JS module but kept as a PNG
- expect(
- readFile(
- `dist/apps/${appName}/${images.find((f) => f.startsWith('emitted.'))}`
- )
- ).not.toContain('export default');
-
- expect(readFile(`dist/apps/${appName}/index.html`)).toContain(
- '
'
- );
- }, 500000);
-
- it('should emit decorator metadata when --compiler=babel and it is enabled in tsconfig', async () => {
- const appName = uniq('app');
- runCLI(
- `generate @nx/web:app apps/${appName} --bundler=webpack --compiler=babel --no-interactive --unitTestRunner=vitest --linter=eslint`
- );
-
- updateFile(`apps/${appName}/src/app/app.element.ts`, (content) => {
- const newContent = `${content}
- function enumerable(value: boolean) {
- return function (
- target: any,
- propertyKey: string,
- descriptor: PropertyDescriptor
- ) {
- descriptor.enumerable = value;
- };
- }
- function sealed(target: any) {
- return target;
- }
-
- @sealed
- class Foo {
- @enumerable(false) bar() {}
- }
- `;
- return newContent;
- });
-
- updateFile(`apps/${appName}/src/app/app.element.ts`, (content) => {
- const newContent = `${content}
- // bust babel and nx cache
- `;
- return newContent;
- });
- setPluginOption(
- `apps/${appName}/webpack.config.js`,
- 'outputHashing',
- 'none'
- );
- runCLI(`build ${appName}`);
-
- expect(readFile(`dist/apps/${appName}/main.js`)).toMatch(
- /Reflect\.metadata/
- );
-
- // Turn off decorator metadata
- updateFile(`apps/${appName}/tsconfig.app.json`, (content) => {
- const json = JSON.parse(content);
- json.compilerOptions.emitDecoratorMetadata = false;
- return JSON.stringify(json);
- });
-
- setPluginOption(
- `apps/${appName}/webpack.config.js`,
- 'outputHashing',
- 'none'
- );
- runCLI(`build ${appName}`);
-
- expect(readFile(`dist/apps/${appName}/main.js`)).not.toMatch(
- /Reflect\.metadata/
- );
- }, 120000);
-
- it('should emit decorator metadata when using --compiler=swc', async () => {
- const appName = uniq('app');
- runCLI(
- `generate @nx/web:app apps/${appName} --bundler=webpack --compiler=swc --no-interactive --unitTestRunner=vitest --linter=eslint`
- );
-
- updateFile(`apps/${appName}/src/app/app.element.ts`, (content) => {
- const newContent = `${content}
- function enumerable(value: boolean) {
- return function (
- target: any,
- propertyKey: string,
- descriptor: PropertyDescriptor
- ) {
- descriptor.enumerable = value;
- };
- }
- function sealed(target: any) {
- return target;
- }
-
- @sealed
- class Foo {
- @enumerable(false) bar() {}
- }
- `;
- return newContent;
- });
-
- updateFile(`apps/${appName}/src/app/app.element.ts`, (content) => {
- const newContent = `${content}
- // bust babel and nx cache
- `;
- return newContent;
- });
- setPluginOption(
- `apps/${appName}/webpack.config.js`,
- 'outputHashing',
- 'none'
- );
- runCLI(`build ${appName}`);
-
- expect(readFile(`dist/apps/${appName}/main.js`)).toMatch(
- /Foo=.*?_decorate/
- );
- }, 120000);
-
- it('should support generating applications with the new name and root format', () => {
- const appName = uniq('app1');
-
- runCLI(
- `generate @nx/web:app ${appName} --bundler=webpack --no-interactive --unitTestRunner=vitest --linter=eslint`
- );
-
- // check files are generated without the layout directory ("apps/") and
- // using the project name as the directory when no directory is provided
- checkFilesExist(`${appName}/src/main.ts`);
- // check build works
- expect(runCLI(`build ${appName}`)).toContain(
- `Successfully ran target build for project ${appName}`
- );
- // check tests pass
- const appTestResult = runCLI(`test ${appName}`);
- expect(appTestResult).toContain(
- `Successfully ran target test for project ${appName}`
- );
- }, 500_000);
-});
-
-describe('CLI - Environment Variables', () => {
- it('should automatically load workspace and per-project environment variables', async () => {
- newProject();
-
- const appName = uniq('app');
- //test if the Nx CLI loads root .env vars
- updateFile(
- `.env`,
- 'NX_PUBLIC_WS_BASE=ws-base\nNX_PUBLIC_SHARED_ENV=shared-in-workspace-base'
- );
- updateFile(
- `.env.local`,
- 'NX_PUBLIC_WS_ENV_LOCAL=ws-env-local\nNX_PUBLIC_SHARED_ENV=shared-in-workspace-env-local'
- );
- updateFile(
- `.local.env`,
- 'NX_PUBLIC_WS_LOCAL_ENV=ws-local-env\nNX_PUBLIC_SHARED_ENV=shared-in-workspace-local-env'
- );
- updateFile(
- `apps/${appName}/.env`,
- 'NX_PUBLIC_APP_BASE=app-base\nNX_PUBLIC_SHARED_ENV=shared-in-app-base'
- );
- updateFile(
- `apps/${appName}/.env.local`,
- 'NX_PUBLIC_APP_ENV_LOCAL=app-env-local\nNX_PUBLIC_SHARED_ENV=shared-in-app-env-local'
- );
- updateFile(
- `apps/${appName}/.local.env`,
- 'NX_PUBLIC_APP_LOCAL_ENV=app-local-env\nNX_PUBLIC_SHARED_ENV=shared-in-app-local-env'
- );
- const main = `apps/${appName}/src/main.ts`;
- const newCode = `
- const envVars = [process.env.NODE_ENV, process.env.NX_PUBLIC_WS_BASE, process.env.NX_PUBLIC_WS_ENV_LOCAL, process.env.NX_PUBLIC_WS_LOCAL_ENV, process.env.NX_PUBLIC_APP_BASE, process.env.NX_PUBLIC_APP_ENV_LOCAL, process.env.NX_PUBLIC_APP_LOCAL_ENV, process.env.NX_PUBLIC_SHARED_ENV];
- const nodeEnv = process.env.NODE_ENV;
- const nxWsBase = process.env.NX_PUBLIC_WS_BASE;
- const nxWsEnvLocal = process.env.NX_PUBLIC_WS_ENV_LOCAL;
- const nxWsLocalEnv = process.env.NX_PUBLIC_WS_LOCAL_ENV;
- const nxAppBase = process.env.NX_PUBLIC_APP_BASE;
- const nxAppEnvLocal = process.env.NX_PUBLIC_APP_ENV_LOCAL;
- const nxAppLocalEnv = process.env.NX_PUBLIC_APP_LOCAL_ENV;
- const nxSharedEnv = process.env.NX_PUBLIC_SHARED_ENV;
- `;
-
- runCLI(
- `generate @nx/web:app apps/${appName} --bundler=webpack --no-interactive --compiler=babel --unitTestRunner=vitest --linter=eslint`
- );
-
- const content = readFile(main);
-
- updateFile(main, `${newCode}\n${content}`);
-
- const appName2 = uniq('app');
-
- updateFile(
- `apps/${appName2}/.env`,
- 'NX_PUBLIC_APP_BASE=app2-base\nNX_PUBLIC_SHARED_ENV=shared2-in-app-base'
- );
- updateFile(
- `apps/${appName2}/.env.local`,
- 'NX_PUBLIC_APP_ENV_LOCAL=app2-env-local\nNX_PUBLIC_SHARED_ENV=shared2-in-app-env-local'
- );
- updateFile(
- `apps/${appName2}/.local.env`,
- 'NX_PUBLIC_APP_LOCAL_ENV=app2-local-env\nNX_PUBLIC_SHARED_ENV=shared2-in-app-local-env'
- );
- const main2 = `apps/${appName2}/src/main.ts`;
- const newCode2 = `const envVars = [process.env.NODE_ENV, process.env.NX_PUBLIC_WS_BASE, process.env.NX_PUBLIC_WS_ENV_LOCAL, process.env.NX_PUBLIC_WS_LOCAL_ENV, process.env.NX_PUBLIC_APP_BASE, process.env.NX_PUBLIC_APP_ENV_LOCAL, process.env.NX_PUBLIC_APP_LOCAL_ENV, process.env.NX_PUBLIC_SHARED_ENV];`;
-
- runCLI(
- `generate @nx/web:app apps/${appName2} --bundler=webpack --no-interactive --compiler=babel --unitTestRunner=vitest --linter=eslint`
- );
-
- const content2 = readFile(main2);
-
- updateFile(main2, `${newCode2}\n${content2}`);
-
- setPluginOption(
- `apps/${appName}/webpack.config.js`,
- 'outputHashing',
- 'none'
- );
- setPluginOption(`apps/${appName}/webpack.config.js`, 'optimization', false);
- setPluginOption(
- `apps/${appName2}/webpack.config.js`,
- 'outputHashing',
- 'none'
- );
- setPluginOption(
- `apps/${appName2}/webpack.config.js`,
- 'optimization',
- false
- );
- runCLI(`run-many --target build --node-env=test`);
- expect(readFile(`dist/apps/${appName}/main.js`)).toContain(
- 'const envVars = ["test", "ws-base", "ws-env-local", "ws-local-env", "app-base", "app-env-local", "app-local-env", "shared-in-app-env-local"];'
- );
- expect(readFile(`dist/apps/${appName2}/main.js`)).toContain(
- 'const envVars = ["test", "ws-base", "ws-env-local", "ws-local-env", "app2-base", "app2-env-local", "app2-local-env", "shared2-in-app-env-local"];'
- );
- });
-});
-
-describe('index.html interpolation', () => {
- beforeAll(() => newProject());
- afterAll(() => cleanupProject());
-
- test('should interpolate environment variables', async () => {
- const appName = uniq('app');
-
- runCLI(
- `generate @nx/web:app apps/${appName} --bundler=webpack --no-interactive --unitTestRunner=vitest --linter=eslint`
- );
-
- const srcPath = `apps/${appName}/src`;
- const indexPath = `${srcPath}/index.html`;
- const indexContent = `
-
-
-
-
BestReactApp
-
-
-
-
-
-
-
Nx Variable: %NX_PUBLIC_VARIABLE%
-
Some other variable: %SOME_OTHER_VARIABLE%
-
-
-`;
- const envFilePath = `apps/${appName}/.env`;
- const envFileContents = `
- NX_PUBLIC_VARIABLE=foo
- SOME_OTHER_VARIABLE=bar
- }`;
-
- createFile(envFilePath);
-
- // createFile could not create a file with content
- updateFile(envFilePath, envFileContents);
- updateFile(indexPath, indexContent);
-
- runCLI(`build ${appName}`);
-
- const distPath = `dist/apps/${appName}`;
- const resultIndexContents = readFile(`${distPath}/index.html`);
-
- expect(resultIndexContents).toMatch(/
Nx Variable: foo<\/div>/);
- });
-});
-
-function setPluginOption(
- webpackConfigPath: string,
- option: string,
- value: string | boolean
-): void {
- updateFile(webpackConfigPath, (content) => {
- return content.replace(
- new RegExp(`${option}: .+`),
- `${option}: ${typeof value === 'string' ? `'${value}'` : value},`
- );
- });
-}
diff --git a/e2e/webpack/src/webpack-app-plugin.test.ts b/e2e/webpack/src/webpack-app-plugin.test.ts
new file mode 100644
index 0000000000000..6569b23b7df1e
--- /dev/null
+++ b/e2e/webpack/src/webpack-app-plugin.test.ts
@@ -0,0 +1,66 @@
+import {
+ checkFilesExist,
+ createFile,
+ runCLI,
+ runCommand,
+ uniq,
+ updateFile,
+} from '@nx/e2e-utils';
+import { setupWebpackTest } from './webpack-setup';
+
+describe('Webpack Plugin', () => {
+ setupWebpackTest();
+
+ it('should be able to build with NxWebpackPlugin and a standard webpack config file', () => {
+ const appName = uniq('app');
+ runCLI(
+ `generate @nx/web:app ${appName} --bundler webpack --directory=apps/${appName}`
+ );
+ updateFile(`apps/${appName}/src/main.ts`, `console.log('Hello');\n`);
+ updateFile(`apps/${appName}/src/foo.ts`, `console.log('Foo');\n`);
+ updateFile(`apps/${appName}/src/bar.ts`, `console.log('Bar');\n`);
+
+ updateFile(
+ `apps/${appName}/webpack.config.js`,
+ `
+ const path = require('path');
+ const { NxAppWebpackPlugin } = require('@nx/webpack/app-plugin');
+
+ module.exports = {
+ target: 'node',
+ output: {
+ path: path.join(__dirname, '../../dist/apps/${appName}'),
+ // do not remove dist, so files between builds will remain
+ clean: false,
+ },
+ plugins: [
+ new NxAppWebpackPlugin({
+ compiler: 'tsc',
+ main: './src/main.ts',
+ additionalEntryPoints: [
+ './src/foo.ts',
+ {
+ entryName: 'bar',
+ entryPath: './src/bar.ts',
+ }
+ ],
+ tsConfig: './tsconfig.app.json',
+ outputHashing: 'none',
+ optimization: false,
+ })
+ ]
+ };`
+ );
+
+ runCLI(`build ${appName}`);
+
+ expect(runCommand(`node dist/apps/${appName}/main.js`)).toMatch(/Hello/);
+ expect(runCommand(`node dist/apps/${appName}/foo.js`)).toMatch(/Foo/);
+ expect(runCommand(`node dist/apps/${appName}/bar.js`)).toMatch(/Bar/);
+
+ // Ensure dist is not removed between builds since output.clean === false
+ createFile(`dist/apps/${appName}/extra.js`);
+ runCLI(`build ${appName} --skip-nx-cache`);
+ checkFilesExist(`dist/apps/${appName}/extra.js`);
+ }, 500_000);
+});
diff --git a/e2e/webpack/src/webpack-assets.test.ts b/e2e/webpack/src/webpack-assets.test.ts
new file mode 100644
index 0000000000000..6a346778f538c
--- /dev/null
+++ b/e2e/webpack/src/webpack-assets.test.ts
@@ -0,0 +1,42 @@
+import {
+ checkFilesExist,
+ runCLI,
+ uniq,
+ updateFile,
+ updateJson,
+} from '@nx/e2e-utils';
+import { setupWebpackTest } from './webpack-setup';
+
+describe('Webpack Plugin', () => {
+ setupWebpackTest();
+
+ it('should resolve assets from executors as relative to workspace root', () => {
+ const appName = uniq('app');
+ runCLI(
+ `generate @nx/web:app ${appName} --directory=apps/${appName} --bundler webpack`
+ );
+ updateFile('shared/docs/TEST.md', 'TEST');
+ updateJson(`apps/${appName}/project.json`, (json) => {
+ json.targets.build = {
+ executor: '@nx/webpack:webpack',
+ outputs: ['{options.outputPath}'],
+ options: {
+ assets: [
+ {
+ input: 'shared/docs',
+ glob: 'TEST.md',
+ output: '.',
+ },
+ ],
+ outputPath: `dist/apps/${appName}`,
+ webpackConfig: `apps/${appName}/webpack.config.js`,
+ },
+ };
+ return json;
+ });
+
+ runCLI(`build ${appName}`);
+
+ checkFilesExist(`dist/apps/${appName}/TEST.md`);
+ });
+});
diff --git a/e2e/webpack/src/webpack-babel-corejs.test.ts b/e2e/webpack/src/webpack-babel-corejs.test.ts
new file mode 100644
index 0000000000000..861b0374c5900
--- /dev/null
+++ b/e2e/webpack/src/webpack-babel-corejs.test.ts
@@ -0,0 +1,50 @@
+import {
+ checkFilesExist,
+ listFiles,
+ packageInstall,
+ readFile,
+ runCLI,
+ uniq,
+ updateFile,
+} from '@nx/e2e-utils';
+import { setupWebpackTest } from './webpack-setup';
+
+describe('Webpack Plugin', () => {
+ setupWebpackTest();
+
+ it('should support babel + core-js to polyfill JS features', async () => {
+ const appName = uniq('app');
+ runCLI(
+ `generate @nx/web:app ${appName} --directory=apps/${appName} --bundler webpack --compiler=babel`
+ );
+ packageInstall('core-js', undefined, '3.26.1', 'prod');
+
+ checkFilesExist(`apps/${appName}/src/main.ts`);
+ updateFile(
+ `apps/${appName}/src/main.ts`,
+ `
+ import 'core-js/stable';
+ async function main() {
+ const result = await Promise.resolve('foobar')
+ console.log(result);
+ }
+ main();
+ `
+ );
+
+ // Modern browser
+ updateFile(`apps/${appName}/.browserslistrc`, `last 1 Chrome version\n`);
+ runCLI(`build ${appName}`);
+ expect(readMainFile(`dist/apps/${appName}`)).toMatch(`await Promise`);
+
+ // Legacy browser
+ updateFile(`apps/${appName}/.browserslistrc`, `IE 11\n`);
+ runCLI(`build ${appName}`);
+ expect(readMainFile(`dist/apps/${appName}`)).not.toMatch(`await Promise`);
+ });
+});
+
+function readMainFile(dir: string): string {
+ const main = listFiles(dir).find((f) => f.startsWith('main.'));
+ return readFile(`${dir}/${main}`);
+}
diff --git a/e2e/webpack/src/webpack-babel-env.test.ts b/e2e/webpack/src/webpack-babel-env.test.ts
new file mode 100644
index 0000000000000..7d94b363f9358
--- /dev/null
+++ b/e2e/webpack/src/webpack-babel-env.test.ts
@@ -0,0 +1,40 @@
+import { runCLI, uniq, updateFile } from '@nx/e2e-utils';
+import { setupWebpackTest } from './webpack-setup';
+
+describe('Webpack Plugin', () => {
+ setupWebpackTest();
+
+ it('should use either BABEL_ENV or NODE_ENV value for Babel environment configuration', async () => {
+ const myPkg = uniq('my-pkg');
+ runCLI(
+ `generate @nx/js:lib ${myPkg} --directory=libs/${myPkg} --bundler=none`
+ );
+ updateFile(`libs/${myPkg}/src/index.ts`, `console.log('Hello');\n`);
+
+ runCLI(
+ `generate @nx/webpack:configuration ${myPkg} --target=node --compiler=babel --tsConfig=libs/${myPkg}/tsconfig.lib.json --main=libs/${myPkg}/src/index.ts`
+ );
+
+ updateFile(
+ `libs/${myPkg}/.babelrc`,
+ `{ 'presets': ['@nx/js/babel', './custom-preset'] } `
+ );
+ updateFile(
+ `libs/${myPkg}/custom-preset.js`,
+ `
+ module.exports = function(api, opts) {
+ console.log('Babel env is ' + api.env());
+ return opts;
+ }
+ `
+ );
+
+ let output = runCLI(`build ${myPkg}`, {
+ env: {
+ NODE_ENV: 'nodeEnv',
+ BABEL_ENV: 'babelEnv',
+ },
+ });
+ expect(output).toContain('Babel env is babelEnv');
+ }, 500_000);
+});
diff --git a/e2e/webpack/src/webpack-compose-plugins.test.ts b/e2e/webpack/src/webpack-compose-plugins.test.ts
new file mode 100644
index 0000000000000..f892fd1944b14
--- /dev/null
+++ b/e2e/webpack/src/webpack-compose-plugins.test.ts
@@ -0,0 +1,42 @@
+import { runCLI, uniq, updateFile } from '@nx/e2e-utils';
+import { setupWebpackTest } from './webpack-setup';
+
+describe('Webpack Plugin', () => {
+ setupWebpackTest();
+
+ it('should be able to support webpack config with nx enhanced and babel', () => {
+ const appName = uniq('app');
+
+ runCLI(
+ `generate @nx/web:app ${appName} --directory=apps/${appName} --bundler=webpack --compiler=babel`
+ );
+
+ updateFile(
+ `apps/${appName}/webpack.config.js`,
+ `
+ const { composePlugins, withNx } = require('@nx/webpack');
+ const { withReact } = require('@nx/react');
+ const { join } = require('path');
+
+ const pluginOption = {
+ index: 'apps/${appName}/src/index.html',
+ main: 'apps/${appName}/src/main.ts',
+ tsConfig: 'apps/${appName}/tsconfig.app.json',
+ outputPath: 'dist/apps/${appName}',
+ }
+
+ // Nx composable plugins for webpack.
+ module.exports = composePlugins(
+ withNx(pluginOption),
+ withReact(pluginOption),
+ );`
+ );
+
+ const result = runCLI(`build ${appName}`);
+
+ expect(result).toContain(`nx run ${appName}:build`);
+ expect(result).toContain(
+ `Successfully ran target build for project ${appName}`
+ );
+ });
+});
diff --git a/e2e/webpack/src/webpack-config-array.test.ts b/e2e/webpack/src/webpack-config-array.test.ts
new file mode 100644
index 0000000000000..05caa69e8d470
--- /dev/null
+++ b/e2e/webpack/src/webpack-config-array.test.ts
@@ -0,0 +1,71 @@
+import {
+ checkFilesExist,
+ createFile,
+ runCLI,
+ uniq,
+ updateFile,
+} from '@nx/e2e-utils';
+import { setupWebpackTest } from './webpack-setup';
+
+describe('config types', () => {
+ setupWebpackTest();
+
+ it('should support an array of standard config objects', () => {
+ const appName = uniq('app');
+ const serverName = uniq('server');
+
+ runCLI(
+ `generate @nx/react:application --directory=apps/${appName} --bundler=webpack --e2eTestRunner=none`
+ );
+
+ // Create server index file
+ createFile(
+ `apps/${serverName}/index.js`,
+ `console.log('Hello from ${serverName}');\n`
+ );
+
+ updateFile(
+ `apps/${appName}/webpack.config.js`,
+ `
+ const path = require('path');
+ const { NxAppWebpackPlugin } = require('@nx/webpack/app-plugin');
+
+ module.exports = [
+ {
+ name: 'client',
+ target: 'node',
+ output: {
+ path: path.join(__dirname, '../../dist/${appName}')
+ },
+ plugins: [
+ new NxAppWebpackPlugin({
+ compiler: 'tsc',
+ main: './src/main.tsx',
+ tsConfig: './tsconfig.app.json',
+ outputHashing: 'none',
+ optimization: false,
+ })
+ ]
+ }, {
+ name: 'server',
+ target: 'node',
+ entry: '../${serverName}/index.js',
+ output: {
+ path: path.join(__dirname, '../../dist/${serverName}'),
+ filename: 'index.js',
+ },
+ }
+ ];
+ `
+ );
+
+ const result = runCLI(`build ${appName}`);
+
+ checkFilesExist(`dist/${appName}/main.js`);
+ checkFilesExist(`dist/${serverName}/index.js`);
+
+ expect(result).toContain(
+ `Successfully ran target build for project ${appName}`
+ );
+ });
+});
diff --git a/e2e/webpack/src/webpack-config-function-array.test.ts b/e2e/webpack/src/webpack-config-function-array.test.ts
new file mode 100644
index 0000000000000..82ff3f6fd66ca
--- /dev/null
+++ b/e2e/webpack/src/webpack-config-function-array.test.ts
@@ -0,0 +1,72 @@
+import {
+ checkFilesExist,
+ createFile,
+ runCLI,
+ uniq,
+ updateFile,
+} from '@nx/e2e-utils';
+import { setupWebpackTest } from './webpack-setup';
+
+describe('config types', () => {
+ setupWebpackTest();
+
+ it('should support a function that returns an array of standard config objects', () => {
+ const appName = uniq('app');
+ const serverName = uniq('server');
+
+ runCLI(
+ `generate @nx/react:application --directory=apps/${appName} --bundler=webpack --e2eTestRunner=none`
+ );
+
+ // Create server index file
+ createFile(
+ `apps/${serverName}/index.js`,
+ `console.log('Hello from ${serverName}');\n`
+ );
+
+ updateFile(
+ `apps/${appName}/webpack.config.js`,
+ `
+ const path = require('path');
+ const { NxAppWebpackPlugin } = require('@nx/webpack/app-plugin');
+
+ module.exports = () => {
+ return [
+ {
+ name: 'client',
+ target: 'node',
+ output: {
+ path: path.join(__dirname, '../../dist/${appName}')
+ },
+ plugins: [
+ new NxAppWebpackPlugin({
+ compiler: 'tsc',
+ main: './src/main.tsx',
+ tsConfig: './tsconfig.app.json',
+ outputHashing: 'none',
+ optimization: false,
+ })
+ ]
+ },
+ {
+ name: 'server',
+ target: 'node',
+ entry: '../${serverName}/index.js',
+ output: {
+ path: path.join(__dirname, '../../dist/${serverName}'),
+ filename: 'index.js',
+ }
+ }
+ ];
+ };`
+ );
+ const result = runCLI(`build ${appName}`);
+
+ checkFilesExist(`dist/${serverName}/index.js`);
+ checkFilesExist(`dist/${appName}/main.js`);
+
+ expect(result).toContain(
+ `Successfully ran target build for project ${appName}`
+ );
+ });
+});
diff --git a/e2e/webpack/src/webpack-config-function.test.ts b/e2e/webpack/src/webpack-config-function.test.ts
new file mode 100644
index 0000000000000..d86039b6bcd47
--- /dev/null
+++ b/e2e/webpack/src/webpack-config-function.test.ts
@@ -0,0 +1,44 @@
+import { runCLI, uniq, updateFile } from '@nx/e2e-utils';
+import { setupWebpackTest } from './webpack-setup';
+
+describe('config types', () => {
+ setupWebpackTest();
+
+ it('should support a standard function that returns a config object', () => {
+ const appName = uniq('app');
+
+ runCLI(
+ `generate @nx/react:application --directory=apps/${appName} --bundler=webpack --e2eTestRunner=none`
+ );
+
+ updateFile(
+ `apps/${appName}/webpack.config.js`,
+ `
+ const path = require('path');
+ const { NxAppWebpackPlugin } = require('@nx/webpack/app-plugin');
+
+ module.exports = () => {
+ return {
+ target: 'node',
+ output: {
+ path: path.join(__dirname, '../../dist/${appName}')
+ },
+ plugins: [
+ new NxAppWebpackPlugin({
+ compiler: 'tsc',
+ main: './src/main.tsx',
+ tsConfig: './tsconfig.app.json',
+ outputHashing: 'none',
+ optimization: false,
+ })
+ ]
+ };
+ };`
+ );
+
+ const result = runCLI(`build ${appName}`);
+ expect(result).toContain(
+ `Successfully ran target build for project ${appName}`
+ );
+ });
+});
diff --git a/e2e/webpack/src/webpack-config-standard-object.test.ts b/e2e/webpack/src/webpack-config-standard-object.test.ts
new file mode 100644
index 0000000000000..432c9d3482261
--- /dev/null
+++ b/e2e/webpack/src/webpack-config-standard-object.test.ts
@@ -0,0 +1,43 @@
+import { runCLI, uniq, updateFile } from '@nx/e2e-utils';
+import { setupWebpackTest } from './webpack-setup';
+
+describe('config types', () => {
+ setupWebpackTest();
+
+ it('should support a standard config object', () => {
+ const appName = uniq('app');
+
+ runCLI(
+ `generate @nx/react:application --directory=apps/${appName} --bundler=webpack --e2eTestRunner=none`
+ );
+
+ updateFile(
+ `apps/${appName}/webpack.config.js`,
+ `
+ const path = require('path');
+ const { NxAppWebpackPlugin } = require('@nx/webpack/app-plugin');
+
+ module.exports = {
+ target: 'node',
+ output: {
+ path: path.join(__dirname, '../../dist/${appName}')
+ },
+ plugins: [
+ new NxAppWebpackPlugin({
+ compiler: 'babel',
+ main: './src/main.tsx',
+ tsConfig: './tsconfig.app.json',
+ outputHashing: 'none',
+ optimization: false,
+ })
+ ]
+ };`
+ );
+
+ const result = runCLI(`build ${appName}`);
+
+ expect(result).toContain(
+ `Successfully ran target build for project ${appName}`
+ );
+ });
+});
diff --git a/e2e/webpack/src/webpack-env-variables.test.ts b/e2e/webpack/src/webpack-env-variables.test.ts
new file mode 100644
index 0000000000000..551181f63e02e
--- /dev/null
+++ b/e2e/webpack/src/webpack-env-variables.test.ts
@@ -0,0 +1,40 @@
+import {
+ checkFilesExist,
+ listFiles,
+ readFile,
+ runCLI,
+ uniq,
+ updateFile,
+} from '@nx/e2e-utils';
+import { setupWebpackTest } from './webpack-setup';
+
+describe('Webpack Plugin', () => {
+ setupWebpackTest();
+
+ it('should bundle in NX_PUBLIC_ environment variables', () => {
+ const appName = uniq('app');
+ runCLI(
+ `generate @nx/web:app ${appName} --directory=apps/${appName} --bundler webpack`
+ );
+
+ checkFilesExist(`apps/${appName}/src/main.ts`);
+ updateFile(
+ `apps/${appName}/src/main.ts`,
+ `
+ console.log(process.env['NX_PUBLIC_TEST']);
+ `
+ );
+
+ runCLI(`build ${appName}`, {
+ env: {
+ NX_PUBLIC_TEST: 'foobar',
+ },
+ });
+
+ const mainFile = listFiles(`dist/apps/${appName}`).filter((f) =>
+ f.startsWith('main.')
+ );
+ const content = readFile(`dist/apps/${appName}/${mainFile}`);
+ expect(content).toMatch(/foobar/);
+ });
+});
diff --git a/e2e/webpack/src/webpack-executor-options.test.ts b/e2e/webpack/src/webpack-executor-options.test.ts
new file mode 100644
index 0000000000000..4c10fdbd85b2f
--- /dev/null
+++ b/e2e/webpack/src/webpack-executor-options.test.ts
@@ -0,0 +1,62 @@
+import {
+ checkFilesExist,
+ fileExists,
+ runCLI,
+ uniq,
+ updateFile,
+ updateJson,
+} from '@nx/e2e-utils';
+import { setupWebpackTest } from './webpack-setup';
+
+describe('Webpack Plugin', () => {
+ setupWebpackTest();
+
+ it('should allow options to be passed from the executor', async () => {
+ const appName = uniq('app');
+ runCLI(
+ `generate @nx/web:app ${appName} --directory=apps/${appName} --bundler webpack`
+ );
+
+ checkFilesExist(`apps/${appName}/project.json`);
+ updateJson(`apps/${appName}/project.json`, (json) => {
+ json.targets.build = {
+ executor: '@nx/webpack:webpack',
+ outputs: ['{options.outputPath}'],
+ options: {
+ generatePackageJson: true, // This should be passed to the plugin.
+ outputPath: `dist/apps/${appName}`,
+ webpackConfig: `apps/${appName}/webpack.config.js`,
+ },
+ };
+ return json;
+ });
+
+ checkFilesExist(`apps/${appName}/webpack.config.js`);
+ updateFile(
+ `apps/${appName}/webpack.config.js`,
+ `
+ const { NxAppWebpackPlugin } = require('@nx/webpack/app-plugin');
+ const { join } = require('path');
+ module.exports = {
+ output: {
+ path: join(__dirname, '../../dist/apps/demo'),
+ },
+ plugins: [
+ new NxAppWebpackPlugin({
+ // NOTE: generatePackageJson is missing here, but executor passes it.
+ target: 'web',
+ compiler: 'swc',
+ main: './src/main.ts',
+ tsConfig: './tsconfig.app.json',
+ optimization: false,
+ outputHashing: 'none',
+ }),
+ ],
+ };`
+ );
+
+ runCLI(`build ${appName}`);
+
+ fileExists(`dist/apps/${appName}/package.json`);
+ });
+});
diff --git a/e2e/webpack/src/webpack-libs-from-source.test.ts b/e2e/webpack/src/webpack-libs-from-source.test.ts
new file mode 100644
index 0000000000000..ce757f653034f
--- /dev/null
+++ b/e2e/webpack/src/webpack-libs-from-source.test.ts
@@ -0,0 +1,60 @@
+import { runCLI, uniq, updateFile } from '@nx/e2e-utils';
+import { setupWebpackTest } from './webpack-setup';
+
+describe('Webpack Plugin', () => {
+ setupWebpackTest();
+
+ it('it should support building libraries and apps when buildLibsFromSource is false', () => {
+ const appName = uniq('app');
+ const myPkg = uniq('my-pkg');
+
+ runCLI(
+ `generate @nx/web:application ${appName} --directory=apps/${appName}`
+ );
+
+ runCLI(
+ `generate @nx/js:lib ${myPkg} --directory=libs/${myPkg} --importPath=@${appName}/${myPkg}`
+ );
+
+ updateFile(`libs/${myPkg}/src/index.ts`, `export const foo = 'bar';\n`);
+
+ updateFile(
+ `apps/${appName}/src/main.ts`,
+ `import { foo } from '@${appName}/${myPkg}';\nconsole.log(foo);\n`
+ );
+
+ updateFile(
+ `apps/${appName}/webpack.config.js`,
+ `
+ const path = require('path');
+ const { NxAppWebpackPlugin } = require('@nx/webpack/app-plugin');
+
+ module.exports = {
+ target: 'node',
+ output: {
+ path: path.join(__dirname, '../../dist/${appName}')
+ },
+ plugins: [
+ new NxAppWebpackPlugin({
+ compiler: 'tsc',
+ main: 'apps/${appName}/src/main.ts',
+ tsConfig: 'apps/${appName}/tsconfig.app.json',
+ outputHashing: 'none',
+ optimization: false,
+ buildLibsFromSource: false,
+ })
+ ]
+ };`
+ );
+
+ const result = runCLI(`build ${appName}`);
+
+ expect(result).toContain(
+ `Running target build for project ${appName} and 1 task it depends on`
+ );
+ expect(result).toContain(`nx run ${myPkg}:build`);
+ expect(result).toContain(
+ `Successfully ran target build for project ${appName} and 1 task it depends on`
+ );
+ });
+});
diff --git a/e2e/webpack/src/webpack-node-compilers.test.ts b/e2e/webpack/src/webpack-node-compilers.test.ts
new file mode 100644
index 0000000000000..d256168310ed6
--- /dev/null
+++ b/e2e/webpack/src/webpack-node-compilers.test.ts
@@ -0,0 +1,95 @@
+import {
+ rmDist,
+ runCLI,
+ runCommand,
+ uniq,
+ updateFile,
+ updateJson,
+} from '@nx/e2e-utils';
+import { join } from 'path';
+import { setupWebpackTest } from './webpack-setup';
+
+describe('Webpack Plugin', () => {
+ setupWebpackTest();
+
+ it('should be able to setup project to build node programs with webpack and different compilers', async () => {
+ const myPkg = uniq('my-pkg');
+ runCLI(
+ `generate @nx/js:lib ${myPkg} --directory=libs/${myPkg} --bundler=none`
+ );
+ updateFile(`libs/${myPkg}/src/index.ts`, `console.log('Hello');\n`);
+
+ runCLI(
+ `generate @nx/webpack:configuration ${myPkg} --target=node --tsConfig=libs/${myPkg}/tsconfig.lib.json --main=libs/${myPkg}/src/index.ts`
+ );
+
+ // Test `scriptType` later during during.
+ updateFile(
+ `libs/${myPkg}/webpack.config.js`,
+ `
+ const path = require('path');
+ const { NxAppWebpackPlugin } = require('@nx/webpack/app-plugin');
+
+ class DebugPlugin {
+ apply(compiler) {
+ console.log('scriptType is ' + compiler.options.output.scriptType);
+ }
+ }
+
+ module.exports = {
+ target: 'node',
+ output: {
+ path: path.join(__dirname, '../../dist/libs/${myPkg}')
+ },
+ plugins: [
+ new NxAppWebpackPlugin({
+ compiler: 'tsc',
+ main: './src/index.ts',
+ tsConfig: './tsconfig.lib.json',
+ outputHashing: 'none',
+ optimization: false,
+ }),
+ new DebugPlugin()
+ ]
+ };`
+ );
+
+ rmDist();
+
+ const buildOutput = runCLI(`build ${myPkg}`);
+ // Ensure scriptType is not set if we're in Node (it only applies to Web).
+ expect(buildOutput).toContain('scriptType is undefined');
+ let output = runCommand(`node dist/libs/${myPkg}/main.js`);
+ expect(output).toMatch(/Hello/);
+ expect(output).not.toMatch(/Conflicting/);
+ expect(output).not.toMatch(/process.env.NODE_ENV/);
+
+ updateJson(join('libs', myPkg, 'project.json'), (config) => {
+ delete config.targets.build;
+ return config;
+ });
+
+ // swc
+ runCLI(
+ `generate @nx/webpack:configuration ${myPkg} --target=node --tsConfig=libs/${myPkg}/tsconfig.lib.json --main=libs/${myPkg}/src/index.ts --compiler=swc`
+ );
+ rmDist();
+ runCLI(`build ${myPkg}`);
+ output = runCommand(`node dist/libs/${myPkg}/main.js`);
+ expect(output).toMatch(/Hello/);
+
+ updateJson(join('libs', myPkg, 'project.json'), (config) => {
+ delete config.targets.build;
+ return config;
+ });
+
+ // tsc
+ runCLI(
+ `generate @nx/webpack:configuration ${myPkg} --target=node --tsConfig=libs/${myPkg}/tsconfig.lib.json --main=libs/${myPkg}/src/index.ts --compiler=tsc`
+ );
+ rmDist();
+ runCLI(`build ${myPkg}`);
+ output = runCommand(`node dist/libs/${myPkg}/main.js`);
+ expect(output).toMatch(/Hello/);
+ }, 500000);
+});
diff --git a/e2e/webpack/src/webpack-setup.ts b/e2e/webpack/src/webpack-setup.ts
new file mode 100644
index 0000000000000..3a81392207846
--- /dev/null
+++ b/e2e/webpack/src/webpack-setup.ts
@@ -0,0 +1,8 @@
+import { cleanupProject, newProject } from '@nx/e2e-utils';
+
+export function setupWebpackTest() {
+ beforeAll(() =>
+ newProject({ packages: ['@nx/webpack', '@nx/js', '@nx/react', '@nx/web'] })
+ );
+ afterAll(() => cleanupProject());
+}
diff --git a/e2e/webpack/src/webpack.test.ts b/e2e/webpack/src/webpack.test.ts
deleted file mode 100644
index 09ec1281430fe..0000000000000
--- a/e2e/webpack/src/webpack.test.ts
+++ /dev/null
@@ -1,620 +0,0 @@
-import {
- checkFilesExist,
- cleanupProject,
- createFile,
- fileExists,
- listFiles,
- newProject,
- packageInstall,
- readFile,
- rmDist,
- runCLI,
- runCommand,
- uniq,
- updateFile,
- updateJson,
-} from '@nx/e2e-utils';
-import { join } from 'path';
-
-describe('Webpack Plugin', () => {
- beforeAll(() =>
- newProject({ packages: ['@nx/webpack', '@nx/js', '@nx/react', '@nx/web'] })
- );
- afterAll(() => cleanupProject());
-
- it('should be able to setup project to build node programs with webpack and different compilers', async () => {
- const myPkg = uniq('my-pkg');
- runCLI(
- `generate @nx/js:lib ${myPkg} --directory=libs/${myPkg} --bundler=none`
- );
- updateFile(`libs/${myPkg}/src/index.ts`, `console.log('Hello');\n`);
-
- runCLI(
- `generate @nx/webpack:configuration ${myPkg} --target=node --tsConfig=libs/${myPkg}/tsconfig.lib.json --main=libs/${myPkg}/src/index.ts`
- );
-
- // Test `scriptType` later during during.
- updateFile(
- `libs/${myPkg}/webpack.config.js`,
- `
- const path = require('path');
- const { NxAppWebpackPlugin } = require('@nx/webpack/app-plugin');
-
- class DebugPlugin {
- apply(compiler) {
- console.log('scriptType is ' + compiler.options.output.scriptType);
- }
- }
-
- module.exports = {
- target: 'node',
- output: {
- path: path.join(__dirname, '../../dist/libs/${myPkg}')
- },
- plugins: [
- new NxAppWebpackPlugin({
- compiler: 'tsc',
- main: './src/index.ts',
- tsConfig: './tsconfig.lib.json',
- outputHashing: 'none',
- optimization: false,
- }),
- new DebugPlugin()
- ]
- };`
- );
-
- rmDist();
-
- const buildOutput = runCLI(`build ${myPkg}`);
- // Ensure scriptType is not set if we're in Node (it only applies to Web).
- expect(buildOutput).toContain('scriptType is undefined');
- let output = runCommand(`node dist/libs/${myPkg}/main.js`);
- expect(output).toMatch(/Hello/);
- expect(output).not.toMatch(/Conflicting/);
- expect(output).not.toMatch(/process.env.NODE_ENV/);
-
- updateJson(join('libs', myPkg, 'project.json'), (config) => {
- delete config.targets.build;
- return config;
- });
-
- // swc
- runCLI(
- `generate @nx/webpack:configuration ${myPkg} --target=node --tsConfig=libs/${myPkg}/tsconfig.lib.json --main=libs/${myPkg}/src/index.ts --compiler=swc`
- );
- rmDist();
- runCLI(`build ${myPkg}`);
- output = runCommand(`node dist/libs/${myPkg}/main.js`);
- expect(output).toMatch(/Hello/);
-
- updateJson(join('libs', myPkg, 'project.json'), (config) => {
- delete config.targets.build;
- return config;
- });
-
- // tsc
- runCLI(
- `generate @nx/webpack:configuration ${myPkg} --target=node --tsConfig=libs/${myPkg}/tsconfig.lib.json --main=libs/${myPkg}/src/index.ts --compiler=tsc`
- );
- rmDist();
- runCLI(`build ${myPkg}`);
- output = runCommand(`node dist/libs/${myPkg}/main.js`);
- expect(output).toMatch(/Hello/);
- }, 500000);
-
- it('should use either BABEL_ENV or NODE_ENV value for Babel environment configuration', async () => {
- const myPkg = uniq('my-pkg');
- runCLI(
- `generate @nx/js:lib ${myPkg} --directory=libs/${myPkg} --bundler=none`
- );
- updateFile(`libs/${myPkg}/src/index.ts`, `console.log('Hello');\n`);
-
- runCLI(
- `generate @nx/webpack:configuration ${myPkg} --target=node --compiler=babel --tsConfig=libs/${myPkg}/tsconfig.lib.json --main=libs/${myPkg}/src/index.ts`
- );
-
- updateFile(
- `libs/${myPkg}/.babelrc`,
- `{ 'presets': ['@nx/js/babel', './custom-preset'] } `
- );
- updateFile(
- `libs/${myPkg}/custom-preset.js`,
- `
- module.exports = function(api, opts) {
- console.log('Babel env is ' + api.env());
- return opts;
- }
- `
- );
-
- let output = runCLI(`build ${myPkg}`, {
- env: {
- NODE_ENV: 'nodeEnv',
- BABEL_ENV: 'babelEnv',
- },
- });
- expect(output).toContain('Babel env is babelEnv');
- }, 500_000);
-
- it('should be able to build with NxWebpackPlugin and a standard webpack config file', () => {
- const appName = uniq('app');
- runCLI(
- `generate @nx/web:app ${appName} --bundler webpack --directory=apps/${appName}`
- );
- updateFile(`apps/${appName}/src/main.ts`, `console.log('Hello');\n`);
- updateFile(`apps/${appName}/src/foo.ts`, `console.log('Foo');\n`);
- updateFile(`apps/${appName}/src/bar.ts`, `console.log('Bar');\n`);
-
- updateFile(
- `apps/${appName}/webpack.config.js`,
- `
- const path = require('path');
- const { NxAppWebpackPlugin } = require('@nx/webpack/app-plugin');
-
- module.exports = {
- target: 'node',
- output: {
- path: path.join(__dirname, '../../dist/apps/${appName}'),
- // do not remove dist, so files between builds will remain
- clean: false,
- },
- plugins: [
- new NxAppWebpackPlugin({
- compiler: 'tsc',
- main: './src/main.ts',
- additionalEntryPoints: [
- './src/foo.ts',
- {
- entryName: 'bar',
- entryPath: './src/bar.ts',
- }
- ],
- tsConfig: './tsconfig.app.json',
- outputHashing: 'none',
- optimization: false,
- })
- ]
- };`
- );
-
- runCLI(`build ${appName}`);
-
- expect(runCommand(`node dist/apps/${appName}/main.js`)).toMatch(/Hello/);
- expect(runCommand(`node dist/apps/${appName}/foo.js`)).toMatch(/Foo/);
- expect(runCommand(`node dist/apps/${appName}/bar.js`)).toMatch(/Bar/);
-
- // Ensure dist is not removed between builds since output.clean === false
- createFile(`dist/apps/${appName}/extra.js`);
- runCLI(`build ${appName} --skip-nx-cache`);
- checkFilesExist(`dist/apps/${appName}/extra.js`);
- }, 500_000);
-
- it('should bundle in NX_PUBLIC_ environment variables', () => {
- const appName = uniq('app');
- runCLI(
- `generate @nx/web:app ${appName} --directory=apps/${appName} --bundler webpack`
- );
-
- checkFilesExist(`apps/${appName}/src/main.ts`);
- updateFile(
- `apps/${appName}/src/main.ts`,
- `
- console.log(process.env['NX_PUBLIC_TEST']);
- `
- );
-
- runCLI(`build ${appName}`, {
- env: {
- NX_PUBLIC_TEST: 'foobar',
- },
- });
-
- const mainFile = listFiles(`dist/apps/${appName}`).filter((f) =>
- f.startsWith('main.')
- );
- const content = readFile(`dist/apps/${appName}/${mainFile}`);
- expect(content).toMatch(/foobar/);
- });
-
- it('should support babel + core-js to polyfill JS features', async () => {
- const appName = uniq('app');
- runCLI(
- `generate @nx/web:app ${appName} --directory=apps/${appName} --bundler webpack --compiler=babel`
- );
- packageInstall('core-js', undefined, '3.26.1', 'prod');
-
- checkFilesExist(`apps/${appName}/src/main.ts`);
- updateFile(
- `apps/${appName}/src/main.ts`,
- `
- import 'core-js/stable';
- async function main() {
- const result = await Promise.resolve('foobar')
- console.log(result);
- }
- main();
- `
- );
-
- // Modern browser
- updateFile(`apps/${appName}/.browserslistrc`, `last 1 Chrome version\n`);
- runCLI(`build ${appName}`);
- expect(readMainFile(`dist/apps/${appName}`)).toMatch(`await Promise`);
-
- // Legacy browser
- updateFile(`apps/${appName}/.browserslistrc`, `IE 11\n`);
- runCLI(`build ${appName}`);
- expect(readMainFile(`dist/apps/${appName}`)).not.toMatch(`await Promise`);
- });
-
- it('should allow options to be passed from the executor', async () => {
- const appName = uniq('app');
- runCLI(
- `generate @nx/web:app ${appName} --directory=apps/${appName} --bundler webpack`
- );
-
- checkFilesExist(`apps/${appName}/project.json`);
- updateJson(`apps/${appName}/project.json`, (json) => {
- json.targets.build = {
- executor: '@nx/webpack:webpack',
- outputs: ['{options.outputPath}'],
- options: {
- generatePackageJson: true, // This should be passed to the plugin.
- outputPath: `dist/apps/${appName}`,
- webpackConfig: `apps/${appName}/webpack.config.js`,
- },
- };
- return json;
- });
-
- checkFilesExist(`apps/${appName}/webpack.config.js`);
- updateFile(
- `apps/${appName}/webpack.config.js`,
- `
- const { NxAppWebpackPlugin } = require('@nx/webpack/app-plugin');
- const { join } = require('path');
- module.exports = {
- output: {
- path: join(__dirname, '../../dist/apps/demo'),
- },
- plugins: [
- new NxAppWebpackPlugin({
- // NOTE: generatePackageJson is missing here, but executor passes it.
- target: 'web',
- compiler: 'swc',
- main: './src/main.ts',
- tsConfig: './tsconfig.app.json',
- optimization: false,
- outputHashing: 'none',
- }),
- ],
- };`
- );
-
- runCLI(`build ${appName}`);
-
- fileExists(`dist/apps/${appName}/package.json`);
- });
-
- it('should resolve assets from executors as relative to workspace root', () => {
- const appName = uniq('app');
- runCLI(
- `generate @nx/web:app ${appName} --directory=apps/${appName} --bundler webpack`
- );
- updateFile('shared/docs/TEST.md', 'TEST');
- updateJson(`apps/${appName}/project.json`, (json) => {
- json.targets.build = {
- executor: '@nx/webpack:webpack',
- outputs: ['{options.outputPath}'],
- options: {
- assets: [
- {
- input: 'shared/docs',
- glob: 'TEST.md',
- output: '.',
- },
- ],
- outputPath: `dist/apps/${appName}`,
- webpackConfig: `apps/${appName}/webpack.config.js`,
- },
- };
- return json;
- });
-
- runCLI(`build ${appName}`);
-
- checkFilesExist(`dist/apps/${appName}/TEST.md`);
- });
-
- it('it should support building libraries and apps when buildLibsFromSource is false', () => {
- const appName = uniq('app');
- const myPkg = uniq('my-pkg');
-
- runCLI(
- `generate @nx/web:application ${appName} --directory=apps/${appName}`
- );
-
- runCLI(
- `generate @nx/js:lib ${myPkg} --directory=libs/${myPkg} --importPath=@${appName}/${myPkg}`
- );
-
- updateFile(`libs/${myPkg}/src/index.ts`, `export const foo = 'bar';\n`);
-
- updateFile(
- `apps/${appName}/src/main.ts`,
- `import { foo } from '@${appName}/${myPkg}';\nconsole.log(foo);\n`
- );
-
- updateFile(
- `apps/${appName}/webpack.config.js`,
- `
- const path = require('path');
- const { NxAppWebpackPlugin } = require('@nx/webpack/app-plugin');
-
- module.exports = {
- target: 'node',
- output: {
- path: path.join(__dirname, '../../dist/${appName}')
- },
- plugins: [
- new NxAppWebpackPlugin({
- compiler: 'tsc',
- main: 'apps/${appName}/src/main.ts',
- tsConfig: 'apps/${appName}/tsconfig.app.json',
- outputHashing: 'none',
- optimization: false,
- buildLibsFromSource: false,
- })
- ]
- };`
- );
-
- const result = runCLI(`build ${appName}`);
-
- expect(result).toContain(
- `Running target build for project ${appName} and 1 task it depends on`
- );
- expect(result).toContain(`nx run ${myPkg}:build`);
- expect(result).toContain(
- `Successfully ran target build for project ${appName} and 1 task it depends on`
- );
- });
-
- it('should be able to support webpack config with nx enhanced and babel', () => {
- const appName = uniq('app');
-
- runCLI(
- `generate @nx/web:app ${appName} --directory=apps/${appName} --bundler=webpack --compiler=babel`
- );
-
- updateFile(
- `apps/${appName}/webpack.config.js`,
- `
- const { composePlugins, withNx } = require('@nx/webpack');
- const { withReact } = require('@nx/react');
- const { join } = require('path');
-
- const pluginOption = {
- index: 'apps/${appName}/src/index.html',
- main: 'apps/${appName}/src/main.ts',
- tsConfig: 'apps/${appName}/tsconfig.app.json',
- outputPath: 'dist/apps/${appName}',
- }
-
- // Nx composable plugins for webpack.
- module.exports = composePlugins(
- withNx(pluginOption),
- withReact(pluginOption),
- );`
- );
-
- const result = runCLI(`build ${appName}`);
-
- expect(result).toContain(`nx run ${appName}:build`);
- expect(result).toContain(
- `Successfully ran target build for project ${appName}`
- );
- });
-
- describe('config types', () => {
- it('should support a standard config object', () => {
- const appName = uniq('app');
-
- runCLI(
- `generate @nx/react:application --directory=apps/${appName} --bundler=webpack --e2eTestRunner=none`
- );
-
- updateFile(
- `apps/${appName}/webpack.config.js`,
- `
- const path = require('path');
- const { NxAppWebpackPlugin } = require('@nx/webpack/app-plugin');
-
- module.exports = {
- target: 'node',
- output: {
- path: path.join(__dirname, '../../dist/${appName}')
- },
- plugins: [
- new NxAppWebpackPlugin({
- compiler: 'babel',
- main: './src/main.tsx',
- tsConfig: './tsconfig.app.json',
- outputHashing: 'none',
- optimization: false,
- })
- ]
- };`
- );
-
- const result = runCLI(`build ${appName}`);
-
- expect(result).toContain(
- `Successfully ran target build for project ${appName}`
- );
- });
-
- it('should support a standard function that returns a config object', () => {
- const appName = uniq('app');
-
- runCLI(
- `generate @nx/react:application --directory=apps/${appName} --bundler=webpack --e2eTestRunner=none`
- );
-
- updateFile(
- `apps/${appName}/webpack.config.js`,
- `
- const path = require('path');
- const { NxAppWebpackPlugin } = require('@nx/webpack/app-plugin');
-
- module.exports = () => {
- return {
- target: 'node',
- output: {
- path: path.join(__dirname, '../../dist/${appName}')
- },
- plugins: [
- new NxAppWebpackPlugin({
- compiler: 'tsc',
- main: './src/main.tsx',
- tsConfig: './tsconfig.app.json',
- outputHashing: 'none',
- optimization: false,
- })
- ]
- };
- };`
- );
-
- const result = runCLI(`build ${appName}`);
- expect(result).toContain(
- `Successfully ran target build for project ${appName}`
- );
- });
-
- it('should support an array of standard config objects', () => {
- const appName = uniq('app');
- const serverName = uniq('server');
-
- runCLI(
- `generate @nx/react:application --directory=apps/${appName} --bundler=webpack --e2eTestRunner=none`
- );
-
- // Create server index file
- createFile(
- `apps/${serverName}/index.js`,
- `console.log('Hello from ${serverName}');\n`
- );
-
- updateFile(
- `apps/${appName}/webpack.config.js`,
- `
- const path = require('path');
- const { NxAppWebpackPlugin } = require('@nx/webpack/app-plugin');
-
- module.exports = [
- {
- name: 'client',
- target: 'node',
- output: {
- path: path.join(__dirname, '../../dist/${appName}')
- },
- plugins: [
- new NxAppWebpackPlugin({
- compiler: 'tsc',
- main: './src/main.tsx',
- tsConfig: './tsconfig.app.json',
- outputHashing: 'none',
- optimization: false,
- })
- ]
- }, {
- name: 'server',
- target: 'node',
- entry: '../${serverName}/index.js',
- output: {
- path: path.join(__dirname, '../../dist/${serverName}'),
- filename: 'index.js',
- },
- }
- ];
- `
- );
-
- const result = runCLI(`build ${appName}`);
-
- checkFilesExist(`dist/${appName}/main.js`);
- checkFilesExist(`dist/${serverName}/index.js`);
-
- expect(result).toContain(
- `Successfully ran target build for project ${appName}`
- );
- });
-
- it('should support a function that returns an array of standard config objects', () => {
- const appName = uniq('app');
- const serverName = uniq('server');
-
- runCLI(
- `generate @nx/react:application --directory=apps/${appName} --bundler=webpack --e2eTestRunner=none`
- );
-
- // Create server index file
- createFile(
- `apps/${serverName}/index.js`,
- `console.log('Hello from ${serverName}');\n`
- );
-
- updateFile(
- `apps/${appName}/webpack.config.js`,
- `
- const path = require('path');
- const { NxAppWebpackPlugin } = require('@nx/webpack/app-plugin');
-
- module.exports = () => {
- return [
- {
- name: 'client',
- target: 'node',
- output: {
- path: path.join(__dirname, '../../dist/${appName}')
- },
- plugins: [
- new NxAppWebpackPlugin({
- compiler: 'tsc',
- main: './src/main.tsx',
- tsConfig: './tsconfig.app.json',
- outputHashing: 'none',
- optimization: false,
- })
- ]
- },
- {
- name: 'server',
- target: 'node',
- entry: '../${serverName}/index.js',
- output: {
- path: path.join(__dirname, '../../dist/${serverName}'),
- filename: 'index.js',
- }
- }
- ];
- };`
- );
- const result = runCLI(`build ${appName}`);
-
- checkFilesExist(`dist/${serverName}/index.js`);
- checkFilesExist(`dist/${appName}/main.js`);
-
- expect(result).toContain(
- `Successfully ran target build for project ${appName}`
- );
- });
- });
-});
-
-function readMainFile(dir: string): string {
- const main = listFiles(dir).find((f) => f.startsWith('main.'));
- return readFile(`${dir}/${main}`);
-}
diff --git a/e2e/workspace-create/src/create-nx-workspace-npm-angular.test.ts b/e2e/workspace-create/src/create-nx-workspace-npm-angular.test.ts
new file mode 100644
index 0000000000000..d72e9794ee365
--- /dev/null
+++ b/e2e/workspace-create/src/create-nx-workspace-npm-angular.test.ts
@@ -0,0 +1,41 @@
+import {
+ checkFilesExist,
+ packageInstall,
+ readJson,
+ runCLI,
+ uniq,
+} from '@nx/e2e-utils';
+import {
+ setupNpmWorkspaceTest,
+ getWorkspaceName,
+} from './create-nx-workspace-npm-setup';
+
+describe('create-nx-workspace --preset=npm', () => {
+ setupNpmWorkspaceTest();
+
+ it('should add angular application', () => {
+ const wsName = getWorkspaceName();
+ packageInstall('@nx/angular', wsName);
+ const appName = uniq('my-app');
+
+ expect(() => {
+ runCLI(`generate @nx/angular:app packages/${appName} --no-interactive`);
+ }).not.toThrow();
+ checkFilesExist('tsconfig.base.json');
+ }, 1_000_000);
+
+ it('should add angular library', () => {
+ const wsName = getWorkspaceName();
+ packageInstall('@nx/angular', wsName);
+ const libName = uniq('lib');
+
+ expect(() => {
+ runCLI(`generate @nx/angular:lib packages/${libName} --no-interactive`);
+ }).not.toThrow();
+ checkFilesExist('tsconfig.base.json');
+ const tsconfig = readJson(`tsconfig.base.json`);
+ expect(tsconfig.compilerOptions.paths).toEqual({
+ [`@${wsName}/${libName}`]: [`packages/${libName}/src/index.ts`],
+ });
+ }, 1_000_000);
+});
diff --git a/e2e/workspace-create/src/create-nx-workspace-npm-express.test.ts b/e2e/workspace-create/src/create-nx-workspace-npm-express.test.ts
new file mode 100644
index 0000000000000..07a3a86d3cd1e
--- /dev/null
+++ b/e2e/workspace-create/src/create-nx-workspace-npm-express.test.ts
@@ -0,0 +1,21 @@
+import { checkFilesExist, packageInstall, runCLI, uniq } from '@nx/e2e-utils';
+import {
+ setupNpmWorkspaceTest,
+ getWorkspaceName,
+} from './create-nx-workspace-npm-setup';
+
+describe('create-nx-workspace --preset=npm', () => {
+ setupNpmWorkspaceTest();
+
+ it('should add express application', () => {
+ const wsName = getWorkspaceName();
+ packageInstall('@nx/express', wsName);
+
+ const appName = uniq('my-app');
+
+ expect(() => {
+ runCLI(`generate @nx/express:app packages/${appName} --no-interactive`);
+ }).not.toThrow();
+ checkFilesExist('tsconfig.base.json');
+ });
+});
diff --git a/e2e/workspace-create/src/create-nx-workspace-npm-init.test.ts b/e2e/workspace-create/src/create-nx-workspace-npm-init.test.ts
new file mode 100644
index 0000000000000..e419bde76da5d
--- /dev/null
+++ b/e2e/workspace-create/src/create-nx-workspace-npm-init.test.ts
@@ -0,0 +1,24 @@
+import {
+ checkFilesExist,
+ getSelectedPackageManager,
+ readJson,
+} from '@nx/e2e-utils';
+import {
+ setupNpmWorkspaceTest,
+ getWorkspaceName,
+} from './create-nx-workspace-npm-setup';
+
+describe('create-nx-workspace --preset=npm', () => {
+ setupNpmWorkspaceTest();
+
+ it('should setup package-based workspace', () => {
+ const packageJson = readJson('package.json');
+ expect(packageJson.dependencies).toEqual({});
+
+ if (getSelectedPackageManager() === 'pnpm') {
+ checkFilesExist('pnpm-workspace.yaml');
+ } else {
+ expect(packageJson.workspaces).toEqual(['packages/*']);
+ }
+ });
+});
diff --git a/e2e/workspace-create/src/create-nx-workspace-npm-js.test.ts b/e2e/workspace-create/src/create-nx-workspace-npm-js.test.ts
new file mode 100644
index 0000000000000..ad15853db8e32
--- /dev/null
+++ b/e2e/workspace-create/src/create-nx-workspace-npm-js.test.ts
@@ -0,0 +1,34 @@
+import {
+ checkFilesExist,
+ packageInstall,
+ readJson,
+ runCLI,
+ uniq,
+} from '@nx/e2e-utils';
+import {
+ setupNpmWorkspaceTest,
+ getWorkspaceName,
+} from './create-nx-workspace-npm-setup';
+
+describe('create-nx-workspace --preset=npm', () => {
+ setupNpmWorkspaceTest();
+
+ it('should add js library', () => {
+ const wsName = getWorkspaceName();
+ packageInstall('@nx/js', wsName);
+
+ const libName = uniq('lib');
+
+ expect(() =>
+ runCLI(`generate @nx/js:library packages/${libName} --no-interactive`)
+ ).not.toThrow();
+ checkFilesExist('tsconfig.base.json', 'tsconfig.json');
+ const tsconfigBase = readJson(`tsconfig.base.json`);
+ expect(tsconfigBase.compilerOptions.paths).toBeUndefined();
+ const tsconfig = readJson(`tsconfig.json`);
+ expect(tsconfig.extends).toBe('./tsconfig.base.json');
+ expect(tsconfig.references).toStrictEqual([
+ { path: `./packages/${libName}` },
+ ]);
+ });
+});
diff --git a/e2e/workspace-create/src/create-nx-workspace-npm-nest.test.ts b/e2e/workspace-create/src/create-nx-workspace-npm-nest.test.ts
new file mode 100644
index 0000000000000..7dd0d2611d3f5
--- /dev/null
+++ b/e2e/workspace-create/src/create-nx-workspace-npm-nest.test.ts
@@ -0,0 +1,46 @@
+import {
+ checkFilesExist,
+ packageInstall,
+ readJson,
+ runCLI,
+ uniq,
+} from '@nx/e2e-utils';
+import {
+ setupNpmWorkspaceTest,
+ getWorkspaceName,
+} from './create-nx-workspace-npm-setup';
+
+describe('create-nx-workspace --preset=npm', () => {
+ setupNpmWorkspaceTest();
+
+ it('should add nest application', () => {
+ const wsName = getWorkspaceName();
+ packageInstall('@nx/nest', wsName);
+
+ const appName = uniq('my-app');
+
+ expect(() => {
+ runCLI(`generate @nx/nest:app packages/${appName} --no-interactive`);
+ }).not.toThrow();
+ checkFilesExist('tsconfig.base.json');
+ });
+
+ it('should add nest library', () => {
+ const wsName = getWorkspaceName();
+ packageInstall('@nx/nest', wsName);
+
+ const libName = uniq('lib');
+
+ expect(() => {
+ runCLI(`generate @nx/nest:lib packages/${libName} --no-interactive`);
+ }).not.toThrow();
+ checkFilesExist('tsconfig.base.json', 'tsconfig.json');
+ const tsconfigBase = readJson(`tsconfig.base.json`);
+ expect(tsconfigBase.compilerOptions.paths).toBeUndefined();
+ const tsconfig = readJson(`tsconfig.json`);
+ expect(tsconfig.extends).toBe('./tsconfig.base.json');
+ expect(tsconfig.references).toStrictEqual([
+ { path: `./packages/${libName}` },
+ ]);
+ });
+});
diff --git a/e2e/workspace-create/src/create-nx-workspace-npm-next.test.ts b/e2e/workspace-create/src/create-nx-workspace-npm-next.test.ts
new file mode 100644
index 0000000000000..6ae05ed9c73e0
--- /dev/null
+++ b/e2e/workspace-create/src/create-nx-workspace-npm-next.test.ts
@@ -0,0 +1,46 @@
+import {
+ checkFilesExist,
+ packageInstall,
+ readJson,
+ runCLI,
+ uniq,
+} from '@nx/e2e-utils';
+import {
+ setupNpmWorkspaceTest,
+ getWorkspaceName,
+} from './create-nx-workspace-npm-setup';
+
+describe('create-nx-workspace --preset=npm', () => {
+ setupNpmWorkspaceTest();
+
+ it('should add next application', () => {
+ const wsName = getWorkspaceName();
+ packageInstall('@nx/next', wsName);
+
+ const appName = uniq('my-app');
+
+ expect(() => {
+ runCLI(`generate @nx/next:app packages/${appName} --no-interactive`);
+ }).not.toThrow();
+ checkFilesExist('tsconfig.base.json');
+ });
+
+ it('should add next library', () => {
+ const wsName = getWorkspaceName();
+ packageInstall('@nx/next', wsName);
+
+ const libName = uniq('lib');
+
+ expect(() => {
+ runCLI(`generate @nx/next:lib packages/${libName} --no-interactive`);
+ }).not.toThrow();
+ checkFilesExist('tsconfig.base.json', 'tsconfig.json');
+ const tsconfigBase = readJson(`tsconfig.base.json`);
+ expect(tsconfigBase.compilerOptions.paths).toBeUndefined();
+ const tsconfig = readJson(`tsconfig.json`);
+ expect(tsconfig.extends).toBe('./tsconfig.base.json');
+ expect(tsconfig.references).toStrictEqual([
+ { path: `./packages/${libName}` },
+ ]);
+ });
+});
diff --git a/e2e/workspace-create/src/create-nx-workspace-npm-node.test.ts b/e2e/workspace-create/src/create-nx-workspace-npm-node.test.ts
new file mode 100644
index 0000000000000..e8a2c3682ed24
--- /dev/null
+++ b/e2e/workspace-create/src/create-nx-workspace-npm-node.test.ts
@@ -0,0 +1,46 @@
+import {
+ checkFilesExist,
+ packageInstall,
+ readJson,
+ runCLI,
+ uniq,
+} from '@nx/e2e-utils';
+import {
+ setupNpmWorkspaceTest,
+ getWorkspaceName,
+} from './create-nx-workspace-npm-setup';
+
+describe('create-nx-workspace --preset=npm', () => {
+ setupNpmWorkspaceTest();
+
+ it('should add node application', () => {
+ const wsName = getWorkspaceName();
+ packageInstall('@nx/node', wsName);
+
+ const appName = uniq('my-app');
+
+ expect(() => {
+ runCLI(`generate @nx/node:app packages/${appName} --no-interactive`);
+ }).not.toThrow();
+ checkFilesExist('tsconfig.base.json');
+ });
+
+ it('should add node library', () => {
+ const wsName = getWorkspaceName();
+ packageInstall('@nx/node', wsName);
+
+ const libName = uniq('lib');
+
+ expect(() => {
+ runCLI(`generate @nx/node:lib packages/${libName} --no-interactive`);
+ }).not.toThrow();
+ checkFilesExist('tsconfig.base.json', 'tsconfig.json');
+ const tsconfigBase = readJson(`tsconfig.base.json`);
+ expect(tsconfigBase.compilerOptions.paths).toBeUndefined();
+ const tsconfig = readJson(`tsconfig.json`);
+ expect(tsconfig.extends).toBe('./tsconfig.base.json');
+ expect(tsconfig.references).toStrictEqual([
+ { path: `./packages/${libName}` },
+ ]);
+ });
+});
diff --git a/e2e/workspace-create/src/create-nx-workspace-npm-react-native.test.ts b/e2e/workspace-create/src/create-nx-workspace-npm-react-native.test.ts
new file mode 100644
index 0000000000000..6f28dc361f99d
--- /dev/null
+++ b/e2e/workspace-create/src/create-nx-workspace-npm-react-native.test.ts
@@ -0,0 +1,50 @@
+import {
+ checkFilesExist,
+ packageInstall,
+ readJson,
+ runCLI,
+ uniq,
+} from '@nx/e2e-utils';
+import {
+ setupNpmWorkspaceTest,
+ getWorkspaceName,
+} from './create-nx-workspace-npm-setup';
+
+describe('create-nx-workspace --preset=npm', () => {
+ setupNpmWorkspaceTest();
+
+ it('should add react-native application', () => {
+ const wsName = getWorkspaceName();
+ packageInstall('@nx/react-native', wsName);
+
+ const appName = uniq('my-app');
+
+ expect(() => {
+ runCLI(
+ `generate @nx/react-native:app packages/${appName} --install=false --no-interactive`
+ );
+ }).not.toThrow();
+ checkFilesExist('tsconfig.base.json');
+ });
+
+ it('should add react-native library', () => {
+ const wsName = getWorkspaceName();
+ packageInstall('@nx/react-native', wsName);
+
+ const libName = uniq('lib');
+
+ expect(() => {
+ runCLI(
+ `generate @nx/react-native:lib packages/${libName} --no-interactive`
+ );
+ }).not.toThrow();
+ checkFilesExist('tsconfig.base.json', 'tsconfig.json');
+ const tsconfigBase = readJson(`tsconfig.base.json`);
+ expect(tsconfigBase.compilerOptions.paths).toBeUndefined();
+ const tsconfig = readJson(`tsconfig.json`);
+ expect(tsconfig.extends).toBe('./tsconfig.base.json');
+ expect(tsconfig.references).toStrictEqual([
+ { path: `./packages/${libName}` },
+ ]);
+ });
+});
diff --git a/e2e/workspace-create/src/create-nx-workspace-npm-react.test.ts b/e2e/workspace-create/src/create-nx-workspace-npm-react.test.ts
new file mode 100644
index 0000000000000..defe48e5179d5
--- /dev/null
+++ b/e2e/workspace-create/src/create-nx-workspace-npm-react.test.ts
@@ -0,0 +1,46 @@
+import {
+ checkFilesExist,
+ packageInstall,
+ readJson,
+ runCLI,
+ uniq,
+} from '@nx/e2e-utils';
+import {
+ setupNpmWorkspaceTest,
+ getWorkspaceName,
+} from './create-nx-workspace-npm-setup';
+
+describe('create-nx-workspace --preset=npm', () => {
+ setupNpmWorkspaceTest();
+
+ it('should add react application', () => {
+ const wsName = getWorkspaceName();
+ packageInstall('@nx/react', wsName);
+
+ const appName = uniq('my-app');
+
+ expect(() => {
+ runCLI(`generate @nx/react:app packages/${appName} --no-interactive`);
+ }).not.toThrow();
+ checkFilesExist('tsconfig.base.json');
+ });
+
+ it('should add react library', () => {
+ const wsName = getWorkspaceName();
+ packageInstall('@nx/react', wsName);
+
+ const libName = uniq('lib');
+
+ expect(() => {
+ runCLI(`generate @nx/react:lib packages/${libName} --no-interactive`);
+ }).not.toThrow();
+ checkFilesExist('tsconfig.base.json', 'tsconfig.json');
+ const tsconfigBase = readJson(`tsconfig.base.json`);
+ expect(tsconfigBase.compilerOptions.paths).toBeUndefined();
+ const tsconfig = readJson(`tsconfig.json`);
+ expect(tsconfig.extends).toBe('./tsconfig.base.json');
+ expect(tsconfig.references).toStrictEqual([
+ { path: `./packages/${libName}` },
+ ]);
+ });
+});
diff --git a/e2e/workspace-create/src/create-nx-workspace-npm-setup.ts b/e2e/workspace-create/src/create-nx-workspace-npm-setup.ts
new file mode 100644
index 0000000000000..28e8893a24849
--- /dev/null
+++ b/e2e/workspace-create/src/create-nx-workspace-npm-setup.ts
@@ -0,0 +1,39 @@
+import {
+ cleanupProject,
+ getSelectedPackageManager,
+ runCommand,
+ runCreateWorkspace,
+ uniq,
+} from '@nx/e2e-utils';
+
+const wsName = uniq('npm');
+
+let orginalGlobCache;
+
+export function setupNpmWorkspaceTest() {
+ beforeAll(() => {
+ orginalGlobCache = process.env.NX_PROJECT_GLOB_CACHE;
+ // glob cache is causing previous projects to show in Workspace for maxWorkers overrides
+ // which fails due to files no longer being available
+ process.env.NX_PROJECT_GLOB_CACHE = 'false';
+
+ runCreateWorkspace(wsName, {
+ preset: 'npm',
+ packageManager: getSelectedPackageManager(),
+ });
+ });
+
+ afterEach(() => {
+ // cleanup previous projects
+ runCommand(`rm -rf packages/** tsconfig.base.json tsconfig.json`);
+ });
+
+ afterAll(() => {
+ process.env.NX_PROJECT_GLOB_CACHE = orginalGlobCache;
+ cleanupProject({ skipReset: true });
+ });
+}
+
+export function getWorkspaceName() {
+ return wsName;
+}
diff --git a/e2e/workspace-create/src/create-nx-workspace-npm-web.test.ts b/e2e/workspace-create/src/create-nx-workspace-npm-web.test.ts
new file mode 100644
index 0000000000000..9c73153737da5
--- /dev/null
+++ b/e2e/workspace-create/src/create-nx-workspace-npm-web.test.ts
@@ -0,0 +1,21 @@
+import { checkFilesExist, packageInstall, runCLI, uniq } from '@nx/e2e-utils';
+import {
+ setupNpmWorkspaceTest,
+ getWorkspaceName,
+} from './create-nx-workspace-npm-setup';
+
+describe('create-nx-workspace --preset=npm', () => {
+ setupNpmWorkspaceTest();
+
+ it('should add web application', () => {
+ const wsName = getWorkspaceName();
+ packageInstall('@nx/web', wsName);
+
+ const appName = uniq('my-app');
+
+ expect(() =>
+ runCLI(`generate @nx/web:app packages/${appName} --no-interactive`)
+ ).not.toThrow();
+ checkFilesExist('tsconfig.base.json');
+ });
+});
diff --git a/e2e/workspace-create/src/create-nx-workspace-npm.test.ts b/e2e/workspace-create/src/create-nx-workspace-npm.test.ts
deleted file mode 100644
index 837902373f585..0000000000000
--- a/e2e/workspace-create/src/create-nx-workspace-npm.test.ts
+++ /dev/null
@@ -1,263 +0,0 @@
-import {
- checkFilesExist,
- cleanupProject,
- getSelectedPackageManager,
- packageInstall,
- readJson,
- runCLI,
- runCommand,
- runCreateWorkspace,
- uniq,
-} from '@nx/e2e-utils';
-
-describe('create-nx-workspace --preset=npm', () => {
- const wsName = uniq('npm');
-
- let orginalGlobCache;
-
- beforeAll(() => {
- orginalGlobCache = process.env.NX_PROJECT_GLOB_CACHE;
- // glob cache is causing previous projects to show in Workspace for maxWorkers overrides
- // which fails due to files no longer being available
- process.env.NX_PROJECT_GLOB_CACHE = 'false';
-
- runCreateWorkspace(wsName, {
- preset: 'npm',
- packageManager: getSelectedPackageManager(),
- });
- });
-
- afterEach(() => {
- // cleanup previous projects
- runCommand(`rm -rf packages/** tsconfig.base.json tsconfig.json`);
- });
-
- afterAll(() => {
- process.env.NX_PROJECT_GLOB_CACHE = orginalGlobCache;
- cleanupProject({ skipReset: true });
- });
-
- it('should setup package-based workspace', () => {
- const packageJson = readJson('package.json');
- expect(packageJson.dependencies).toEqual({});
-
- if (getSelectedPackageManager() === 'pnpm') {
- checkFilesExist('pnpm-workspace.yaml');
- } else {
- expect(packageJson.workspaces).toEqual(['packages/*']);
- }
- });
-
- it('should add angular application', () => {
- packageInstall('@nx/angular', wsName);
- const appName = uniq('my-app');
-
- expect(() => {
- runCLI(`generate @nx/angular:app packages/${appName} --no-interactive`);
- }).not.toThrow();
- checkFilesExist('tsconfig.base.json');
- }, 1_000_000);
-
- it('should add angular library', () => {
- packageInstall('@nx/angular', wsName);
- const libName = uniq('lib');
-
- expect(() => {
- runCLI(`generate @nx/angular:lib packages/${libName} --no-interactive`);
- }).not.toThrow();
- checkFilesExist('tsconfig.base.json');
- const tsconfig = readJson(`tsconfig.base.json`);
- expect(tsconfig.compilerOptions.paths).toEqual({
- [`@${wsName}/${libName}`]: [`packages/${libName}/src/index.ts`],
- });
- }, 1_000_000);
-
- it('should add js library', () => {
- packageInstall('@nx/js', wsName);
-
- const libName = uniq('lib');
-
- expect(() =>
- runCLI(`generate @nx/js:library packages/${libName} --no-interactive`)
- ).not.toThrow();
- checkFilesExist('tsconfig.base.json', 'tsconfig.json');
- const tsconfigBase = readJson(`tsconfig.base.json`);
- expect(tsconfigBase.compilerOptions.paths).toBeUndefined();
- const tsconfig = readJson(`tsconfig.json`);
- expect(tsconfig.extends).toBe('./tsconfig.base.json');
- expect(tsconfig.references).toStrictEqual([
- { path: `./packages/${libName}` },
- ]);
- });
-
- it('should add web application', () => {
- packageInstall('@nx/web', wsName);
-
- const appName = uniq('my-app');
-
- expect(() =>
- runCLI(`generate @nx/web:app packages/${appName} --no-interactive`)
- ).not.toThrow();
- checkFilesExist('tsconfig.base.json');
- });
-
- it('should add react application', () => {
- packageInstall('@nx/react', wsName);
-
- const appName = uniq('my-app');
-
- expect(() => {
- runCLI(`generate @nx/react:app packages/${appName} --no-interactive`);
- }).not.toThrow();
- checkFilesExist('tsconfig.base.json');
- });
-
- it('should add react library', () => {
- packageInstall('@nx/react', wsName);
-
- const libName = uniq('lib');
-
- expect(() => {
- runCLI(`generate @nx/react:lib packages/${libName} --no-interactive`);
- }).not.toThrow();
- checkFilesExist('tsconfig.base.json', 'tsconfig.json');
- const tsconfigBase = readJson(`tsconfig.base.json`);
- expect(tsconfigBase.compilerOptions.paths).toBeUndefined();
- const tsconfig = readJson(`tsconfig.json`);
- expect(tsconfig.extends).toBe('./tsconfig.base.json');
- expect(tsconfig.references).toStrictEqual([
- { path: `./packages/${libName}` },
- ]);
- });
-
- it('should add next application', () => {
- packageInstall('@nx/next', wsName);
-
- const appName = uniq('my-app');
-
- expect(() => {
- runCLI(`generate @nx/next:app packages/${appName} --no-interactive`);
- }).not.toThrow();
- checkFilesExist('tsconfig.base.json');
- });
-
- it('should add next library', () => {
- packageInstall('@nx/next', wsName);
-
- const libName = uniq('lib');
-
- expect(() => {
- runCLI(`generate @nx/next:lib packages/${libName} --no-interactive`);
- }).not.toThrow();
- checkFilesExist('tsconfig.base.json', 'tsconfig.json');
- const tsconfigBase = readJson(`tsconfig.base.json`);
- expect(tsconfigBase.compilerOptions.paths).toBeUndefined();
- const tsconfig = readJson(`tsconfig.json`);
- expect(tsconfig.extends).toBe('./tsconfig.base.json');
- expect(tsconfig.references).toStrictEqual([
- { path: `./packages/${libName}` },
- ]);
- });
-
- it('should add react-native application', () => {
- packageInstall('@nx/react-native', wsName);
-
- const appName = uniq('my-app');
-
- expect(() => {
- runCLI(
- `generate @nx/react-native:app packages/${appName} --install=false --no-interactive`
- );
- }).not.toThrow();
- checkFilesExist('tsconfig.base.json');
- });
-
- it('should add react-native library', () => {
- packageInstall('@nx/react-native', wsName);
-
- const libName = uniq('lib');
-
- expect(() => {
- runCLI(
- `generate @nx/react-native:lib packages/${libName} --no-interactive`
- );
- }).not.toThrow();
- checkFilesExist('tsconfig.base.json', 'tsconfig.json');
- const tsconfigBase = readJson(`tsconfig.base.json`);
- expect(tsconfigBase.compilerOptions.paths).toBeUndefined();
- const tsconfig = readJson(`tsconfig.json`);
- expect(tsconfig.extends).toBe('./tsconfig.base.json');
- expect(tsconfig.references).toStrictEqual([
- { path: `./packages/${libName}` },
- ]);
- });
-
- it('should add node application', () => {
- packageInstall('@nx/node', wsName);
-
- const appName = uniq('my-app');
-
- expect(() => {
- runCLI(`generate @nx/node:app packages/${appName} --no-interactive`);
- }).not.toThrow();
- checkFilesExist('tsconfig.base.json');
- });
-
- it('should add node library', () => {
- packageInstall('@nx/node', wsName);
-
- const libName = uniq('lib');
-
- expect(() => {
- runCLI(`generate @nx/node:lib packages/${libName} --no-interactive`);
- }).not.toThrow();
- checkFilesExist('tsconfig.base.json', 'tsconfig.json');
- const tsconfigBase = readJson(`tsconfig.base.json`);
- expect(tsconfigBase.compilerOptions.paths).toBeUndefined();
- const tsconfig = readJson(`tsconfig.json`);
- expect(tsconfig.extends).toBe('./tsconfig.base.json');
- expect(tsconfig.references).toStrictEqual([
- { path: `./packages/${libName}` },
- ]);
- });
-
- it('should add nest application', () => {
- packageInstall('@nx/nest', wsName);
-
- const appName = uniq('my-app');
-
- expect(() => {
- runCLI(`generate @nx/nest:app packages/${appName} --no-interactive`);
- }).not.toThrow();
- checkFilesExist('tsconfig.base.json');
- });
-
- it('should add nest library', () => {
- packageInstall('@nx/nest', wsName);
-
- const libName = uniq('lib');
-
- expect(() => {
- runCLI(`generate @nx/nest:lib packages/${libName} --no-interactive`);
- }).not.toThrow();
- checkFilesExist('tsconfig.base.json', 'tsconfig.json');
- const tsconfigBase = readJson(`tsconfig.base.json`);
- expect(tsconfigBase.compilerOptions.paths).toBeUndefined();
- const tsconfig = readJson(`tsconfig.json`);
- expect(tsconfig.extends).toBe('./tsconfig.base.json');
- expect(tsconfig.references).toStrictEqual([
- { path: `./packages/${libName}` },
- ]);
- });
-
- it('should add express application', () => {
- packageInstall('@nx/express', wsName);
-
- const appName = uniq('my-app');
-
- expect(() => {
- runCLI(`generate @nx/express:app packages/${appName} --no-interactive`);
- }).not.toThrow();
- checkFilesExist('tsconfig.base.json');
- });
-});
diff --git a/nx.json b/nx.json
index 0c6ca02ce7bf2..f7f2298df0769 100644
--- a/nx.json
+++ b/nx.json
@@ -330,7 +330,7 @@
}
],
"parallel": 1,
- "bust": 3,
+ "bust": 12,
"defaultBase": "master",
"sync": {
"applyChanges": true