Skip to content

Commit

Permalink
fix(nextjs): fixes for convert-to-inferred (#26735)
Browse files Browse the repository at this point in the history
…nferred

<!-- Please make sure you have read the submission guidelines before
posting an PR -->
<!--
https://github.com/nrwl/nx/blob/master/CONTRIBUTING.md#-submitting-a-pr
-->

<!-- Please make sure that your commit message follows our format -->
<!-- Example: `fix(nx): must begin with lowercase` -->

<!-- If this is a particularly complex change or feature addition, you
can request a dedicated Nx release for this pull request branch. Mention
someone from the Nx team or the `@nrwl/nx-pipelines-reviewers` and they
will confirm if the PR warrants its own release for testing purposes,
and generate it for you if appropriate. -->

## Current Behavior
<!-- This is the behavior we have today -->

## Expected Behavior
<!-- This is the behavior we should expect with the changes in this PR
-->

## Related Issue(s)
<!-- Please link the issue being fixed so it gets closed when this is
merged. -->

Fixes #

---------

Co-authored-by: Nicholas Cunningham <[email protected]>
  • Loading branch information
jaysoo and ndcunningham authored Jun 27, 2024
1 parent d90a735 commit c75e7ef
Show file tree
Hide file tree
Showing 4 changed files with 147 additions and 11 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -381,8 +381,10 @@ describe('convert-to-inferred', () => {
{},
{
build: {
debug: true,
profile: true,
experimentalAppOnly: true,
experimentalBuildMode: true,
experimentalBuildMode: 'generate',
},
}
);
Expand All @@ -391,10 +393,33 @@ describe('convert-to-inferred', () => {
await convertToInferred(tree, { project: project.name });

const projectConfig = readProjectConfiguration(tree, project.name);
expect(projectConfig.targets.build).toMatchObject({
options: {
args: ['--experimental-app-only', '--experimental-build-mode'],
},
expect(projectConfig.targets.build.options).toEqual({
args: [
'--debug',
'--profile',
'--experimental-app-only',
'--experimental-build-mode generate',
],
});
});

it('should not migrate options to CLI args if they are booleans and are false', async () => {
const project = createProject(
tree,
{},
{
build: {
debug: false,
profile: false,
experimentalAppOnly: false,
},
}
);
writeNextConfig(tree, project.root);

await convertToInferred(tree, { project: project.name });

const projectConfig = readProjectConfiguration(tree, project.name);
expect(projectConfig.targets.build.options).toBeUndefined();
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -157,17 +157,36 @@ function handlePropertiesFromTargetOptions(
delete options.watch;
}

if ('experimentalAppOnly' in options && options.experimentalAppOnly) {
options['args'] ??= [];
options['args'].push('--experimental-app-only');
if ('debug' in options) {
if (options.debug) {
options['args'] ??= [];
options['args'].push('--debug');
}
delete options.debug;
}

if ('profile' in options) {
if (options.profile) {
options['args'] ??= [];
options['args'].push('--profile');
}
delete options.profile;
}

if ('experimentalAppOnly' in options) {
if (options.experimentalAppOnly) {
options['args'] ??= [];
options['args'].push('--experimental-app-only');
}
delete options.experimentalAppOnly;
}

if ('experimentalBuildMode' in options && options.experimentalBuildMode) {
if ('experimentalBuildMode' in options) {
options['args'] ??= [];
options['args'].push(`--experimental-build-mode`);
options['args'].push(
`--experimental-build-mode ${options.experimentalBuildMode}`
);
delete options.experimentalBuildMode;
}

configValues[configuration] = configMap;
}
Original file line number Diff line number Diff line change
Expand Up @@ -145,4 +145,80 @@ describe('UpdateNextConfig', () => {
project: 'no-compose-plugins',
});
});

describe('Reserved variables', () => {
it('should warn the user if the next config file contains reserved variables', () => {
const initConfig = `
const options = {};
const configValues = {};
const configuration = {};
`;
const projectDetails = {
projectName: 'reserved-variables',
root: 'reserved-variables',
};
tree.write(`${projectDetails.root}/next.config.js`, initConfig);

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

expect(mockLog.addLog).toHaveBeenCalledWith({
executorName: '@nx/next:build',
log: "The project (reserved-variables) Next.js config contains reserved variables ('options', 'configValues' or 'configuration') which are generated during the migration. Leaving it as is.",
project: 'reserved-variables',
});
});

it('should warn the user if the next config file contains a reserved variable (option)', () => {
const initConfig = `const options = {};`;
const projectDetails = {
projectName: 'reserved-options',
root: 'reserved-options',
};
tree.write(`${projectDetails.root}/next.config.js`, initConfig);

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

expect(mockLog.addLog).toHaveBeenCalledWith({
executorName: '@nx/next:build',
log: "The project (reserved-options) Next.js config contains reserved variables ('options', 'configValues' or 'configuration') which are generated during the migration. Leaving it as is.",
project: 'reserved-options',
});
});

it('should warn the user if the next config file contains a reserved variable (configValues)', () => {
const initConfig = `const configValues = {};`;
const projectDetails = {
projectName: 'reserved-config-values',
root: 'reserved-config-values',
};

tree.write(`${projectDetails.root}/next.config.js`, initConfig);

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

expect(mockLog.addLog).toHaveBeenCalledWith({
executorName: '@nx/next:build',
log: "The project (reserved-config-values) Next.js config contains reserved variables ('options', 'configValues' or 'configuration') which are generated during the migration. Leaving it as is.",
project: 'reserved-config-values',
});
});

it('should warn the user if the next config file contains a reserved variable (configuration)', () => {
const initConfig = `const configuration = {};`;
const projectDetails = {
projectName: 'reserved-configuration-values',
root: 'reserved-configuration-values',
};

tree.write(`${projectDetails.root}/next.config.js`, initConfig);

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

expect(mockLog.addLog).toHaveBeenCalledWith({
executorName: '@nx/next:build',
log: "The project (reserved-configuration-values) Next.js config contains reserved variables ('options', 'configValues' or 'configuration') which are generated during the migration. Leaving it as is.",
project: 'reserved-configuration-values',
});
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,22 @@ export function updateNextConfig(
const nextConfigContents = tree.read(nextConfigPath, 'utf-8');
let ast = tsquery.ast(nextConfigContents);

const reservedVarQuery = `
VariableStatement > VariableDeclarationList > VariableDeclaration:has(Identifier[name=configValues]),
VariableStatement > VariableDeclarationList > VariableDeclaration:has(Identifier[name=configuration]),
VariableStatement > VariableDeclarationList > VariableDeclaration:has(Identifier[name=options])
`;

const matches = tsquery(ast, reservedVarQuery);
if (matches.length > 0) {
migrationLogs.addLog({
project: project.projectName,
executorName: '@nx/next:build',
log: `The project (${project.projectName}) Next.js config contains reserved variables ('options', 'configValues' or 'configuration') which are generated during the migration. Leaving it as is.`,
});
return;
}

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

0 comments on commit c75e7ef

Please sign in to comment.