import { checkFilesExist, cleanupProject, newProject, rmDist, runCLI, uniq, updateFile, updateJson, } from '@nx/e2e/utils'; import { join } from 'path'; describe('Next.js Webpack', () => { let proj: string; let originalEnv: string; beforeEach(() => { proj = newProject(); originalEnv = process.env.NODE_ENV; }); afterEach(() => { process.env.NODE_ENV = originalEnv; cleanupProject(); }); it('should support custom webpack and run-commands using withNx', async () => { const appName = uniq('app'); runCLI( `generate @nx/next:app ${appName} --no-interactive --style=css --appDir=false` ); updateFile( `apps/${appName}/next.config.js`, ` const { withNx } = require('@nx/next'); const nextConfig = { nx: { svgr: false, }, webpack: (config, context) => { // Make sure SVGR plugin is disabled if nx.svgr === false (see above) const found = config.module.rules.find((rule) => { // Check if the rule is for SVG files if (!/\.(svg)$/i.test('test.svg')) return false; // Check if the rule has a 'oneOf' structure if (!rule.oneOf || !Array.isArray(rule.oneOf)) return false; // Check each item in 'oneOf' for SVGR loader return rule.oneOf.some((oneOfRule) => { if (!oneOfRule.use) return false; // 'use' might be an object or an array, ensure it's an array for consistency const uses = Array.isArray(oneOfRule.use) ? oneOfRule.use : [oneOfRule.use]; return uses.some(use => { if (typeof use.loader !== 'string') return false; const svgrRegex = new RegExp('@svgr/webpack'); return svgrRegex.test(use.loader); }); }); }); if (found) throw new Error('Found SVGR plugin'); console.log('NODE_ENV is', process.env.NODE_ENV); return config; } }; module.exports = withNx(nextConfig); ` ); // deleting `NODE_ENV` value, so that it's `undefined`, and not `"test"` // by the time it reaches the build executor. // this simulates existing behaviour of running a next.js build executor via Nx delete process.env.NODE_ENV; const result = runCLI(`build ${appName}`); checkFilesExist(`dist/apps/${appName}/next.config.js`); expect(result).toContain('NODE_ENV is production'); updateFile( `apps/${appName}/next.config.js`, ` const { withNx } = require('@nx/next'); // Not including "nx" entry should still work. const nextConfig = {}; module.exports = withNx(nextConfig); ` ); rmDist(); runCLI(`build ${appName}`); checkFilesExist(`dist/apps/${appName}/next.config.js`); // Make sure withNx works with run-commands. updateJson(join('apps', appName, 'project.json'), (json) => { json.targets.build = { command: 'npx next build', outputs: [`{projectRoot}/.next`], options: { cwd: `apps/${appName}`, }, }; return json; }); expect(() => { runCLI(`build ${appName}`); }).not.toThrow(); checkFilesExist(`dist/apps/${appName}/.next/build-manifest.json`); }, 300_000); });