fix(core): tweaks to nx init (#30002)
<!-- 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 #
This commit is contained in:
parent
672318de7f
commit
8b1cd482e3
@ -18,6 +18,7 @@ Nx.json configuration
|
||||
|
||||
### Properties
|
||||
|
||||
- [$schema](../../devkit/documents/NxJsonConfiguration#$schema): string
|
||||
- [affected](../../devkit/documents/NxJsonConfiguration#affected): NxAffectedConfig
|
||||
- [cacheDirectory](../../devkit/documents/NxJsonConfiguration#cachedirectory): string
|
||||
- [cli](../../devkit/documents/NxJsonConfiguration#cli): Object
|
||||
@ -47,6 +48,12 @@ Nx.json configuration
|
||||
|
||||
## Properties
|
||||
|
||||
### $schema
|
||||
|
||||
• `Optional` **$schema**: `string`
|
||||
|
||||
---
|
||||
|
||||
### affected
|
||||
|
||||
• `Optional` **affected**: [`NxAffectedConfig`](../../devkit/documents/NxAffectedConfig)
|
||||
|
||||
@ -16,6 +16,7 @@ use ProjectsConfigurations or NxJsonConfiguration
|
||||
|
||||
### Properties
|
||||
|
||||
- [$schema](../../devkit/documents/Workspace#$schema): string
|
||||
- [affected](../../devkit/documents/Workspace#affected): NxAffectedConfig
|
||||
- [cacheDirectory](../../devkit/documents/Workspace#cachedirectory): string
|
||||
- [cli](../../devkit/documents/Workspace#cli): Object
|
||||
@ -47,6 +48,16 @@ use ProjectsConfigurations or NxJsonConfiguration
|
||||
|
||||
## Properties
|
||||
|
||||
### $schema
|
||||
|
||||
• `Optional` **$schema**: `string`
|
||||
|
||||
#### Inherited from
|
||||
|
||||
[NxJsonConfiguration](../../devkit/documents/NxJsonConfiguration).[$schema](../../devkit/documents/NxJsonConfiguration#$schema)
|
||||
|
||||
---
|
||||
|
||||
### affected
|
||||
|
||||
• `Optional` **affected**: [`NxAffectedConfig`](../../devkit/documents/NxAffectedConfig)
|
||||
|
||||
@ -54,6 +54,7 @@ export const allowedProjectExtensions = [
|
||||
// There are some props in here (root) that angular already knows about,
|
||||
// but it doesn't hurt to have them in here as well to help static analysis.
|
||||
export const allowedWorkspaceExtensions = [
|
||||
'$schema',
|
||||
'implicitDependencies',
|
||||
'affected',
|
||||
'defaultBase',
|
||||
|
||||
@ -7,13 +7,19 @@ export const yargsInitCommand: CommandModule = {
|
||||
'Adds Nx to any type of workspace. It installs nx, creates an nx.json configuration file and optionally sets up remote caching. For more info, check https://nx.dev/recipes/adopting-nx.',
|
||||
builder: (yargs) => withInitOptions(yargs),
|
||||
handler: async (args: any) => {
|
||||
const useV2 = await isInitV2();
|
||||
if (useV2) {
|
||||
await require('./init-v2').initHandler(args);
|
||||
} else {
|
||||
await require('./init-v1').initHandler(args);
|
||||
try {
|
||||
const useV2 = await isInitV2();
|
||||
if (useV2) {
|
||||
await require('./init-v2').initHandler(args);
|
||||
} else {
|
||||
await require('./init-v1').initHandler(args);
|
||||
}
|
||||
process.exit(0);
|
||||
} catch {
|
||||
// Ensure the cursor is always restored just in case the user has bailed during interactive prompts
|
||||
process.stdout.write('\x1b[?25h');
|
||||
process.exit(1);
|
||||
}
|
||||
process.exit(0);
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
@ -0,0 +1,64 @@
|
||||
import { writeFileSync } from 'node:fs';
|
||||
import { join } from 'node:path';
|
||||
import { readJsonFile, writeJsonFile } from '../../../utils/fileutils';
|
||||
import { output } from '../../../utils/output';
|
||||
import { getPackageManagerCommand } from '../../../utils/package-manager';
|
||||
import { InitArgs } from '../init-v1';
|
||||
import {
|
||||
addDepsToPackageJson,
|
||||
createNxJsonFromTurboJson,
|
||||
runInstall,
|
||||
updateGitIgnore,
|
||||
} from './utils';
|
||||
|
||||
type Options = Pick<InitArgs, 'nxCloud' | 'interactive'>;
|
||||
|
||||
export async function addNxToTurborepo(_options: Options) {
|
||||
const repoRoot = process.cwd();
|
||||
|
||||
output.log({
|
||||
title: 'Initializing Nx based on your old Turborepo configuration',
|
||||
});
|
||||
|
||||
output.log({
|
||||
title: '💡 Did you know?',
|
||||
bodyLines: [
|
||||
'- Turborepo requires you to maintain all your common scripts like "build", "lint", "test" in all your packages, as well as their applicable cache inputs and outputs.',
|
||||
`- Nx is extensible and has plugins for the tools you use to infer all of this for you purely based on that tool's configuration file within your packages.`,
|
||||
'',
|
||||
' - E.g. the `@nx/vite` plugin will infer the "build" script based on the existence of a vite.config.js file.',
|
||||
' - Therefore with zero package level config, `nx build my-app` knows to run the `vite build` CLI directly, with all Nx cache inputs and outputs automatically inferred.',
|
||||
'',
|
||||
`NOTE: None of your existing package.json scripts will be modified as part of this initialization process, you can already use them as-is with Nx, but you can learn more about the benefits of Nx's inferred tasks at https://nx.dev/concepts/inferred-tasks`,
|
||||
],
|
||||
});
|
||||
|
||||
let nxJson = createNxJsonFromTurboJson(readJsonFile('turbo.json'));
|
||||
const nxJsonPath = join(repoRoot, 'nx.json');
|
||||
|
||||
// Turborepo workspaces usually have prettier installed, so try and match the formatting before writing the file
|
||||
try {
|
||||
const prettier = await import('prettier');
|
||||
const config = await prettier.resolveConfig(repoRoot);
|
||||
writeFileSync(
|
||||
nxJsonPath,
|
||||
// @ts-ignore - Always await prettier.format, in modern versions it's async
|
||||
await prettier.format(JSON.stringify(nxJson, null, 2), {
|
||||
...(config ?? {}),
|
||||
parser: 'json',
|
||||
})
|
||||
);
|
||||
} catch (err) {
|
||||
// Apply fallback JSON write
|
||||
writeJsonFile(nxJsonPath, nxJson);
|
||||
}
|
||||
|
||||
const pmc = getPackageManagerCommand();
|
||||
|
||||
updateGitIgnore(repoRoot);
|
||||
addDepsToPackageJson(repoRoot);
|
||||
|
||||
output.log({ title: '📦 Installing dependencies' });
|
||||
|
||||
runInstall(repoRoot, pmc);
|
||||
}
|
||||
@ -0,0 +1,46 @@
|
||||
import { execSync } from 'node:child_process';
|
||||
import { deduceDefaultBase as gitInitDefaultBase } from '../../../utils/default-base';
|
||||
|
||||
export function deduceDefaultBase() {
|
||||
try {
|
||||
execSync(`git rev-parse --verify main`, {
|
||||
stdio: ['ignore', 'ignore', 'ignore'],
|
||||
windowsHide: false,
|
||||
});
|
||||
return 'main';
|
||||
} catch {
|
||||
try {
|
||||
execSync(`git rev-parse --verify dev`, {
|
||||
stdio: ['ignore', 'ignore', 'ignore'],
|
||||
windowsHide: false,
|
||||
});
|
||||
return 'dev';
|
||||
} catch {
|
||||
try {
|
||||
execSync(`git rev-parse --verify develop`, {
|
||||
stdio: ['ignore', 'ignore', 'ignore'],
|
||||
windowsHide: false,
|
||||
});
|
||||
return 'develop';
|
||||
} catch {
|
||||
try {
|
||||
execSync(`git rev-parse --verify next`, {
|
||||
stdio: ['ignore', 'ignore', 'ignore'],
|
||||
windowsHide: false,
|
||||
});
|
||||
return 'next';
|
||||
} catch {
|
||||
try {
|
||||
execSync(`git rev-parse --verify master`, {
|
||||
stdio: ['ignore', 'ignore', 'ignore'],
|
||||
windowsHide: false,
|
||||
});
|
||||
return 'master';
|
||||
} catch {
|
||||
return gitInitDefaultBase();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
269
packages/nx/src/command-line/init/implementation/utils.spec.ts
Normal file
269
packages/nx/src/command-line/init/implementation/utils.spec.ts
Normal file
@ -0,0 +1,269 @@
|
||||
jest.mock('./deduce-default-base', () => ({
|
||||
deduceDefaultBase: jest.fn(() => 'main'),
|
||||
}));
|
||||
|
||||
import { NxJsonConfiguration } from '../../../config/nx-json';
|
||||
import { createNxJsonFromTurboJson } from './utils';
|
||||
|
||||
describe('utils', () => {
|
||||
describe('createNxJsonFromTurboJson', () => {
|
||||
test.each<{
|
||||
description: string;
|
||||
turbo: Record<string, any>;
|
||||
nx: NxJsonConfiguration;
|
||||
}>([
|
||||
{
|
||||
description: 'empty turbo.json',
|
||||
turbo: {},
|
||||
nx: {
|
||||
$schema: './node_modules/nx/schemas/nx-schema.json',
|
||||
},
|
||||
},
|
||||
{
|
||||
description: 'global dependencies',
|
||||
turbo: {
|
||||
globalDependencies: ['babel.config.json'],
|
||||
},
|
||||
nx: {
|
||||
$schema: './node_modules/nx/schemas/nx-schema.json',
|
||||
namedInputs: {
|
||||
sharedGlobals: ['{workspaceRoot}/babel.config.json'],
|
||||
default: ['{projectRoot}/**/*', 'sharedGlobals'],
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
description: 'global env variables',
|
||||
turbo: {
|
||||
globalEnv: ['NEXT_PUBLIC_API', 'NODE_ENV'],
|
||||
},
|
||||
nx: {
|
||||
$schema: './node_modules/nx/schemas/nx-schema.json',
|
||||
namedInputs: {
|
||||
sharedGlobals: [{ env: 'NEXT_PUBLIC_API' }, { env: 'NODE_ENV' }],
|
||||
default: ['{projectRoot}/**/*', 'sharedGlobals'],
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
description: 'basic task configuration with dependsOn',
|
||||
turbo: {
|
||||
tasks: {
|
||||
build: {
|
||||
dependsOn: ['^build'],
|
||||
},
|
||||
},
|
||||
},
|
||||
nx: {
|
||||
$schema: './node_modules/nx/schemas/nx-schema.json',
|
||||
targetDefaults: {
|
||||
build: {
|
||||
dependsOn: ['^build'],
|
||||
cache: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
description: 'task configuration with outputs',
|
||||
turbo: {
|
||||
tasks: {
|
||||
build: {
|
||||
outputs: ['dist/**', '.next/**'],
|
||||
},
|
||||
},
|
||||
},
|
||||
nx: {
|
||||
$schema: './node_modules/nx/schemas/nx-schema.json',
|
||||
targetDefaults: {
|
||||
build: {
|
||||
outputs: ['{projectRoot}/dist/**', '{projectRoot}/.next/**'],
|
||||
cache: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
description: 'task configuration with inputs',
|
||||
turbo: {
|
||||
tasks: {
|
||||
build: {
|
||||
inputs: ['src/**/*.tsx', 'test/**/*.tsx'],
|
||||
},
|
||||
},
|
||||
},
|
||||
nx: {
|
||||
$schema: './node_modules/nx/schemas/nx-schema.json',
|
||||
targetDefaults: {
|
||||
build: {
|
||||
inputs: [
|
||||
'{projectRoot}/src/**/*.tsx',
|
||||
'{projectRoot}/test/**/*.tsx',
|
||||
],
|
||||
cache: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
description: 'cache configuration',
|
||||
turbo: {
|
||||
tasks: {
|
||||
build: {
|
||||
cache: true,
|
||||
},
|
||||
dev: {
|
||||
cache: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
nx: {
|
||||
$schema: './node_modules/nx/schemas/nx-schema.json',
|
||||
targetDefaults: {
|
||||
build: {
|
||||
cache: true,
|
||||
},
|
||||
dev: {
|
||||
cache: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
description: 'cache directory configuration',
|
||||
turbo: {
|
||||
cacheDir: './node_modules/.cache/turbo',
|
||||
},
|
||||
nx: {
|
||||
$schema: './node_modules/nx/schemas/nx-schema.json',
|
||||
cacheDirectory: '.nx/cache',
|
||||
},
|
||||
},
|
||||
{
|
||||
description: 'skip project-specific task configurations',
|
||||
turbo: {
|
||||
tasks: {
|
||||
build: {
|
||||
dependsOn: ['^build'],
|
||||
},
|
||||
'docs#build': {
|
||||
dependsOn: ['^build'],
|
||||
outputs: ['www/**'],
|
||||
},
|
||||
},
|
||||
},
|
||||
nx: {
|
||||
$schema: './node_modules/nx/schemas/nx-schema.json',
|
||||
targetDefaults: {
|
||||
build: {
|
||||
dependsOn: ['^build'],
|
||||
cache: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
description: 'complex configuration combining multiple features',
|
||||
turbo: {
|
||||
globalDependencies: ['babel.config.json'],
|
||||
globalEnv: ['NODE_ENV'],
|
||||
cacheDir: './node_modules/.cache/turbo',
|
||||
tasks: {
|
||||
build: {
|
||||
dependsOn: ['^build'],
|
||||
outputs: ['dist/**'],
|
||||
inputs: ['src/**/*'],
|
||||
cache: true,
|
||||
},
|
||||
test: {
|
||||
dependsOn: ['build'],
|
||||
outputs: ['coverage/**'],
|
||||
cache: true,
|
||||
},
|
||||
dev: {
|
||||
cache: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
nx: {
|
||||
$schema: './node_modules/nx/schemas/nx-schema.json',
|
||||
namedInputs: {
|
||||
sharedGlobals: [
|
||||
'{workspaceRoot}/babel.config.json',
|
||||
{ env: 'NODE_ENV' },
|
||||
],
|
||||
default: ['{projectRoot}/**/*', 'sharedGlobals'],
|
||||
},
|
||||
cacheDirectory: '.nx/cache',
|
||||
targetDefaults: {
|
||||
build: {
|
||||
dependsOn: ['^build'],
|
||||
outputs: ['{projectRoot}/dist/**'],
|
||||
inputs: ['{projectRoot}/src/**/*'],
|
||||
cache: true,
|
||||
},
|
||||
test: {
|
||||
dependsOn: ['build'],
|
||||
outputs: ['{projectRoot}/coverage/**'],
|
||||
cache: true,
|
||||
},
|
||||
dev: {
|
||||
cache: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
description: 'turbo starter with $TURBO_DEFAULT$',
|
||||
turbo: {
|
||||
$schema: 'https://turbo.build/schema.json',
|
||||
ui: 'tui',
|
||||
tasks: {
|
||||
build: {
|
||||
dependsOn: ['^build'],
|
||||
inputs: ['$TURBO_DEFAULT$', '.env*'],
|
||||
outputs: ['.next/**', '!.next/cache/**'],
|
||||
},
|
||||
lint: {
|
||||
dependsOn: ['^lint'],
|
||||
},
|
||||
'check-types': {
|
||||
dependsOn: ['^check-types'],
|
||||
},
|
||||
dev: {
|
||||
cache: false,
|
||||
persistent: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
nx: {
|
||||
$schema: './node_modules/nx/schemas/nx-schema.json',
|
||||
targetDefaults: {
|
||||
build: {
|
||||
dependsOn: ['^build'],
|
||||
inputs: ['{projectRoot}/**/*', '{projectRoot}/.env*'],
|
||||
outputs: [
|
||||
'{projectRoot}/.next/**',
|
||||
'!{projectRoot}/.next/cache/**',
|
||||
],
|
||||
cache: true,
|
||||
},
|
||||
lint: {
|
||||
dependsOn: ['^lint'],
|
||||
cache: true,
|
||||
},
|
||||
'check-types': {
|
||||
dependsOn: ['^check-types'],
|
||||
cache: true,
|
||||
},
|
||||
dev: {
|
||||
cache: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
])('$description', ({ turbo, nx }) => {
|
||||
expect(createNxJsonFromTurboJson(turbo)).toEqual(nx);
|
||||
});
|
||||
});
|
||||
});
|
||||
@ -19,7 +19,7 @@ import { existsSync, readFileSync, writeFileSync } from 'fs';
|
||||
import { printSuccessMessage } from '../../../nx-cloud/generators/connect-to-nx-cloud/connect-to-nx-cloud';
|
||||
import { repoUsesGithub } from '../../../nx-cloud/utilities/url-shorten';
|
||||
import { connectWorkspaceToCloud } from '../../connect/connect-to-nx-cloud';
|
||||
import { deduceDefaultBase as gitInitDefaultBase } from '../../../utils/default-base';
|
||||
import { deduceDefaultBase } from './deduce-default-base';
|
||||
|
||||
export function createNxJsonFile(
|
||||
repoRoot: string,
|
||||
@ -61,52 +61,127 @@ export function createNxJsonFile(
|
||||
delete nxJson.targetDefaults;
|
||||
}
|
||||
|
||||
nxJson.defaultBase ??= deduceDefaultBase();
|
||||
const defaultBase = deduceDefaultBase();
|
||||
// Do not add defaultBase if it is inferred to be the Nx default value of main
|
||||
if (defaultBase !== 'main') {
|
||||
nxJson.defaultBase ??= defaultBase;
|
||||
}
|
||||
writeJsonFile(nxJsonPath, nxJson);
|
||||
}
|
||||
|
||||
function deduceDefaultBase() {
|
||||
try {
|
||||
execSync(`git rev-parse --verify main`, {
|
||||
stdio: ['ignore', 'ignore', 'ignore'],
|
||||
windowsHide: false,
|
||||
});
|
||||
return 'main';
|
||||
} catch {
|
||||
try {
|
||||
execSync(`git rev-parse --verify dev`, {
|
||||
stdio: ['ignore', 'ignore', 'ignore'],
|
||||
windowsHide: false,
|
||||
});
|
||||
return 'dev';
|
||||
} catch {
|
||||
try {
|
||||
execSync(`git rev-parse --verify develop`, {
|
||||
stdio: ['ignore', 'ignore', 'ignore'],
|
||||
windowsHide: false,
|
||||
});
|
||||
return 'develop';
|
||||
} catch {
|
||||
try {
|
||||
execSync(`git rev-parse --verify next`, {
|
||||
stdio: ['ignore', 'ignore', 'ignore'],
|
||||
windowsHide: false,
|
||||
});
|
||||
return 'next';
|
||||
} catch {
|
||||
try {
|
||||
execSync(`git rev-parse --verify master`, {
|
||||
stdio: ['ignore', 'ignore', 'ignore'],
|
||||
windowsHide: false,
|
||||
});
|
||||
return 'master';
|
||||
} catch {
|
||||
return gitInitDefaultBase();
|
||||
}
|
||||
}
|
||||
}
|
||||
export function createNxJsonFromTurboJson(
|
||||
turboJson: Record<string, any>
|
||||
): NxJsonConfiguration {
|
||||
const nxJson: NxJsonConfiguration = {
|
||||
$schema: './node_modules/nx/schemas/nx-schema.json',
|
||||
};
|
||||
|
||||
// Handle global dependencies
|
||||
if (turboJson.globalDependencies?.length > 0) {
|
||||
nxJson.namedInputs = {
|
||||
sharedGlobals: turboJson.globalDependencies.map(
|
||||
(dep) => `{workspaceRoot}/${dep}`
|
||||
),
|
||||
default: ['{projectRoot}/**/*', 'sharedGlobals'],
|
||||
};
|
||||
}
|
||||
|
||||
// Handle global env vars
|
||||
if (turboJson.globalEnv?.length > 0) {
|
||||
nxJson.namedInputs = nxJson.namedInputs || {};
|
||||
nxJson.namedInputs.sharedGlobals = nxJson.namedInputs.sharedGlobals || [];
|
||||
nxJson.namedInputs.sharedGlobals.push(
|
||||
...turboJson.globalEnv.map((env) => ({ env }))
|
||||
);
|
||||
nxJson.namedInputs.default = nxJson.namedInputs.default || [];
|
||||
if (!nxJson.namedInputs.default.includes('{projectRoot}/**/*')) {
|
||||
nxJson.namedInputs.default.push('{projectRoot}/**/*');
|
||||
}
|
||||
if (!nxJson.namedInputs.default.includes('sharedGlobals')) {
|
||||
nxJson.namedInputs.default.push('sharedGlobals');
|
||||
}
|
||||
}
|
||||
|
||||
// Handle task configurations
|
||||
if (turboJson.tasks) {
|
||||
nxJson.targetDefaults = {};
|
||||
|
||||
for (const [taskName, taskConfig] of Object.entries(turboJson.tasks)) {
|
||||
// Skip project-specific tasks (containing #)
|
||||
if (taskName.includes('#')) continue;
|
||||
|
||||
const config = taskConfig as any;
|
||||
nxJson.targetDefaults[taskName] = {};
|
||||
|
||||
// Handle dependsOn
|
||||
if (config.dependsOn?.length > 0) {
|
||||
nxJson.targetDefaults[taskName].dependsOn = config.dependsOn;
|
||||
}
|
||||
|
||||
// Handle inputs
|
||||
if (config.inputs?.length > 0) {
|
||||
nxJson.targetDefaults[taskName].inputs = config.inputs
|
||||
.map((input) => {
|
||||
if (input === '$TURBO_DEFAULT$') {
|
||||
return '{projectRoot}/**/*';
|
||||
}
|
||||
// Don't add projectRoot if it's already there or if it's an env var
|
||||
if (
|
||||
input.startsWith('{projectRoot}/') ||
|
||||
input.startsWith('{env.') ||
|
||||
input.startsWith('$')
|
||||
)
|
||||
return input;
|
||||
return `{projectRoot}/${input}`;
|
||||
})
|
||||
.map((input) => {
|
||||
// Don't add projectRoot if it's already there or if it's an env var
|
||||
if (
|
||||
input.startsWith('{projectRoot}/') ||
|
||||
input.startsWith('{env.') ||
|
||||
input.startsWith('$')
|
||||
)
|
||||
return input;
|
||||
return `{projectRoot}/${input}`;
|
||||
});
|
||||
}
|
||||
|
||||
// Handle outputs
|
||||
if (config.outputs?.length > 0) {
|
||||
nxJson.targetDefaults[taskName].outputs = config.outputs.map(
|
||||
(output) => {
|
||||
// Don't add projectRoot if it's already there
|
||||
if (output.startsWith('{projectRoot}/')) return output;
|
||||
// Handle negated patterns by adding projectRoot after the !
|
||||
if (output.startsWith('!')) {
|
||||
return `!{projectRoot}/${output.slice(1)}`;
|
||||
}
|
||||
return `{projectRoot}/${output}`;
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
// Handle cache setting - true by default in Turbo
|
||||
nxJson.targetDefaults[taskName].cache = config.cache !== false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The fact that cacheDir was in use suggests the user had a reason for deviating from the default.
|
||||
* We can't know what that reason was, nor if it would still be applicable in Nx, but we can at least
|
||||
* improve discoverability of the relevant Nx option by explicitly including it with its default value.
|
||||
*/
|
||||
if (turboJson.cacheDir) {
|
||||
nxJson.cacheDirectory = '.nx/cache';
|
||||
}
|
||||
|
||||
const defaultBase = deduceDefaultBase();
|
||||
// Do not add defaultBase if it is inferred to be the Nx default value of main
|
||||
if (defaultBase !== 'main') {
|
||||
nxJson.defaultBase ??= defaultBase;
|
||||
}
|
||||
|
||||
return nxJson;
|
||||
}
|
||||
|
||||
export function addDepsToPackageJson(
|
||||
@ -168,6 +243,7 @@ export async function initCloud(
|
||||
| 'nx-init-monorepo'
|
||||
| 'nx-init-nest'
|
||||
| 'nx-init-npm-repo'
|
||||
| 'nx-init-turborepo'
|
||||
) {
|
||||
const token = await connectWorkspaceToCloud({
|
||||
installationSource,
|
||||
|
||||
@ -1,13 +1,26 @@
|
||||
import { existsSync } from 'fs';
|
||||
|
||||
import { PackageJson } from '../../utils/package-json';
|
||||
import { prompt } from 'enquirer';
|
||||
import { prerelease } from 'semver';
|
||||
import { output } from '../../utils/output';
|
||||
import { getPackageManagerCommand } from '../../utils/package-manager';
|
||||
import { generateDotNxSetup } from './implementation/dot-nx/add-nx-scripts';
|
||||
import { NxJsonConfiguration, readNxJson } from '../../config/nx-json';
|
||||
import { runNxSync } from '../../utils/child-process';
|
||||
import { readJsonFile } from '../../utils/fileutils';
|
||||
import { getPackageNameFromImportPath } from '../../utils/get-package-name-from-import-path';
|
||||
import { output } from '../../utils/output';
|
||||
import { PackageJson } from '../../utils/package-json';
|
||||
import { getPackageManagerCommand } from '../../utils/package-manager';
|
||||
import { nxVersion } from '../../utils/versions';
|
||||
import { globWithWorkspaceContextSync } from '../../utils/workspace-context';
|
||||
import { connectExistingRepoToNxCloudPrompt } from '../connect/connect-to-nx-cloud';
|
||||
import {
|
||||
configurePlugins,
|
||||
runPackageManagerInstallPlugins,
|
||||
} from './configure-plugins';
|
||||
import { addNxToMonorepo } from './implementation/add-nx-to-monorepo';
|
||||
import { addNxToNpmRepo } from './implementation/add-nx-to-npm-repo';
|
||||
import { addNxToTurborepo } from './implementation/add-nx-to-turborepo';
|
||||
import { addNxToAngularCliRepo } from './implementation/angular';
|
||||
import { generateDotNxSetup } from './implementation/dot-nx/add-nx-scripts';
|
||||
import {
|
||||
createNxJsonFile,
|
||||
initCloud,
|
||||
@ -15,18 +28,6 @@ import {
|
||||
printFinalMessage,
|
||||
updateGitIgnore,
|
||||
} from './implementation/utils';
|
||||
import { prompt } from 'enquirer';
|
||||
import { addNxToAngularCliRepo } from './implementation/angular';
|
||||
import { globWithWorkspaceContextSync } from '../../utils/workspace-context';
|
||||
import { connectExistingRepoToNxCloudPrompt } from '../connect/connect-to-nx-cloud';
|
||||
import { addNxToNpmRepo } from './implementation/add-nx-to-npm-repo';
|
||||
import { addNxToMonorepo } from './implementation/add-nx-to-monorepo';
|
||||
import { NxJsonConfiguration, readNxJson } from '../../config/nx-json';
|
||||
import { getPackageNameFromImportPath } from '../../utils/get-package-name-from-import-path';
|
||||
import {
|
||||
configurePlugins,
|
||||
runPackageManagerInstallPlugins,
|
||||
} from './configure-plugins';
|
||||
|
||||
export interface InitArgs {
|
||||
interactive: boolean;
|
||||
@ -82,7 +83,32 @@ export async function initHandler(options: InitArgs): Promise<void> {
|
||||
}
|
||||
|
||||
const packageJson: PackageJson = readJsonFile('package.json');
|
||||
if (isMonorepo(packageJson)) {
|
||||
const _isTurborepo = existsSync('turbo.json');
|
||||
const _isMonorepo = isMonorepo(packageJson);
|
||||
|
||||
const learnMoreLink = _isTurborepo
|
||||
? 'https://nx.dev/recipes/adopting-nx/from-turborepo'
|
||||
: _isMonorepo
|
||||
? 'https://nx.dev/getting-started/tutorials/npm-workspaces-tutorial'
|
||||
: 'https://nx.dev/recipes/adopting-nx/adding-to-existing-project';
|
||||
|
||||
/**
|
||||
* Turborepo users must have set up individual scripts already, and we keep the transition as minimal as possible.
|
||||
* We log a message during the conversion process in addNxToTurborepo about how they can learn more about the power
|
||||
* of Nx plugins and how it would allow them to infer all the relevant scripts automatically, including all cache
|
||||
* inputs and outputs.
|
||||
*/
|
||||
if (_isTurborepo) {
|
||||
await addNxToTurborepo({
|
||||
interactive: options.interactive,
|
||||
});
|
||||
printFinalMessage({
|
||||
learnMoreLink,
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
if (_isMonorepo) {
|
||||
await addNxToMonorepo({
|
||||
interactive: options.interactive,
|
||||
nxCloud: false,
|
||||
@ -93,9 +119,7 @@ export async function initHandler(options: InitArgs): Promise<void> {
|
||||
nxCloud: false,
|
||||
});
|
||||
}
|
||||
const learnMoreLink = isMonorepo(packageJson)
|
||||
? 'https://nx.dev/getting-started/tutorials/npm-workspaces-tutorial'
|
||||
: 'https://nx.dev/recipes/adopting-nx/adding-to-existing-project';
|
||||
|
||||
const useNxCloud =
|
||||
options.nxCloud ??
|
||||
(options.interactive ? await connectExistingRepoToNxCloudPrompt() : false);
|
||||
|
||||
@ -361,6 +361,7 @@ export interface NxSyncConfiguration {
|
||||
* @note: when adding properties here add them to `allowedWorkspaceExtensions` in adapter/compat.ts
|
||||
*/
|
||||
export interface NxJsonConfiguration<T = '*' | string[]> {
|
||||
$schema?: string;
|
||||
/**
|
||||
* Optional (additional) Nx.json configuration file which becomes a base for this one
|
||||
*/
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user