Skip to content

Commit

Permalink
fix(nextjs): allow non-supported next confile to still migrate
Browse files Browse the repository at this point in the history
  • Loading branch information
jaysoo authored and ndcunningham committed Jun 27, 2024
1 parent 915eb74 commit 3bc5d50
Show file tree
Hide file tree
Showing 5 changed files with 160 additions and 54 deletions.
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
import { Tree, createProjectGraphAsync, formatFiles } from '@nx/devkit';
import { createProjectGraphAsync, formatFiles, Tree } from '@nx/devkit';
import { AggregatedLog } from '@nx/devkit/src/generators/plugin-migrations/aggregate-log-util';
import { migrateProjectExecutorsToPluginV1 } from '@nx/devkit/src/generators/plugin-migrations/executor-to-plugin-migrator';
import { createNodes } from '../../plugins/plugin';
import { buildPostTargetTransformer } from './lib/build-post-target-transformer';
import { servePosTargetTransformer } from './lib/serve-post-target-tranformer';
import { skipProjectFilterFactory } from './lib/skip-project-filter';

interface Schema {
project?: string;
Expand Down Expand Up @@ -33,15 +32,13 @@ export async function convertToInferred(tree: Tree, options: Schema) {
targetPluginOptionMapper: (targetName) => ({
buildTargetName: targetName,
}),
skipProjectFilter: skipProjectFilterFactory(tree),
},
{
executors: ['@nx/next:server'],
postTargetTransformer: servePosTargetTransformer(migrationLogs),
targetPluginOptionMapper: (targetName) => ({
devTargetName: targetName,
}),
skipProjectFilter: skipProjectFilterFactory(tree),
},
],
options.project
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ export function buildPostTargetTransformer(migrationLogs: AggregatedLog) {
...configValues[configuration],
};
`;
updateNextConfig(tree, partialNextConfig, projectDetails.root);
updateNextConfig(tree, partialNextConfig, projectDetails, migrationLogs);
return target;
};
}
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,145 @@ import { updateNextConfig } from './update-next-config';

describe('UpdateNextConfig', () => {
let tree: Tree;
const mockLog = {
addLog: jest.fn(),
logs: new Map(),
flushLogs: jest.fn(),
reset: jest.fn(),
};

beforeEach(() => {
tree = createTreeWithEmptyWorkspace();
});

// TODO: Add tests
it('should work', () => {
expect(true).toBe(true);
it('should update the next config file adding the options passed in', () => {
const initConfig = `
//@ts-check
// eslint-disable-next-line @typescript-eslint/no-var-requires
const { composePlugins, withNx } = require('@nx/next');
/**
* @type {import('@nx/next/plugins/with-nx').WithNxOptions}
**/
const nextConfig = {
nx: {
// Set this to true if you would like to use SVGR
// See: https://github.com/gregberge/svgr
svgr: false,
},
};
const plugins = [
// Add more Next.js plugins to this list if needed.
withNx,
];
module.exports = composePlugins(...plugins)(nextConfig);
`;

const projectName = 'my-app';
tree.write(`${projectName}/next.config.js`, initConfig);

const executorOptionsString = `
const configValues = {
default: {
fileReplacements: [
{
replace: './environments/environment.ts',
with: './environments/environment.foo.ts',
},
],
},
development: {},
};
const configuration = process.env.NX_TASK_TARGET_CONFIGURATION || 'default';
const options = {
...configValues.default,
//@ts-expect-error: Ignore TypeScript error for indexing configValues with a dynamic key
...configValues[configuration],
};`;

const projectDetails = { projectName, root: projectName };
updateNextConfig(tree, executorOptionsString, projectDetails, mockLog);

const result = tree.read(`${projectName}/next.config.js`, 'utf-8');
expect(result).toMatchInlineSnapshot(`
"//@ts-check
// eslint-disable-next-line @typescript-eslint/no-var-requires
const { composePlugins, withNx } = require('@nx/next');
const configValues = {
default: {
fileReplacements: [
{
replace: './environments/environment.ts',
with: './environments/environment.foo.ts',
},
],
},
development: {},
};
const configuration = process.env.NX_TASK_TARGET_CONFIGURATION || 'default';
const options = {
...configValues.default,
//@ts-expect-error: Ignore TypeScript error for indexing configValues with a dynamic key
...configValues[configuration],
};
;
/**
* @type {import('@nx/next/plugins/with-nx').WithNxOptions}
**/
const nextConfig = {
nx: {
// Set this to true if you would like to use SVGR
// See: https://github.com/gregberge/svgr
svgr: false,
...options
},
};
const plugins = [
// Add more Next.js plugins to this list if needed.
withNx,
];
module.exports = composePlugins(...plugins)(nextConfig);
"
`);
});

it('should warm the user if the next config file is not support (.mjs)', () => {
const initConfig = `export default {}`;
const projectDetails = { projectName: 'mjs-config', root: 'mjs-config' };
tree.write(`${projectDetails.root}/next.config.mjs`, initConfig);

updateNextConfig(tree, '', projectDetails, mockLog);

expect(mockLog.addLog).toHaveBeenCalledWith({
executorName: '@nx/next:build',
log: 'The project mjs-config does not use a supported Next.js config file format. Only .js and .cjs files using "composePlugins" is supported. Leaving it as is.',
project: 'mjs-config',
});
});

it('should warm the user if composePlugins is not found in the next config file', () => {
// Example of a typical next.config.js file
const initConfig = `
module.exports = {
distDir: 'dist',
reactStrictMode: true,
};
`;
const projectDetails = {
projectName: 'no-compose-plugins',
root: 'no-compose-plugins',
};
tree.write(`${projectDetails.root}/next.config.js`, initConfig);

updateNextConfig(tree, '', projectDetails, mockLog);

expect(mockLog.addLog).toHaveBeenCalledWith({
executorName: '@nx/next:build',
log: 'The project no-compose-plugins does not use a supported Next.js config file format. Only .js and .cjs files using "composePlugins" is supported. Leaving it as is.',
project: 'no-compose-plugins',
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,40 @@ import { Tree } from '@nx/devkit';
import { findNextConfigPath } from './utils';
import { tsquery } from '@phenomnomnominal/tsquery';
import * as ts from 'typescript';
import { AggregatedLog } from '@nx/devkit/src/generators/plugin-migrations/aggregate-log-util';

export function updateNextConfig(
tree: Tree,
updatedConfigFileContents: string,
projectRoot: string
project: { projectName: string; root: string },
migrationLogs: AggregatedLog
) {
const nextConfigPath = findNextConfigPath(tree, projectRoot);
const nextConfigPath = findNextConfigPath(tree, project.root);
if (!nextConfigPath) {
migrationLogs.addLog({
project: project.projectName,
executorName: '@nx/next:build',
log: `The project ${project.projectName} does not use a supported Next.js config file format. Only .js and .cjs files using "composePlugins" is supported. Leaving it as is.`,
});
return;
}

const nextConfigContents = tree.read(nextConfigPath, 'utf-8');
let ast = tsquery.ast(nextConfigContents);

// Query to check for composePlugins in module.exports
const composePluginsQuery = `ExpressionStatement > BinaryExpression > CallExpression > CallExpression:has(Identifier[name=composePlugins])`;
const composePluginNode = tsquery(ast, composePluginsQuery)[0];

if (!composePluginNode) {
migrationLogs.addLog({
project: project.projectName,
executorName: '@nx/next:build',
log: `The project ${project.projectName} does not use a supported Next.js config file format. Only .js and .cjs files using "composePlugins" is supported. Leaving it as is.`,
});
return;
}

let lastRequireEndPosition = -1;

const findLastRequire = (node: ts.Node) => {
Expand Down Expand Up @@ -68,6 +88,7 @@ export function updateNextConfig(
}
return ts.visitEachChild(node, visit, context);
}

return ts.visitNode(rootNode, visit);
};

Expand Down

0 comments on commit 3bc5d50

Please sign in to comment.