import { removeSync, mkdirSync } from 'fs-extra'; import { capitalize } from '@nx/devkit/src/utils/string-utils'; import { checkApp } from './utils'; import { checkFilesExist, cleanupProject, isNotWindows, killPort, newProject, readFile, runCLI, runCommandUntil, tmpProjPath, uniq, updateFile, updateProjectConfig, } from '@nx/e2e/utils'; describe('Next.js Apps Libs', () => { let proj: string; let originalEnv: string; beforeEach(() => { proj = newProject(); originalEnv = process.env.NODE_ENV; }); afterEach(() => { process.env.NODE_ENV = originalEnv; cleanupProject(); }); it('should generate app + libs', async () => { // Remove apps/libs folder and use packages. // Allows us to test other integrated monorepo setup that had a regression. // See: https://github.com/nrwl/nx/issues/16658 removeSync(`${tmpProjPath()}/libs`); removeSync(`${tmpProjPath()}/apps`); mkdirSync(`${tmpProjPath()}/packages`); const appName = uniq('app'); const nextLib = uniq('nextlib'); const jsLib = uniq('tslib'); const buildableLib = uniq('buildablelib'); runCLI( `generate @nx/next:app ${appName} --no-interactive --style=css --appDir=false` ); runCLI(`generate @nx/next:lib ${nextLib} --no-interactive`); runCLI(`generate @nx/js:lib ${jsLib} --no-interactive`); runCLI( `generate @nx/js:lib ${buildableLib} --no-interactive --bundler=vite` ); // Create file in public that should be copied to dist updateFile(`packages/${appName}/public/a/b.txt`, `Hello World!`); // Additional assets that should be copied to dist const sharedLib = uniq('sharedLib'); await updateProjectConfig(appName, (json) => { json.targets.build.options.assets = [ { glob: '**/*', input: `packages/${sharedLib}/src/assets`, output: 'shared/ui', }, ]; return json; }); updateFile(`packages/${sharedLib}/src/assets/hello.txt`, 'Hello World!'); // create a css file in node_modules so that it can be imported in a lib // to test that it works as expected updateFile( 'node_modules/@nx/next/test-styles.css', 'h1 { background-color: red; }' ); updateFile( `packages/${jsLib}/src/lib/${jsLib}.ts`, ` export function jsLib(): string { return 'Hello Nx'; }; // testing whether async-await code in Node / Next.js api routes works as expected export async function jsLibAsync() { return await Promise.resolve('hell0'); } ` ); updateFile( `packages/${buildableLib}/src/lib/${buildableLib}.ts`, ` export function buildableLib(): string { return 'Hello Buildable'; }; ` ); const mainPath = `packages/${appName}/pages/index.tsx`; const content = readFile(mainPath); updateFile( `packages/${appName}/pages/api/hello.ts`, ` import { jsLibAsync } from '@${proj}/${jsLib}'; // eslint-disable-next-line @typescript-eslint/no-explicit-any export default async function handler(_: any, res: any) { const value = await jsLibAsync(); res.send(value); } ` ); updateFile( mainPath, ` import { jsLib } from '@${proj}/${jsLib}'; import { buildableLib } from '@${proj}/${buildableLib}'; /* eslint-disable */ import dynamic from 'next/dynamic'; const TestComponent = dynamic( () => import('@${proj}/${nextLib}').then(d => d.${capitalize( nextLib )}) ); ${content.replace( ``, `