fix(misc): register plugins correctly in migration generators (#26670)
<!-- 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 NXP-816 --> Fixes #
This commit is contained in:
parent
8872ca5c8f
commit
c936f864b8
@ -495,33 +495,46 @@ describe('Cypress - Convert Executors To Plugin', () => {
|
|||||||
|
|
||||||
// nx.json modifications
|
// nx.json modifications
|
||||||
const nxJsonPlugins = readNxJson(tree).plugins;
|
const nxJsonPlugins = readNxJson(tree).plugins;
|
||||||
const addedTestCypressPlugin = nxJsonPlugins.find((plugin) => {
|
const addedCypressPlugins = nxJsonPlugins.filter(
|
||||||
if (
|
(plugin) =>
|
||||||
typeof plugin !== 'string' &&
|
typeof plugin !== 'string' && plugin.plugin === '@nx/cypress/plugin'
|
||||||
plugin.plugin === '@nx/cypress/plugin' &&
|
);
|
||||||
plugin.include?.length === 2
|
expect(addedCypressPlugins).toMatchInlineSnapshot(`
|
||||||
) {
|
[
|
||||||
return true;
|
{
|
||||||
}
|
"options": {
|
||||||
});
|
"ciTargetName": "e2e-ci",
|
||||||
expect(addedTestCypressPlugin).toBeTruthy();
|
"targetName": "e2e",
|
||||||
expect(
|
},
|
||||||
(addedTestCypressPlugin as ExpandedPluginConfiguration).include
|
"plugin": "@nx/cypress/plugin",
|
||||||
).toEqual(['myapp-e2e/**/*', 'second/**/*']);
|
},
|
||||||
|
{
|
||||||
const addedIntegrationCypressPlugin = nxJsonPlugins.find((plugin) => {
|
"include": [
|
||||||
if (
|
"myapp-e2e/**/*",
|
||||||
typeof plugin !== 'string' &&
|
"second/**/*",
|
||||||
plugin.plugin === '@nx/cypress/plugin' &&
|
],
|
||||||
plugin.include?.length === 1
|
"options": {
|
||||||
) {
|
"ciTargetName": "e2e-ci",
|
||||||
return true;
|
"componentTestingTargetName": "component-test",
|
||||||
}
|
"openTargetName": "open-cypress",
|
||||||
});
|
"targetName": "test",
|
||||||
expect(addedIntegrationCypressPlugin).toBeTruthy();
|
},
|
||||||
expect(
|
"plugin": "@nx/cypress/plugin",
|
||||||
(addedIntegrationCypressPlugin as ExpandedPluginConfiguration).include
|
},
|
||||||
).toEqual(['third/**/*']);
|
{
|
||||||
|
"include": [
|
||||||
|
"third/**/*",
|
||||||
|
],
|
||||||
|
"options": {
|
||||||
|
"ciTargetName": "e2e-ci",
|
||||||
|
"componentTestingTargetName": "component-test",
|
||||||
|
"openTargetName": "open-cypress",
|
||||||
|
"targetName": "integration",
|
||||||
|
},
|
||||||
|
"plugin": "@nx/cypress/plugin",
|
||||||
|
},
|
||||||
|
]
|
||||||
|
`);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should keep Cypress options in project.json', async () => {
|
it('should keep Cypress options in project.json', async () => {
|
||||||
|
|||||||
@ -4,16 +4,16 @@ import {
|
|||||||
type TargetConfiguration,
|
type TargetConfiguration,
|
||||||
type Tree,
|
type Tree,
|
||||||
} from '@nx/devkit';
|
} from '@nx/devkit';
|
||||||
import { migrateExecutorToPlugin } from '@nx/devkit/src/generators/plugin-migrations/executor-to-plugin-migrator';
|
import { migrateProjectExecutorsToPlugin } from '@nx/devkit/src/generators/plugin-migrations/executor-to-plugin-migrator';
|
||||||
import { createNodesV2 } from '../../plugins/plugin';
|
|
||||||
import { targetOptionsToCliMap } from './lib/target-options-map';
|
|
||||||
import { upsertBaseUrl } from './lib/upsert-baseUrl';
|
|
||||||
import { addDevServerTargetToConfig } from './lib/add-dev-server-target-to-config';
|
|
||||||
import { addExcludeSpecPattern } from './lib/add-exclude-spec-pattern';
|
|
||||||
import {
|
import {
|
||||||
processTargetOutputs,
|
processTargetOutputs,
|
||||||
toProjectRelativePath,
|
toProjectRelativePath,
|
||||||
} from '@nx/devkit/src/generators/plugin-migrations/plugin-migration-utils';
|
} from '@nx/devkit/src/generators/plugin-migrations/plugin-migration-utils';
|
||||||
|
import { createNodesV2, type CypressPluginOptions } from '../../plugins/plugin';
|
||||||
|
import { addDevServerTargetToConfig } from './lib/add-dev-server-target-to-config';
|
||||||
|
import { addExcludeSpecPattern } from './lib/add-exclude-spec-pattern';
|
||||||
|
import { targetOptionsToCliMap } from './lib/target-options-map';
|
||||||
|
import { upsertBaseUrl } from './lib/upsert-baseUrl';
|
||||||
|
|
||||||
interface Schema {
|
interface Schema {
|
||||||
project?: string;
|
project?: string;
|
||||||
@ -23,38 +23,29 @@ interface Schema {
|
|||||||
|
|
||||||
export async function convertToInferred(tree: Tree, options: Schema) {
|
export async function convertToInferred(tree: Tree, options: Schema) {
|
||||||
const projectGraph = await createProjectGraphAsync();
|
const projectGraph = await createProjectGraphAsync();
|
||||||
const migratedProjectsModern = await migrateExecutorToPlugin(
|
|
||||||
tree,
|
|
||||||
projectGraph,
|
|
||||||
'@nx/cypress:cypress',
|
|
||||||
'@nx/cypress/plugin',
|
|
||||||
(targetName) => ({
|
|
||||||
targetName,
|
|
||||||
ciTargetName: 'e2e-ci',
|
|
||||||
}),
|
|
||||||
postTargetTransformer,
|
|
||||||
createNodesV2,
|
|
||||||
options.project
|
|
||||||
);
|
|
||||||
|
|
||||||
const migratedProjectsLegacy = await migrateExecutorToPlugin(
|
|
||||||
tree,
|
|
||||||
projectGraph,
|
|
||||||
'@nrwl/cypress:cypress',
|
|
||||||
'@nx/cypress/plugin',
|
|
||||||
(targetName) => ({
|
|
||||||
targetName,
|
|
||||||
ciTargetName: 'e2e-ci',
|
|
||||||
}),
|
|
||||||
postTargetTransformer,
|
|
||||||
createNodesV2,
|
|
||||||
options.project
|
|
||||||
);
|
|
||||||
|
|
||||||
const migratedProjects =
|
const migratedProjects =
|
||||||
migratedProjectsModern.size + migratedProjectsLegacy.size;
|
await migrateProjectExecutorsToPlugin<CypressPluginOptions>(
|
||||||
|
tree,
|
||||||
|
projectGraph,
|
||||||
|
'@nx/cypress/plugin',
|
||||||
|
createNodesV2,
|
||||||
|
{
|
||||||
|
targetName: 'cypress',
|
||||||
|
ciTargetName: 'e2e-ci',
|
||||||
|
componentTestingTargetName: 'component-test',
|
||||||
|
openTargetName: 'open-cypress',
|
||||||
|
},
|
||||||
|
[
|
||||||
|
{
|
||||||
|
executors: ['@nx/cypress:cypress', '@nrwl/cypress:cypress'],
|
||||||
|
postTargetTransformer,
|
||||||
|
targetPluginOptionMapper: (targetName) => ({ targetName }),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
options.project
|
||||||
|
);
|
||||||
|
|
||||||
if (migratedProjects === 0) {
|
if (migratedProjects.size === 0) {
|
||||||
throw new Error('Could not find any targets to migrate.');
|
throw new Error('Could not find any targets to migrate.');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,36 +1,32 @@
|
|||||||
import type { RunCommandsOptions } from 'nx/src/executors/run-commands/run-commands.impl';
|
|
||||||
|
|
||||||
import { minimatch } from 'minimatch';
|
import { minimatch } from 'minimatch';
|
||||||
import { deepStrictEqual } from 'node:assert';
|
import { deepStrictEqual } from 'node:assert';
|
||||||
|
|
||||||
import { forEachExecutorOptions } from '../executor-options-utils';
|
|
||||||
import { deleteMatchingProperties } from './plugin-migration-utils';
|
|
||||||
|
|
||||||
import {
|
|
||||||
readNxJson,
|
|
||||||
updateNxJson,
|
|
||||||
updateProjectConfiguration,
|
|
||||||
readProjectConfiguration,
|
|
||||||
ProjectGraph,
|
|
||||||
ExpandedPluginConfiguration,
|
|
||||||
NxJsonConfiguration,
|
|
||||||
TargetConfiguration,
|
|
||||||
Tree,
|
|
||||||
CreateNodes,
|
|
||||||
CreateNodesV2,
|
|
||||||
} from 'nx/src/devkit-exports';
|
|
||||||
|
|
||||||
import {
|
|
||||||
mergeTargetConfigurations,
|
|
||||||
retrieveProjectConfigurations,
|
|
||||||
LoadedNxPlugin,
|
|
||||||
ProjectConfigurationsError,
|
|
||||||
} from 'nx/src/devkit-internals';
|
|
||||||
import type { ConfigurationResult } from 'nx/src/project-graph/utils/project-configuration-utils';
|
|
||||||
import type {
|
import type {
|
||||||
InputDefinition,
|
InputDefinition,
|
||||||
ProjectConfiguration,
|
ProjectConfiguration,
|
||||||
} from 'nx/src/config/workspace-json-project-json';
|
} from 'nx/src/config/workspace-json-project-json';
|
||||||
|
import {
|
||||||
|
readNxJson,
|
||||||
|
readProjectConfiguration,
|
||||||
|
updateNxJson,
|
||||||
|
updateProjectConfiguration,
|
||||||
|
type CreateNodes,
|
||||||
|
type CreateNodesV2,
|
||||||
|
type ExpandedPluginConfiguration,
|
||||||
|
type NxJsonConfiguration,
|
||||||
|
type ProjectGraph,
|
||||||
|
type TargetConfiguration,
|
||||||
|
type Tree,
|
||||||
|
} from 'nx/src/devkit-exports';
|
||||||
|
import {
|
||||||
|
LoadedNxPlugin,
|
||||||
|
ProjectConfigurationsError,
|
||||||
|
mergeTargetConfigurations,
|
||||||
|
retrieveProjectConfigurations,
|
||||||
|
} from 'nx/src/devkit-internals';
|
||||||
|
import type { RunCommandsOptions } from 'nx/src/executors/run-commands/run-commands.impl';
|
||||||
|
import type { ConfigurationResult } from 'nx/src/project-graph/utils/project-configuration-utils';
|
||||||
|
import { forEachExecutorOptions } from '../executor-options-utils';
|
||||||
|
import { deleteMatchingProperties } from './plugin-migration-utils';
|
||||||
|
|
||||||
type PluginOptionsBuilder<T> = (targetName: string) => T;
|
type PluginOptionsBuilder<T> = (targetName: string) => T;
|
||||||
type PostTargetTransformer = (
|
type PostTargetTransformer = (
|
||||||
@ -100,7 +96,6 @@ class ExecutorToPluginMigrator<T> {
|
|||||||
for (const targetName of this.#targetAndProjectsToMigrate.keys()) {
|
for (const targetName of this.#targetAndProjectsToMigrate.keys()) {
|
||||||
await this.#migrateTarget(targetName);
|
await this.#migrateTarget(targetName);
|
||||||
}
|
}
|
||||||
await this.#addPlugins();
|
|
||||||
}
|
}
|
||||||
return this.#targetAndProjectsToMigrate;
|
return this.#targetAndProjectsToMigrate;
|
||||||
}
|
}
|
||||||
@ -235,91 +230,6 @@ class ExecutorToPluginMigrator<T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async #pluginRequiresIncludes(
|
|
||||||
targetName: string,
|
|
||||||
plugin: ExpandedPluginConfiguration<T>
|
|
||||||
) {
|
|
||||||
const loadedPlugin = new LoadedNxPlugin(
|
|
||||||
{
|
|
||||||
createNodesV2: this.#createNodesV2,
|
|
||||||
createNodes: this.#createNodes,
|
|
||||||
name: this.#pluginPath,
|
|
||||||
},
|
|
||||||
plugin
|
|
||||||
);
|
|
||||||
|
|
||||||
const originalResults = this.#createNodesResultsForTargets.get(targetName);
|
|
||||||
|
|
||||||
let resultsWithIncludes: ConfigurationResult;
|
|
||||||
try {
|
|
||||||
resultsWithIncludes = await retrieveProjectConfigurations(
|
|
||||||
[loadedPlugin],
|
|
||||||
this.tree.root,
|
|
||||||
this.#nxJson
|
|
||||||
);
|
|
||||||
} catch (e) {
|
|
||||||
if (e instanceof ProjectConfigurationsError) {
|
|
||||||
resultsWithIncludes = e.partialProjectConfigurationsResult;
|
|
||||||
} else {
|
|
||||||
throw e;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return !deepEqual(originalResults, resultsWithIncludes);
|
|
||||||
}
|
|
||||||
|
|
||||||
async #addPlugins() {
|
|
||||||
for (const [targetName, plugin] of this.#pluginToAddForTarget.entries()) {
|
|
||||||
const pluginOptions = this.#pluginOptionsBuilder(targetName);
|
|
||||||
|
|
||||||
const existingPlugin = this.#nxJson.plugins.find(
|
|
||||||
(plugin: ExpandedPluginConfiguration<T>) => {
|
|
||||||
if (
|
|
||||||
typeof plugin === 'string' ||
|
|
||||||
plugin.plugin !== this.#pluginPath
|
|
||||||
) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (const key in plugin.options) {
|
|
||||||
if (plugin.options[key] !== pluginOptions[key]) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
) as ExpandedPluginConfiguration<T>;
|
|
||||||
|
|
||||||
if (existingPlugin?.include) {
|
|
||||||
// Add to the existing plugin includes
|
|
||||||
existingPlugin.include = existingPlugin.include.concat(
|
|
||||||
// Any include that is in the new plugin's include list
|
|
||||||
plugin.include.filter(
|
|
||||||
(projectPath) =>
|
|
||||||
// And is not already covered by the existing plugin's include list
|
|
||||||
!existingPlugin.include.some((pluginIncludes) =>
|
|
||||||
minimatch(projectPath, pluginIncludes, { dot: true })
|
|
||||||
)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
if (!(await this.#pluginRequiresIncludes(targetName, existingPlugin))) {
|
|
||||||
delete existingPlugin.include;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!existingPlugin) {
|
|
||||||
if (!(await this.#pluginRequiresIncludes(targetName, plugin))) {
|
|
||||||
plugin.include = undefined;
|
|
||||||
}
|
|
||||||
this.#nxJson.plugins.push(plugin);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
updateNxJson(this.tree, this.#nxJson);
|
|
||||||
}
|
|
||||||
|
|
||||||
#getTargetAndProjectsToMigrate() {
|
#getTargetAndProjectsToMigrate() {
|
||||||
forEachExecutorOptions(
|
forEachExecutorOptions(
|
||||||
this.tree,
|
this.tree,
|
||||||
@ -403,96 +313,289 @@ class ExecutorToPluginMigrator<T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
global.NX_GRAPH_CREATION = true;
|
global.NX_GRAPH_CREATION = true;
|
||||||
for (const targetName of this.#targetAndProjectsToMigrate.keys()) {
|
try {
|
||||||
const loadedPlugin = new LoadedNxPlugin(
|
for (const targetName of this.#targetAndProjectsToMigrate.keys()) {
|
||||||
{
|
const result = await getCreateNodesResultsForPlugin(
|
||||||
createNodesV2: this.#createNodesV2,
|
this.tree,
|
||||||
createNodes: this.#createNodes,
|
{
|
||||||
name: this.#pluginPath,
|
plugin: this.#pluginPath,
|
||||||
},
|
options: this.#pluginOptionsBuilder(targetName),
|
||||||
{
|
},
|
||||||
plugin: this.#pluginPath,
|
this.#pluginPath,
|
||||||
options: this.#pluginOptionsBuilder(targetName),
|
this.#createNodes,
|
||||||
}
|
this.#createNodesV2,
|
||||||
);
|
|
||||||
let projectConfigs: ConfigurationResult;
|
|
||||||
try {
|
|
||||||
projectConfigs = await retrieveProjectConfigurations(
|
|
||||||
[loadedPlugin],
|
|
||||||
this.tree.root,
|
|
||||||
this.#nxJson
|
this.#nxJson
|
||||||
);
|
);
|
||||||
} catch (e) {
|
this.#createNodesResultsForTargets.set(targetName, result);
|
||||||
if (e instanceof ProjectConfigurationsError) {
|
}
|
||||||
projectConfigs = e.partialProjectConfigurationsResult;
|
} finally {
|
||||||
} else {
|
global.NX_GRAPH_CREATION = false;
|
||||||
global.NX_GRAPH_CREATION = false;
|
}
|
||||||
throw e;
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function migrateProjectExecutorsToPlugin<T>(
|
||||||
|
tree: Tree,
|
||||||
|
projectGraph: ProjectGraph,
|
||||||
|
pluginPath: string,
|
||||||
|
createNodesV2: CreateNodesV2<T>,
|
||||||
|
defaultPluginOptions: T,
|
||||||
|
migrations: Array<{
|
||||||
|
executors: string[];
|
||||||
|
targetPluginOptionMapper: (targetName: string) => Partial<T>;
|
||||||
|
postTargetTransformer: PostTargetTransformer;
|
||||||
|
skipProjectFilter?: SkipProjectFilter;
|
||||||
|
skipTargetFilter?: SkipTargetFilter;
|
||||||
|
}>,
|
||||||
|
specificProjectToMigrate?: string
|
||||||
|
): Promise<Map<string, Record<string, string>>> {
|
||||||
|
const projects = await migrateProjects(
|
||||||
|
tree,
|
||||||
|
projectGraph,
|
||||||
|
pluginPath,
|
||||||
|
undefined,
|
||||||
|
createNodesV2,
|
||||||
|
defaultPluginOptions,
|
||||||
|
migrations,
|
||||||
|
specificProjectToMigrate
|
||||||
|
);
|
||||||
|
|
||||||
|
return projects;
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function migrateProjectExecutorsToPluginV1<T>(
|
||||||
|
tree: Tree,
|
||||||
|
projectGraph: ProjectGraph,
|
||||||
|
pluginPath: string,
|
||||||
|
createNodes: CreateNodes<T>,
|
||||||
|
defaultPluginOptions: T,
|
||||||
|
migrations: Array<{
|
||||||
|
executors: string[];
|
||||||
|
targetPluginOptionMapper: (targetName: string) => Partial<T>;
|
||||||
|
postTargetTransformer: PostTargetTransformer;
|
||||||
|
skipProjectFilter?: SkipProjectFilter;
|
||||||
|
skipTargetFilter?: SkipTargetFilter;
|
||||||
|
}>,
|
||||||
|
specificProjectToMigrate?: string
|
||||||
|
): Promise<Map<string, Record<string, string>>> {
|
||||||
|
const projects = await migrateProjects(
|
||||||
|
tree,
|
||||||
|
projectGraph,
|
||||||
|
pluginPath,
|
||||||
|
createNodes,
|
||||||
|
undefined,
|
||||||
|
defaultPluginOptions,
|
||||||
|
migrations,
|
||||||
|
specificProjectToMigrate
|
||||||
|
);
|
||||||
|
|
||||||
|
return projects;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function migrateProjects<T>(
|
||||||
|
tree: Tree,
|
||||||
|
projectGraph: ProjectGraph,
|
||||||
|
pluginPath: string,
|
||||||
|
createNodes: CreateNodes<T>,
|
||||||
|
createNodesV2: CreateNodesV2<T>,
|
||||||
|
defaultPluginOptions: T,
|
||||||
|
migrations: Array<{
|
||||||
|
executors: string[];
|
||||||
|
targetPluginOptionMapper: (targetName: string) => Partial<T>;
|
||||||
|
postTargetTransformer: PostTargetTransformer;
|
||||||
|
skipProjectFilter?: SkipProjectFilter;
|
||||||
|
skipTargetFilter?: SkipTargetFilter;
|
||||||
|
}>,
|
||||||
|
specificProjectToMigrate?: string
|
||||||
|
): Promise<Map<string, Record<string, string>>> {
|
||||||
|
const projects = new Map<string, Record<string, string>>();
|
||||||
|
|
||||||
|
for (const migration of migrations) {
|
||||||
|
for (const executor of migration.executors) {
|
||||||
|
const migrator = new ExecutorToPluginMigrator(
|
||||||
|
tree,
|
||||||
|
projectGraph,
|
||||||
|
executor,
|
||||||
|
pluginPath,
|
||||||
|
migration.targetPluginOptionMapper,
|
||||||
|
migration.postTargetTransformer,
|
||||||
|
createNodes,
|
||||||
|
createNodesV2,
|
||||||
|
specificProjectToMigrate,
|
||||||
|
{
|
||||||
|
skipProjectFilter: migration.skipProjectFilter,
|
||||||
|
skipTargetFilter: migration.skipTargetFilter,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
const result = await migrator.run();
|
||||||
|
|
||||||
|
// invert the result to have a map of projects to their targets
|
||||||
|
for (const [target, projectList] of result.entries()) {
|
||||||
|
for (const project of projectList) {
|
||||||
|
if (!projects.has(project)) {
|
||||||
|
projects.set(project, {});
|
||||||
|
}
|
||||||
|
|
||||||
|
projects.set(project, {
|
||||||
|
...projects.get(project),
|
||||||
|
...migration.targetPluginOptionMapper(target),
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this.#createNodesResultsForTargets.set(targetName, projectConfigs);
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// apply default options
|
||||||
|
for (const [project, pluginOptions] of projects.entries()) {
|
||||||
|
projects.set(project, {
|
||||||
|
...defaultPluginOptions,
|
||||||
|
...pluginOptions,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
await addPluginRegistrations(
|
||||||
|
tree,
|
||||||
|
projects,
|
||||||
|
pluginPath,
|
||||||
|
createNodes,
|
||||||
|
createNodesV2,
|
||||||
|
defaultPluginOptions,
|
||||||
|
projectGraph
|
||||||
|
);
|
||||||
|
|
||||||
|
return projects;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function addPluginRegistrations<T>(
|
||||||
|
tree: Tree,
|
||||||
|
projects: Map<string, Record<string, string>>,
|
||||||
|
pluginPath: string,
|
||||||
|
createNodes: CreateNodes | undefined,
|
||||||
|
createNodesV2: CreateNodesV2 | undefined,
|
||||||
|
defaultPluginOptions: T,
|
||||||
|
projectGraph: ProjectGraph
|
||||||
|
) {
|
||||||
|
const nxJson = readNxJson(tree);
|
||||||
|
|
||||||
|
// collect createNodes results for each project before adding the plugins
|
||||||
|
const createNodesResults = new Map<string, ConfigurationResult>();
|
||||||
|
global.NX_GRAPH_CREATION = true;
|
||||||
|
try {
|
||||||
|
for (const [project, options] of projects.entries()) {
|
||||||
|
const projectConfigs = await getCreateNodesResultsForPlugin(
|
||||||
|
tree,
|
||||||
|
{ plugin: pluginPath, options },
|
||||||
|
pluginPath,
|
||||||
|
createNodes,
|
||||||
|
createNodesV2,
|
||||||
|
nxJson
|
||||||
|
);
|
||||||
|
|
||||||
|
createNodesResults.set(project, projectConfigs);
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
global.NX_GRAPH_CREATION = false;
|
global.NX_GRAPH_CREATION = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const arePluginIncludesRequired = async (
|
||||||
|
project: string,
|
||||||
|
pluginConfiguration: ExpandedPluginConfiguration
|
||||||
|
): Promise<boolean> => {
|
||||||
|
global.NX_GRAPH_CREATION = true;
|
||||||
|
let result: ConfigurationResult;
|
||||||
|
try {
|
||||||
|
result = await getCreateNodesResultsForPlugin(
|
||||||
|
tree,
|
||||||
|
pluginConfiguration,
|
||||||
|
pluginPath,
|
||||||
|
createNodes,
|
||||||
|
createNodesV2,
|
||||||
|
nxJson
|
||||||
|
);
|
||||||
|
} finally {
|
||||||
|
global.NX_GRAPH_CREATION = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const originalResults = createNodesResults.get(project);
|
||||||
|
|
||||||
|
return !deepEqual(originalResults, result);
|
||||||
|
};
|
||||||
|
|
||||||
|
for (const [project, options] of projects.entries()) {
|
||||||
|
const existingPlugin = nxJson.plugins?.find(
|
||||||
|
(plugin): plugin is ExpandedPluginConfiguration =>
|
||||||
|
typeof plugin !== 'string' &&
|
||||||
|
plugin.plugin === pluginPath &&
|
||||||
|
Object.keys(options).every(
|
||||||
|
(key) =>
|
||||||
|
plugin.options[key] === options[key] ||
|
||||||
|
(plugin.options[key] === undefined &&
|
||||||
|
options[key] === defaultPluginOptions[key])
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
const projectIncludeGlob = `${projectGraph.nodes[project].data.root}/**/*`;
|
||||||
|
if (!existingPlugin) {
|
||||||
|
nxJson.plugins ??= [];
|
||||||
|
const plugin: ExpandedPluginConfiguration = {
|
||||||
|
plugin: pluginPath,
|
||||||
|
options,
|
||||||
|
include: [projectIncludeGlob],
|
||||||
|
};
|
||||||
|
|
||||||
|
if (!(await arePluginIncludesRequired(project, plugin))) {
|
||||||
|
delete plugin.include;
|
||||||
|
}
|
||||||
|
|
||||||
|
nxJson.plugins.push(plugin);
|
||||||
|
} else if (existingPlugin.include) {
|
||||||
|
if (
|
||||||
|
!existingPlugin.include.some((include) =>
|
||||||
|
minimatch(projectIncludeGlob, include, { dot: true })
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
existingPlugin.include.push(projectIncludeGlob);
|
||||||
|
|
||||||
|
if (!(await arePluginIncludesRequired(project, existingPlugin))) {
|
||||||
|
delete existingPlugin.include;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
updateNxJson(tree, nxJson);
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function migrateExecutorToPlugin<T>(
|
async function getCreateNodesResultsForPlugin(
|
||||||
tree: Tree,
|
tree: Tree,
|
||||||
projectGraph: ProjectGraph,
|
pluginConfiguration: ExpandedPluginConfiguration,
|
||||||
executor: string,
|
|
||||||
pluginPath: string,
|
pluginPath: string,
|
||||||
pluginOptionsBuilder: PluginOptionsBuilder<T>,
|
createNodes: CreateNodes | undefined,
|
||||||
postTargetTransformer: PostTargetTransformer,
|
createNodesV2: CreateNodesV2 | undefined,
|
||||||
createNodes: CreateNodesV2<T>,
|
nxJson: NxJsonConfiguration
|
||||||
specificProjectToMigrate?: string,
|
): Promise<ConfigurationResult> {
|
||||||
filters?: {
|
let projectConfigs: ConfigurationResult;
|
||||||
skipProjectFilter?: SkipProjectFilter;
|
|
||||||
skipTargetFilter?: SkipTargetFilter;
|
|
||||||
}
|
|
||||||
): Promise<Map<string, Set<string>>> {
|
|
||||||
const migrator = new ExecutorToPluginMigrator<T>(
|
|
||||||
tree,
|
|
||||||
projectGraph,
|
|
||||||
executor,
|
|
||||||
pluginPath,
|
|
||||||
pluginOptionsBuilder,
|
|
||||||
postTargetTransformer,
|
|
||||||
undefined,
|
|
||||||
createNodes,
|
|
||||||
specificProjectToMigrate,
|
|
||||||
filters
|
|
||||||
);
|
|
||||||
return await migrator.run();
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function migrateExecutorToPluginV1<T>(
|
try {
|
||||||
tree: Tree,
|
const plugin = new LoadedNxPlugin(
|
||||||
projectGraph: ProjectGraph,
|
{ createNodes, createNodesV2, name: pluginPath },
|
||||||
executor: string,
|
pluginConfiguration
|
||||||
pluginPath: string,
|
);
|
||||||
pluginOptionsBuilder: PluginOptionsBuilder<T>,
|
projectConfigs = await retrieveProjectConfigurations(
|
||||||
postTargetTransformer: PostTargetTransformer,
|
[plugin],
|
||||||
createNodes: CreateNodes<T>,
|
tree.root,
|
||||||
specificProjectToMigrate?: string,
|
nxJson
|
||||||
filters?: {
|
);
|
||||||
skipProjectFilter?: SkipProjectFilter;
|
} catch (e) {
|
||||||
skipTargetFilter?: SkipTargetFilter;
|
if (e instanceof ProjectConfigurationsError) {
|
||||||
|
projectConfigs = e.partialProjectConfigurationsResult;
|
||||||
|
} else {
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
): Promise<Map<string, Set<string>>> {
|
|
||||||
const migrator = new ExecutorToPluginMigrator<T>(
|
return projectConfigs;
|
||||||
tree,
|
|
||||||
projectGraph,
|
|
||||||
executor,
|
|
||||||
pluginPath,
|
|
||||||
pluginOptionsBuilder,
|
|
||||||
postTargetTransformer,
|
|
||||||
createNodes,
|
|
||||||
undefined,
|
|
||||||
specificProjectToMigrate,
|
|
||||||
filters
|
|
||||||
);
|
|
||||||
return await migrator.run();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Checks if two objects are structurely equal, without caring
|
// Checks if two objects are structurely equal, without caring
|
||||||
|
|||||||
@ -6,7 +6,7 @@ import {
|
|||||||
type Tree,
|
type Tree,
|
||||||
} from '@nx/devkit';
|
} from '@nx/devkit';
|
||||||
import { createNodesV2, EslintPluginOptions } from '../../plugins/plugin';
|
import { createNodesV2, EslintPluginOptions } from '../../plugins/plugin';
|
||||||
import { migrateExecutorToPlugin } from '@nx/devkit/src/generators/plugin-migrations/executor-to-plugin-migrator';
|
import { migrateProjectExecutorsToPlugin } from '@nx/devkit/src/generators/plugin-migrations/executor-to-plugin-migrator';
|
||||||
import { targetOptionsToCliMap } from './lib/target-options-map';
|
import { targetOptionsToCliMap } from './lib/target-options-map';
|
||||||
import { interpolate } from 'nx/src/tasks-runner/utils';
|
import { interpolate } from 'nx/src/tasks-runner/utils';
|
||||||
import {
|
import {
|
||||||
@ -22,33 +22,24 @@ interface Schema {
|
|||||||
export async function convertToInferred(tree: Tree, options: Schema) {
|
export async function convertToInferred(tree: Tree, options: Schema) {
|
||||||
const projectGraph = await createProjectGraphAsync();
|
const projectGraph = await createProjectGraphAsync();
|
||||||
|
|
||||||
const migratedProjectsModern =
|
|
||||||
await migrateExecutorToPlugin<EslintPluginOptions>(
|
|
||||||
tree,
|
|
||||||
projectGraph,
|
|
||||||
'@nx/eslint:lint',
|
|
||||||
'@nx/eslint/plugin',
|
|
||||||
(targetName) => ({ targetName }),
|
|
||||||
postTargetTransformer,
|
|
||||||
createNodesV2,
|
|
||||||
options.project
|
|
||||||
);
|
|
||||||
|
|
||||||
const migratedProjectsLegacy =
|
|
||||||
await migrateExecutorToPlugin<EslintPluginOptions>(
|
|
||||||
tree,
|
|
||||||
projectGraph,
|
|
||||||
'@nrwl/linter:eslint',
|
|
||||||
'@nx/eslint/plugin',
|
|
||||||
(targetName) => ({ targetName }),
|
|
||||||
postTargetTransformer,
|
|
||||||
createNodesV2,
|
|
||||||
options.project
|
|
||||||
);
|
|
||||||
|
|
||||||
const migratedProjects =
|
const migratedProjects =
|
||||||
migratedProjectsModern.size + migratedProjectsLegacy.size;
|
await migrateProjectExecutorsToPlugin<EslintPluginOptions>(
|
||||||
if (migratedProjects === 0) {
|
tree,
|
||||||
|
projectGraph,
|
||||||
|
'@nx/eslint/plugin',
|
||||||
|
createNodesV2,
|
||||||
|
{ targetName: 'lint' },
|
||||||
|
[
|
||||||
|
{
|
||||||
|
executors: ['@nx/eslint:lint', '@nrwl/linter:eslint'],
|
||||||
|
postTargetTransformer,
|
||||||
|
targetPluginOptionMapper: (targetName) => ({ targetName }),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
options.project
|
||||||
|
);
|
||||||
|
|
||||||
|
if (migratedProjects.size === 0) {
|
||||||
throw new Error('Could not find any targets to migrate.');
|
throw new Error('Could not find any targets to migrate.');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -5,7 +5,7 @@ import {
|
|||||||
type TargetConfiguration,
|
type TargetConfiguration,
|
||||||
type Tree,
|
type Tree,
|
||||||
} from '@nx/devkit';
|
} from '@nx/devkit';
|
||||||
import { migrateExecutorToPlugin } from '@nx/devkit/src/generators/plugin-migrations/executor-to-plugin-migrator';
|
import { migrateProjectExecutorsToPlugin } from '@nx/devkit/src/generators/plugin-migrations/executor-to-plugin-migrator';
|
||||||
import {
|
import {
|
||||||
processTargetOutputs,
|
processTargetOutputs,
|
||||||
toProjectRelativePath,
|
toProjectRelativePath,
|
||||||
@ -22,34 +22,24 @@ interface Schema {
|
|||||||
|
|
||||||
export async function convertToInferred(tree: Tree, options: Schema) {
|
export async function convertToInferred(tree: Tree, options: Schema) {
|
||||||
const projectGraph = await createProjectGraphAsync();
|
const projectGraph = await createProjectGraphAsync();
|
||||||
const migratedProjectsModern =
|
|
||||||
await migrateExecutorToPlugin<JestPluginOptions>(
|
|
||||||
tree,
|
|
||||||
projectGraph,
|
|
||||||
'@nx/jest:jest',
|
|
||||||
'@nx/jest/plugin',
|
|
||||||
(targetName) => ({ targetName }),
|
|
||||||
postTargetTransformer,
|
|
||||||
createNodesV2,
|
|
||||||
options.project
|
|
||||||
);
|
|
||||||
|
|
||||||
const migratedProjectsLegacy =
|
|
||||||
await migrateExecutorToPlugin<JestPluginOptions>(
|
|
||||||
tree,
|
|
||||||
projectGraph,
|
|
||||||
'@nrwl/jest:jest',
|
|
||||||
'@nx/jest/plugin',
|
|
||||||
(targetName) => ({ targetName }),
|
|
||||||
postTargetTransformer,
|
|
||||||
createNodesV2,
|
|
||||||
options.project
|
|
||||||
);
|
|
||||||
|
|
||||||
const migratedProjects =
|
const migratedProjects =
|
||||||
migratedProjectsModern.size + migratedProjectsLegacy.size;
|
await migrateProjectExecutorsToPlugin<JestPluginOptions>(
|
||||||
|
tree,
|
||||||
|
projectGraph,
|
||||||
|
'@nx/jest/plugin',
|
||||||
|
createNodesV2,
|
||||||
|
{ targetName: 'test' },
|
||||||
|
[
|
||||||
|
{
|
||||||
|
executors: ['@nx/jest:jest', '@nrwl/jest:jest'],
|
||||||
|
postTargetTransformer,
|
||||||
|
targetPluginOptionMapper: (targetName) => ({ targetName }),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
options.project
|
||||||
|
);
|
||||||
|
|
||||||
if (migratedProjects === 0) {
|
if (migratedProjects.size === 0) {
|
||||||
throw new Error('Could not find any targets to migrate.');
|
throw new Error('Could not find any targets to migrate.');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -6,7 +6,7 @@ import {
|
|||||||
type Tree,
|
type Tree,
|
||||||
} from '@nx/devkit';
|
} from '@nx/devkit';
|
||||||
import { createNodesV2, PlaywrightPluginOptions } from '../../plugins/plugin';
|
import { createNodesV2, PlaywrightPluginOptions } from '../../plugins/plugin';
|
||||||
import { migrateExecutorToPlugin } from '@nx/devkit/src/generators/plugin-migrations/executor-to-plugin-migrator';
|
import { migrateProjectExecutorsToPlugin } from '@nx/devkit/src/generators/plugin-migrations/executor-to-plugin-migrator';
|
||||||
|
|
||||||
interface Schema {
|
interface Schema {
|
||||||
project?: string;
|
project?: string;
|
||||||
@ -17,14 +17,19 @@ interface Schema {
|
|||||||
export async function convertToInferred(tree: Tree, options: Schema) {
|
export async function convertToInferred(tree: Tree, options: Schema) {
|
||||||
const projectGraph = await createProjectGraphAsync();
|
const projectGraph = await createProjectGraphAsync();
|
||||||
const migratedProjects =
|
const migratedProjects =
|
||||||
await migrateExecutorToPlugin<PlaywrightPluginOptions>(
|
await migrateProjectExecutorsToPlugin<PlaywrightPluginOptions>(
|
||||||
tree,
|
tree,
|
||||||
projectGraph,
|
projectGraph,
|
||||||
'@nx/playwright:playwright',
|
|
||||||
'@nx/playwright/plugin',
|
'@nx/playwright/plugin',
|
||||||
(targetName) => ({ targetName, ciTargetName: 'e2e-ci' }),
|
|
||||||
postTargetTransformer,
|
|
||||||
createNodesV2,
|
createNodesV2,
|
||||||
|
{ targetName: 'e2e', ciTargetName: 'e2e-ci' },
|
||||||
|
[
|
||||||
|
{
|
||||||
|
executors: ['@nx/playwright:playwright'],
|
||||||
|
postTargetTransformer,
|
||||||
|
targetPluginOptionMapper: (targetName) => ({ targetName }),
|
||||||
|
},
|
||||||
|
],
|
||||||
options.project
|
options.project
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@ -239,7 +239,7 @@ describe('Remix - Convert To Inferred', () => {
|
|||||||
plugin: '@nx/remix/plugin',
|
plugin: '@nx/remix/plugin',
|
||||||
options: {
|
options: {
|
||||||
buildTargetName: 'build',
|
buildTargetName: 'build',
|
||||||
devTargetName: defaultTestProjectOptions.serveTargetName,
|
devTargetName: 'custom-dev',
|
||||||
startTargetName: 'start',
|
startTargetName: 'start',
|
||||||
typecheckTargetName: 'typecheck',
|
typecheckTargetName: 'typecheck',
|
||||||
staticServeTargetName: 'static-serve',
|
staticServeTargetName: 'static-serve',
|
||||||
|
|||||||
@ -1,15 +1,9 @@
|
|||||||
import {
|
import { createProjectGraphAsync, formatFiles, type Tree } from '@nx/devkit';
|
||||||
addDependenciesToPackageJson,
|
|
||||||
createProjectGraphAsync,
|
|
||||||
formatFiles,
|
|
||||||
runTasksInSerial,
|
|
||||||
type Tree,
|
|
||||||
} from '@nx/devkit';
|
|
||||||
import { AggregatedLog } from '@nx/devkit/src/generators/plugin-migrations/aggregate-log-util';
|
import { AggregatedLog } from '@nx/devkit/src/generators/plugin-migrations/aggregate-log-util';
|
||||||
import { migrateExecutorToPluginV1 } from '@nx/devkit/src/generators/plugin-migrations/executor-to-plugin-migrator';
|
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 { buildPostTargetTransformer } from './lib/build-post-target-transformer';
|
||||||
import { servePostTargetTransformer } from './lib/serve-post-target-transformer';
|
import { servePostTargetTransformer } from './lib/serve-post-target-transformer';
|
||||||
import { createNodes } from '../../plugins/plugin';
|
|
||||||
|
|
||||||
interface Schema {
|
interface Schema {
|
||||||
project?: string;
|
project?: string;
|
||||||
@ -19,43 +13,38 @@ interface Schema {
|
|||||||
export async function convertToInferred(tree: Tree, options: Schema) {
|
export async function convertToInferred(tree: Tree, options: Schema) {
|
||||||
const projectGraph = await createProjectGraphAsync();
|
const projectGraph = await createProjectGraphAsync();
|
||||||
const migrationLogs = new AggregatedLog();
|
const migrationLogs = new AggregatedLog();
|
||||||
const migratedBuildProjects = await migrateExecutorToPluginV1(
|
const migratedProjects = await migrateProjectExecutorsToPluginV1(
|
||||||
tree,
|
tree,
|
||||||
projectGraph,
|
projectGraph,
|
||||||
'@nx/remix:build',
|
|
||||||
'@nx/remix/plugin',
|
'@nx/remix/plugin',
|
||||||
(targetName) => ({
|
createNodes,
|
||||||
buildTargetName: targetName,
|
{
|
||||||
|
buildTargetName: 'build',
|
||||||
devTargetName: 'dev',
|
devTargetName: 'dev',
|
||||||
startTargetName: 'start',
|
startTargetName: 'start',
|
||||||
typecheckTargetName: 'typecheck',
|
|
||||||
staticServeTargetName: 'static-serve',
|
staticServeTargetName: 'static-serve',
|
||||||
}),
|
typecheckTargetName: 'typecheck',
|
||||||
buildPostTargetTransformer(migrationLogs),
|
},
|
||||||
createNodes,
|
[
|
||||||
|
{
|
||||||
|
executors: ['@nx/remix:build'],
|
||||||
|
postTargetTransformer: buildPostTargetTransformer(migrationLogs),
|
||||||
|
targetPluginOptionMapper: (targetName) => ({
|
||||||
|
buildTargetName: targetName,
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
executors: ['@nx/remix:serve'],
|
||||||
|
postTargetTransformer: servePostTargetTransformer(migrationLogs),
|
||||||
|
targetPluginOptionMapper: (targetName) => ({
|
||||||
|
devTargetName: targetName,
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
],
|
||||||
options.project
|
options.project
|
||||||
);
|
);
|
||||||
|
|
||||||
const migratedServeProjects = await migrateExecutorToPluginV1(
|
if (migratedProjects.size === 0) {
|
||||||
tree,
|
|
||||||
projectGraph,
|
|
||||||
'@nx/remix:serve',
|
|
||||||
'@nx/remix/plugin',
|
|
||||||
(targetName) => ({
|
|
||||||
buildTargetName: 'build',
|
|
||||||
devTargetName: targetName,
|
|
||||||
startTargetName: 'start',
|
|
||||||
typecheckTargetName: 'typecheck',
|
|
||||||
staticServeTargetName: 'static-serve',
|
|
||||||
}),
|
|
||||||
servePostTargetTransformer(migrationLogs),
|
|
||||||
createNodes,
|
|
||||||
options.project
|
|
||||||
);
|
|
||||||
|
|
||||||
const migratedProjects =
|
|
||||||
migratedBuildProjects.size + migratedServeProjects.size;
|
|
||||||
if (migratedProjects === 0) {
|
|
||||||
throw new Error('Could not find any targets to migrate.');
|
throw new Error('Could not find any targets to migrate.');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -287,8 +287,8 @@ describe('Storybook - Convert To Inferred', () => {
|
|||||||
nxJson.plugins.push({
|
nxJson.plugins.push({
|
||||||
plugin: '@nx/storybook/plugin',
|
plugin: '@nx/storybook/plugin',
|
||||||
options: {
|
options: {
|
||||||
buildTargetName: 'storybook-build',
|
buildStorybookTargetName: 'storybook-build',
|
||||||
serveTargetName: defaultTestProjectOptions.serveTargetName,
|
serveStorybookTargetName: 'custom-storybook',
|
||||||
staticStorybookTargetName: 'static-storybook',
|
staticStorybookTargetName: 'static-storybook',
|
||||||
testStorybookTargetName: 'test-storybook',
|
testStorybookTargetName: 'test-storybook',
|
||||||
},
|
},
|
||||||
|
|||||||
@ -6,7 +6,7 @@ import {
|
|||||||
type Tree,
|
type Tree,
|
||||||
} from '@nx/devkit';
|
} from '@nx/devkit';
|
||||||
import { AggregatedLog } from '@nx/devkit/src/generators/plugin-migrations/aggregate-log-util';
|
import { AggregatedLog } from '@nx/devkit/src/generators/plugin-migrations/aggregate-log-util';
|
||||||
import { migrateExecutorToPluginV1 } from '@nx/devkit/src/generators/plugin-migrations/executor-to-plugin-migrator';
|
import { migrateProjectExecutorsToPluginV1 } from '@nx/devkit/src/generators/plugin-migrations/executor-to-plugin-migrator';
|
||||||
import { buildPostTargetTransformer } from './lib/build-post-target-transformer';
|
import { buildPostTargetTransformer } from './lib/build-post-target-transformer';
|
||||||
import { servePostTargetTransformer } from './lib/serve-post-target-transformer';
|
import { servePostTargetTransformer } from './lib/serve-post-target-transformer';
|
||||||
import { createNodes } from '../../plugins/plugin';
|
import { createNodes } from '../../plugins/plugin';
|
||||||
@ -20,41 +20,37 @@ interface Schema {
|
|||||||
export async function convertToInferred(tree: Tree, options: Schema) {
|
export async function convertToInferred(tree: Tree, options: Schema) {
|
||||||
const projectGraph = await createProjectGraphAsync();
|
const projectGraph = await createProjectGraphAsync();
|
||||||
const migrationLogs = new AggregatedLog();
|
const migrationLogs = new AggregatedLog();
|
||||||
const migratedBuildProjects = await migrateExecutorToPluginV1(
|
const migratedProjects = await migrateProjectExecutorsToPluginV1(
|
||||||
tree,
|
tree,
|
||||||
projectGraph,
|
projectGraph,
|
||||||
'@nx/storybook:build',
|
|
||||||
'@nx/storybook/plugin',
|
'@nx/storybook/plugin',
|
||||||
(targetName) => ({
|
createNodes,
|
||||||
buildStorybookTargetName: targetName,
|
{
|
||||||
|
buildStorybookTargetName: 'build-storybook',
|
||||||
serveStorybookTargetName: 'storybook',
|
serveStorybookTargetName: 'storybook',
|
||||||
staticStorybookTargetName: 'static-storybook',
|
staticStorybookTargetName: 'static-storybook',
|
||||||
testStorybookTargetName: 'test-storybook',
|
testStorybookTargetName: 'test-storybook',
|
||||||
}),
|
},
|
||||||
buildPostTargetTransformer(migrationLogs),
|
[
|
||||||
createNodes,
|
{
|
||||||
|
executors: ['@nx/storybook:build', '@nrwl/storybook:build'],
|
||||||
|
postTargetTransformer: buildPostTargetTransformer(migrationLogs),
|
||||||
|
targetPluginOptionMapper: (targetName) => ({
|
||||||
|
buildStorybookTargetName: targetName,
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
executors: ['@nx/storybook:storybook', '@nrwl/storybook:storybook'],
|
||||||
|
postTargetTransformer: servePostTargetTransformer(migrationLogs),
|
||||||
|
targetPluginOptionMapper: (targetName) => ({
|
||||||
|
serveStorybookTargetName: targetName,
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
],
|
||||||
options.project
|
options.project
|
||||||
);
|
);
|
||||||
|
|
||||||
const migratedServeProjects = await migrateExecutorToPluginV1(
|
if (migratedProjects.size === 0) {
|
||||||
tree,
|
|
||||||
projectGraph,
|
|
||||||
'@nx/storybook:storybook',
|
|
||||||
'@nx/storybook/plugin',
|
|
||||||
(targetName) => ({
|
|
||||||
buildStorybookTargetName: 'build-storybook',
|
|
||||||
serveStorybookTargetName: targetName,
|
|
||||||
staticStorybookTargetName: 'static-storybook',
|
|
||||||
testStorybookTargetName: 'test-storybook',
|
|
||||||
}),
|
|
||||||
servePostTargetTransformer(migrationLogs),
|
|
||||||
createNodes,
|
|
||||||
options.project
|
|
||||||
);
|
|
||||||
|
|
||||||
const migratedProjects =
|
|
||||||
migratedBuildProjects.size + migratedServeProjects.size;
|
|
||||||
if (migratedProjects === 0) {
|
|
||||||
throw new Error('Could not find any targets to migrate.');
|
throw new Error('Could not find any targets to migrate.');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -18,6 +18,7 @@ import {
|
|||||||
} from '@nx/devkit';
|
} from '@nx/devkit';
|
||||||
import { TempFs } from '@nx/devkit/internal-testing-utils';
|
import { TempFs } from '@nx/devkit/internal-testing-utils';
|
||||||
import { join } from 'node:path';
|
import { join } from 'node:path';
|
||||||
|
import type { VitePluginOptions } from '../../plugins/plugin';
|
||||||
|
|
||||||
let fs: TempFs;
|
let fs: TempFs;
|
||||||
|
|
||||||
@ -514,33 +515,116 @@ describe('Vite - Convert Executors To Plugin', () => {
|
|||||||
|
|
||||||
// nx.json modifications
|
// nx.json modifications
|
||||||
const nxJsonPlugins = readNxJson(tree).plugins;
|
const nxJsonPlugins = readNxJson(tree).plugins;
|
||||||
const addedTestVitePlugin = nxJsonPlugins.find((plugin) => {
|
const addedVitePlugins = nxJsonPlugins.filter((plugin) => {
|
||||||
if (
|
if (typeof plugin !== 'string' && plugin.plugin === '@nx/vite/plugin') {
|
||||||
typeof plugin !== 'string' &&
|
|
||||||
plugin.plugin === '@nx/vite/plugin' &&
|
|
||||||
plugin.include?.length === 2
|
|
||||||
) {
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
expect(addedTestVitePlugin).toBeTruthy();
|
expect(addedVitePlugins).toMatchInlineSnapshot(`
|
||||||
expect(
|
[
|
||||||
(addedTestVitePlugin as ExpandedPluginConfiguration).include
|
{
|
||||||
).toEqual(['myapp/**/*', 'second/**/*']);
|
"options": {
|
||||||
|
"buildTargetName": "build",
|
||||||
|
"previewTargetName": "preview",
|
||||||
|
"serveTargetName": "serve",
|
||||||
|
"testTargetName": "test",
|
||||||
|
},
|
||||||
|
"plugin": "@nx/vite/plugin",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"include": [
|
||||||
|
"myapp/**/*",
|
||||||
|
"second/**/*",
|
||||||
|
],
|
||||||
|
"options": {
|
||||||
|
"buildTargetName": "bundle",
|
||||||
|
"previewTargetName": "preview",
|
||||||
|
"serveStaticTargetName": "serve-static",
|
||||||
|
"serveTargetName": "serve",
|
||||||
|
"testTargetName": "test",
|
||||||
|
},
|
||||||
|
"plugin": "@nx/vite/plugin",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"include": [
|
||||||
|
"third/**/*",
|
||||||
|
],
|
||||||
|
"options": {
|
||||||
|
"buildTargetName": "build-base",
|
||||||
|
"previewTargetName": "preview",
|
||||||
|
"serveStaticTargetName": "serve-static",
|
||||||
|
"serveTargetName": "serve",
|
||||||
|
"testTargetName": "test",
|
||||||
|
},
|
||||||
|
"plugin": "@nx/vite/plugin",
|
||||||
|
},
|
||||||
|
]
|
||||||
|
`);
|
||||||
|
});
|
||||||
|
|
||||||
const addedIntegrationVitePlugin = nxJsonPlugins.find((plugin) => {
|
it('should handle multiple different target names for the same project', async () => {
|
||||||
if (
|
const project1 = createTestProject(tree);
|
||||||
typeof plugin !== 'string' &&
|
const project2 = createTestProject(tree, {
|
||||||
plugin.plugin === '@nx/vite/plugin' &&
|
appRoot: 'project2',
|
||||||
plugin.include?.length === 1
|
appName: 'project2',
|
||||||
) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
expect(addedIntegrationVitePlugin).toBeTruthy();
|
const project3 = createTestProject(tree, {
|
||||||
expect(
|
appRoot: 'project3',
|
||||||
(addedIntegrationVitePlugin as ExpandedPluginConfiguration).include
|
appName: 'project3',
|
||||||
).toEqual(['third/**/*']);
|
buildTargetName: 'vite-build',
|
||||||
|
serveTargetName: 'vite-serve',
|
||||||
|
});
|
||||||
|
const project4 = createTestProject(tree, {
|
||||||
|
appRoot: 'project4',
|
||||||
|
appName: 'project4',
|
||||||
|
buildTargetName: 'build',
|
||||||
|
serveTargetName: 'vite-serve',
|
||||||
|
});
|
||||||
|
const project5 = createTestProject(tree, {
|
||||||
|
appRoot: 'project5',
|
||||||
|
appName: 'project5',
|
||||||
|
buildTargetName: 'vite-build',
|
||||||
|
serveTargetName: 'serve',
|
||||||
|
});
|
||||||
|
|
||||||
|
await convertToInferred(tree, { skipFormat: true });
|
||||||
|
|
||||||
|
// nx.json modifications
|
||||||
|
const nxJsonPlugins = readNxJson(tree).plugins;
|
||||||
|
const vitePluginRegistrations = nxJsonPlugins.filter(
|
||||||
|
(plugin): plugin is ExpandedPluginConfiguration<VitePluginOptions> =>
|
||||||
|
typeof plugin !== 'string' && plugin.plugin === '@nx/vite/plugin'
|
||||||
|
);
|
||||||
|
expect(vitePluginRegistrations.length).toBe(4);
|
||||||
|
expect(vitePluginRegistrations[0].options.buildTargetName).toBe('build');
|
||||||
|
expect(vitePluginRegistrations[0].options.serveTargetName).toBe('serve');
|
||||||
|
expect(vitePluginRegistrations[0].include).toEqual([
|
||||||
|
`${project1.root}/**/*`,
|
||||||
|
`${project2.root}/**/*`,
|
||||||
|
]);
|
||||||
|
expect(vitePluginRegistrations[1].options.buildTargetName).toBe('build');
|
||||||
|
expect(vitePluginRegistrations[1].options.serveTargetName).toBe(
|
||||||
|
'vite-serve'
|
||||||
|
);
|
||||||
|
expect(vitePluginRegistrations[1].include).toEqual([
|
||||||
|
`${project4.root}/**/*`,
|
||||||
|
]);
|
||||||
|
expect(vitePluginRegistrations[2].options.buildTargetName).toBe(
|
||||||
|
'vite-build'
|
||||||
|
);
|
||||||
|
expect(vitePluginRegistrations[2].options.serveTargetName).toBe(
|
||||||
|
'vite-serve'
|
||||||
|
);
|
||||||
|
expect(vitePluginRegistrations[2].include).toEqual([
|
||||||
|
`${project3.root}/**/*`,
|
||||||
|
]);
|
||||||
|
expect(vitePluginRegistrations[3].options.buildTargetName).toBe(
|
||||||
|
'vite-build'
|
||||||
|
);
|
||||||
|
expect(vitePluginRegistrations[3].options.serveTargetName).toBe('serve');
|
||||||
|
expect(vitePluginRegistrations[3].include).toEqual([
|
||||||
|
`${project5.root}/**/*`,
|
||||||
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should keep Vite options in project.json', async () => {
|
it('should keep Vite options in project.json', async () => {
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import { createProjectGraphAsync, formatFiles, type Tree } from '@nx/devkit';
|
import { createProjectGraphAsync, formatFiles, type Tree } from '@nx/devkit';
|
||||||
import { migrateExecutorToPlugin } from '@nx/devkit/src/generators/plugin-migrations/executor-to-plugin-migrator';
|
import { migrateProjectExecutorsToPlugin } from '@nx/devkit/src/generators/plugin-migrations/executor-to-plugin-migrator';
|
||||||
import { createNodesV2, VitePluginOptions } from '../../plugins/plugin';
|
import { createNodesV2, VitePluginOptions } from '../../plugins/plugin';
|
||||||
import { buildPostTargetTransformer } from './lib/build-post-target-transformer';
|
import { buildPostTargetTransformer } from './lib/build-post-target-transformer';
|
||||||
import { servePostTargetTransformer } from './lib/serve-post-target-transformer';
|
import { servePostTargetTransformer } from './lib/serve-post-target-transformer';
|
||||||
@ -15,81 +15,46 @@ interface Schema {
|
|||||||
export async function convertToInferred(tree: Tree, options: Schema) {
|
export async function convertToInferred(tree: Tree, options: Schema) {
|
||||||
const projectGraph = await createProjectGraphAsync();
|
const projectGraph = await createProjectGraphAsync();
|
||||||
const migrationLogs = new AggregatedLog();
|
const migrationLogs = new AggregatedLog();
|
||||||
const migratedBuildProjects =
|
|
||||||
await migrateExecutorToPlugin<VitePluginOptions>(
|
|
||||||
tree,
|
|
||||||
projectGraph,
|
|
||||||
'@nx/vite:build',
|
|
||||||
'@nx/vite/plugin',
|
|
||||||
(targetName) => ({
|
|
||||||
buildTargetName: targetName,
|
|
||||||
serveTargetName: 'serve',
|
|
||||||
previewTargetName: 'preview',
|
|
||||||
testTargetName: 'test',
|
|
||||||
serveStaticTargetName: 'serve-static',
|
|
||||||
}),
|
|
||||||
buildPostTargetTransformer,
|
|
||||||
createNodesV2,
|
|
||||||
options.project
|
|
||||||
);
|
|
||||||
const migratedServeProjects =
|
|
||||||
await migrateExecutorToPlugin<VitePluginOptions>(
|
|
||||||
tree,
|
|
||||||
projectGraph,
|
|
||||||
'@nx/vite:dev-server',
|
|
||||||
'@nx/vite/plugin',
|
|
||||||
(targetName) => ({
|
|
||||||
buildTargetName: 'build',
|
|
||||||
serveTargetName: targetName,
|
|
||||||
previewTargetName: 'preview',
|
|
||||||
testTargetName: 'test',
|
|
||||||
serveStaticTargetName: 'serve-static',
|
|
||||||
}),
|
|
||||||
servePostTargetTransformer(migrationLogs),
|
|
||||||
createNodesV2,
|
|
||||||
options.project
|
|
||||||
);
|
|
||||||
const migratedPreviewProjects =
|
|
||||||
await migrateExecutorToPlugin<VitePluginOptions>(
|
|
||||||
tree,
|
|
||||||
projectGraph,
|
|
||||||
'@nx/vite:preview-server',
|
|
||||||
'@nx/vite/plugin',
|
|
||||||
(targetName) => ({
|
|
||||||
buildTargetName: 'build',
|
|
||||||
serveTargetName: 'serve',
|
|
||||||
previewTargetName: targetName,
|
|
||||||
testTargetName: 'test',
|
|
||||||
serveStaticTargetName: 'serve-static',
|
|
||||||
}),
|
|
||||||
previewPostTargetTransformer(migrationLogs),
|
|
||||||
createNodesV2,
|
|
||||||
options.project
|
|
||||||
);
|
|
||||||
const migratedTestProjects = await migrateExecutorToPlugin<VitePluginOptions>(
|
|
||||||
tree,
|
|
||||||
projectGraph,
|
|
||||||
'@nx/vite:test',
|
|
||||||
'@nx/vite/plugin',
|
|
||||||
(targetName) => ({
|
|
||||||
buildTargetName: 'build',
|
|
||||||
serveTargetName: 'serve',
|
|
||||||
previewTargetName: 'preview',
|
|
||||||
testTargetName: targetName,
|
|
||||||
serveStaticTargetName: 'serve-static',
|
|
||||||
}),
|
|
||||||
testPostTargetTransformer,
|
|
||||||
createNodesV2,
|
|
||||||
options.project
|
|
||||||
);
|
|
||||||
|
|
||||||
const migratedProjects =
|
const migratedProjects =
|
||||||
migratedBuildProjects.size +
|
await migrateProjectExecutorsToPlugin<VitePluginOptions>(
|
||||||
migratedServeProjects.size +
|
tree,
|
||||||
migratedPreviewProjects.size +
|
projectGraph,
|
||||||
migratedTestProjects.size;
|
'@nx/vite/plugin',
|
||||||
|
createNodesV2,
|
||||||
|
{
|
||||||
|
buildTargetName: 'build',
|
||||||
|
serveTargetName: 'serve',
|
||||||
|
previewTargetName: 'preview',
|
||||||
|
testTargetName: 'test',
|
||||||
|
serveStaticTargetName: 'serve-static',
|
||||||
|
},
|
||||||
|
[
|
||||||
|
{
|
||||||
|
executors: ['@nx/vite:build'],
|
||||||
|
postTargetTransformer: buildPostTargetTransformer,
|
||||||
|
targetPluginOptionMapper: (target) => ({ buildTargetName: target }),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
executors: ['@nx/vite:dev-server'],
|
||||||
|
postTargetTransformer: servePostTargetTransformer(migrationLogs),
|
||||||
|
targetPluginOptionMapper: (target) => ({ serveTargetName: target }),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
executors: ['@nx/vite:preview-server'],
|
||||||
|
postTargetTransformer: previewPostTargetTransformer(migrationLogs),
|
||||||
|
targetPluginOptionMapper: (target) => ({ previewTargetName: target }),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
executors: ['@nx/vite:test'],
|
||||||
|
postTargetTransformer: testPostTargetTransformer,
|
||||||
|
targetPluginOptionMapper: (target) => ({ testTargetName: target }),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
options.project
|
||||||
|
);
|
||||||
|
|
||||||
if (migratedProjects === 0) {
|
if (migratedProjects.size === 0) {
|
||||||
throw new Error('Could not find any targets to migrate.');
|
throw new Error('Could not find any targets to migrate.');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -3,6 +3,7 @@ import {
|
|||||||
joinPathFragments,
|
joinPathFragments,
|
||||||
readNxJson,
|
readNxJson,
|
||||||
readProjectConfiguration,
|
readProjectConfiguration,
|
||||||
|
updateNxJson,
|
||||||
updateProjectConfiguration,
|
updateProjectConfiguration,
|
||||||
writeJson,
|
writeJson,
|
||||||
type ExpandedPluginConfiguration,
|
type ExpandedPluginConfiguration,
|
||||||
@ -14,6 +15,7 @@ import { TempFs } from '@nx/devkit/internal-testing-utils';
|
|||||||
import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing';
|
import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing';
|
||||||
import { join } from 'node:path';
|
import { join } from 'node:path';
|
||||||
import { getRelativeProjectJsonSchemaPath } from 'nx/src/generators/utils/project-configuration';
|
import { getRelativeProjectJsonSchemaPath } from 'nx/src/generators/utils/project-configuration';
|
||||||
|
import type { WebpackPluginOptions } from '../../plugins/plugin';
|
||||||
import { convertToInferred } from './convert-to-inferred';
|
import { convertToInferred } from './convert-to-inferred';
|
||||||
|
|
||||||
let fs: TempFs;
|
let fs: TempFs;
|
||||||
@ -377,6 +379,78 @@ describe('convert-to-inferred', () => {
|
|||||||
expect(updatedProject2.targets.build).toStrictEqual(project2BuildTarget);
|
expect(updatedProject2.targets.build).toStrictEqual(project2BuildTarget);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should remove "includes" from the plugin registration when all projects are included', async () => {
|
||||||
|
const project1 = createProject(tree);
|
||||||
|
writeWebpackConfig(tree, project1.root);
|
||||||
|
const nxJson = readNxJson(tree);
|
||||||
|
nxJson.plugins ??= [];
|
||||||
|
nxJson.plugins.push({
|
||||||
|
plugin: '@nx/webpack/plugin',
|
||||||
|
options: {
|
||||||
|
buildTargetName: 'build',
|
||||||
|
previewTargetName: 'preview',
|
||||||
|
serveStaticTargetName: 'serve-static',
|
||||||
|
serveTargetName: 'serve',
|
||||||
|
},
|
||||||
|
include: [`${project1.root}/**/*`],
|
||||||
|
});
|
||||||
|
updateNxJson(tree, nxJson);
|
||||||
|
const project2 = createProject(tree, {
|
||||||
|
appName: 'app2',
|
||||||
|
appRoot: 'apps/app2',
|
||||||
|
});
|
||||||
|
writeWebpackConfig(tree, project2.root);
|
||||||
|
|
||||||
|
await convertToInferred(tree, { project: project2.name });
|
||||||
|
|
||||||
|
// nx.json modifications
|
||||||
|
const nxJsonPlugins = readNxJson(tree).plugins;
|
||||||
|
const webpackPluginRegistrations = nxJsonPlugins.filter(
|
||||||
|
(plugin): plugin is ExpandedPluginConfiguration<WebpackPluginOptions> =>
|
||||||
|
typeof plugin !== 'string' && plugin.plugin === '@nx/webpack/plugin'
|
||||||
|
);
|
||||||
|
expect(webpackPluginRegistrations.length).toBe(1);
|
||||||
|
expect(webpackPluginRegistrations[0].include).toBeUndefined();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not add to "includes" when existing matching registration does not have it set', async () => {
|
||||||
|
const project1 = createProject(tree);
|
||||||
|
writeWebpackConfig(tree, project1.root);
|
||||||
|
const nxJson = readNxJson(tree);
|
||||||
|
nxJson.plugins ??= [];
|
||||||
|
nxJson.plugins.push({
|
||||||
|
plugin: '@nx/webpack/plugin',
|
||||||
|
options: {
|
||||||
|
buildTargetName: 'build',
|
||||||
|
previewTargetName: 'preview',
|
||||||
|
serveStaticTargetName: 'serve-static',
|
||||||
|
serveTargetName: 'serve',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
updateNxJson(tree, nxJson);
|
||||||
|
const project2 = createProject(tree, {
|
||||||
|
appName: 'app2',
|
||||||
|
appRoot: 'apps/app2',
|
||||||
|
});
|
||||||
|
writeWebpackConfig(tree, project2.root);
|
||||||
|
const project3 = createProject(tree, {
|
||||||
|
appName: 'app3',
|
||||||
|
appRoot: 'apps/app3',
|
||||||
|
});
|
||||||
|
writeWebpackConfig(tree, project3.root);
|
||||||
|
|
||||||
|
await convertToInferred(tree, { project: project2.name });
|
||||||
|
|
||||||
|
// nx.json modifications
|
||||||
|
const nxJsonPlugins = readNxJson(tree).plugins;
|
||||||
|
const webpackPluginRegistrations = nxJsonPlugins.filter(
|
||||||
|
(plugin): plugin is ExpandedPluginConfiguration<WebpackPluginOptions> =>
|
||||||
|
typeof plugin !== 'string' && plugin.plugin === '@nx/webpack/plugin'
|
||||||
|
);
|
||||||
|
expect(webpackPluginRegistrations.length).toBe(1);
|
||||||
|
expect(webpackPluginRegistrations[0].include).toBeUndefined();
|
||||||
|
});
|
||||||
|
|
||||||
it('should move options to the webpack config file', async () => {
|
it('should move options to the webpack config file', async () => {
|
||||||
const project = createProject(tree);
|
const project = createProject(tree);
|
||||||
writeWebpackConfig(tree, project.root);
|
writeWebpackConfig(tree, project.root);
|
||||||
@ -753,11 +827,26 @@ describe('convert-to-inferred', () => {
|
|||||||
appName: 'app3',
|
appName: 'app3',
|
||||||
appRoot: 'apps/app3',
|
appRoot: 'apps/app3',
|
||||||
buildTargetName: 'build-webpack',
|
buildTargetName: 'build-webpack',
|
||||||
|
serveTargetName: 'serve-webpack',
|
||||||
});
|
});
|
||||||
writeWebpackConfig(tree, project3.root);
|
writeWebpackConfig(tree, project3.root);
|
||||||
const projectWithComposePlugins = createProject(tree, {
|
const project4 = createProject(tree, {
|
||||||
appName: 'app4',
|
appName: 'app4',
|
||||||
appRoot: 'apps/app4',
|
appRoot: 'apps/app4',
|
||||||
|
buildTargetName: 'build',
|
||||||
|
serveTargetName: 'serve-webpack',
|
||||||
|
});
|
||||||
|
writeWebpackConfig(tree, project4.root);
|
||||||
|
const project5 = createProject(tree, {
|
||||||
|
appName: 'app5',
|
||||||
|
appRoot: 'apps/app5',
|
||||||
|
buildTargetName: 'build-webpack',
|
||||||
|
serveTargetName: 'serve',
|
||||||
|
});
|
||||||
|
writeWebpackConfig(tree, project5.root);
|
||||||
|
const projectWithComposePlugins = createProject(tree, {
|
||||||
|
appName: 'app6',
|
||||||
|
appRoot: 'apps/app6',
|
||||||
});
|
});
|
||||||
const projectWithComposePluginsInitialTargets =
|
const projectWithComposePluginsInitialTargets =
|
||||||
projectWithComposePlugins.targets;
|
projectWithComposePlugins.targets;
|
||||||
@ -783,8 +872,8 @@ module.exports = composePlugins(
|
|||||||
initialProjectWithComposePluginsWebpackConfig
|
initialProjectWithComposePluginsWebpackConfig
|
||||||
);
|
);
|
||||||
const projectWithNoNxAppWebpackPlugin = createProject(tree, {
|
const projectWithNoNxAppWebpackPlugin = createProject(tree, {
|
||||||
appName: 'app5',
|
appName: 'app7',
|
||||||
appRoot: 'apps/app5',
|
appRoot: 'apps/app7',
|
||||||
});
|
});
|
||||||
const projectWithNoNxAppWebpackPluginInitialTargets =
|
const projectWithNoNxAppWebpackPluginInitialTargets =
|
||||||
projectWithNoNxAppWebpackPlugin.targets;
|
projectWithNoNxAppWebpackPlugin.targets;
|
||||||
@ -829,6 +918,28 @@ module.exports = composePlugins(
|
|||||||
});
|
});
|
||||||
const updatedProject3 = readProjectConfiguration(tree, project3.name);
|
const updatedProject3 = readProjectConfiguration(tree, project3.name);
|
||||||
expect(updatedProject3.targets).toStrictEqual({
|
expect(updatedProject3.targets).toStrictEqual({
|
||||||
|
'build-webpack': {
|
||||||
|
configurations: { development: {}, production: {} },
|
||||||
|
defaultConfiguration: 'production',
|
||||||
|
},
|
||||||
|
'serve-webpack': {
|
||||||
|
configurations: { development: {}, production: {} },
|
||||||
|
defaultConfiguration: 'development',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
const updatedProject4 = readProjectConfiguration(tree, project4.name);
|
||||||
|
expect(updatedProject4.targets).toStrictEqual({
|
||||||
|
build: {
|
||||||
|
configurations: { development: {}, production: {} },
|
||||||
|
defaultConfiguration: 'production',
|
||||||
|
},
|
||||||
|
'serve-webpack': {
|
||||||
|
configurations: { development: {}, production: {} },
|
||||||
|
defaultConfiguration: 'development',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
const updatedProject5 = readProjectConfiguration(tree, project5.name);
|
||||||
|
expect(updatedProject5.targets).toStrictEqual({
|
||||||
'build-webpack': {
|
'build-webpack': {
|
||||||
configurations: { development: {}, production: {} },
|
configurations: { development: {}, production: {} },
|
||||||
defaultConfiguration: 'production',
|
defaultConfiguration: 'production',
|
||||||
@ -882,6 +993,73 @@ module.exports = composePlugins(
|
|||||||
expect(updatedProjectWithNoNxAppWebpackPluginWebpackConfig).toBe(
|
expect(updatedProjectWithNoNxAppWebpackPluginWebpackConfig).toBe(
|
||||||
initialProjectWithNoNxAppWebpackPluginWebpackConfig
|
initialProjectWithNoNxAppWebpackPluginWebpackConfig
|
||||||
);
|
);
|
||||||
|
// nx.json modifications
|
||||||
|
const nxJsonPlugins = readNxJson(tree).plugins;
|
||||||
|
const webpackPluginRegistrations = nxJsonPlugins.filter(
|
||||||
|
(plugin): plugin is ExpandedPluginConfiguration<WebpackPluginOptions> =>
|
||||||
|
typeof plugin !== 'string' && plugin.plugin === '@nx/webpack/plugin'
|
||||||
|
);
|
||||||
|
expect(webpackPluginRegistrations.length).toBe(4);
|
||||||
|
expect(webpackPluginRegistrations[0].options.buildTargetName).toBe(
|
||||||
|
'build'
|
||||||
|
);
|
||||||
|
expect(webpackPluginRegistrations[0].options.serveTargetName).toBe(
|
||||||
|
'serve'
|
||||||
|
);
|
||||||
|
expect(webpackPluginRegistrations[0].include).toEqual([
|
||||||
|
`${project1.root}/**/*`,
|
||||||
|
`${project2.root}/**/*`,
|
||||||
|
]);
|
||||||
|
expect(webpackPluginRegistrations[1].options.buildTargetName).toBe(
|
||||||
|
'build'
|
||||||
|
);
|
||||||
|
expect(webpackPluginRegistrations[1].options.serveTargetName).toBe(
|
||||||
|
'serve-webpack'
|
||||||
|
);
|
||||||
|
expect(webpackPluginRegistrations[1].include).toEqual([
|
||||||
|
`${project4.root}/**/*`,
|
||||||
|
]);
|
||||||
|
expect(webpackPluginRegistrations[2].options.buildTargetName).toBe(
|
||||||
|
'build-webpack'
|
||||||
|
);
|
||||||
|
expect(webpackPluginRegistrations[2].options.serveTargetName).toBe(
|
||||||
|
'serve-webpack'
|
||||||
|
);
|
||||||
|
expect(webpackPluginRegistrations[2].include).toEqual([
|
||||||
|
`${project3.root}/**/*`,
|
||||||
|
]);
|
||||||
|
expect(webpackPluginRegistrations[3].options.buildTargetName).toBe(
|
||||||
|
'build-webpack'
|
||||||
|
);
|
||||||
|
expect(webpackPluginRegistrations[3].options.serveTargetName).toBe(
|
||||||
|
'serve'
|
||||||
|
);
|
||||||
|
expect(webpackPluginRegistrations[3].include).toEqual([
|
||||||
|
`${project5.root}/**/*`,
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should remove "includes" from the plugin registration when all projects are included', async () => {
|
||||||
|
const project1 = createProject(tree);
|
||||||
|
writeWebpackConfig(tree, project1.root);
|
||||||
|
const project2 = createProject(tree, {
|
||||||
|
appName: 'app2',
|
||||||
|
appRoot: 'apps/app2',
|
||||||
|
buildExecutor: '@nrwl/webpack:webpack',
|
||||||
|
serveExecutor: '@nrwl/webpack:dev-server',
|
||||||
|
});
|
||||||
|
writeWebpackConfig(tree, project2.root);
|
||||||
|
|
||||||
|
await convertToInferred(tree, {});
|
||||||
|
|
||||||
|
// nx.json modifications
|
||||||
|
const nxJsonPlugins = readNxJson(tree).plugins;
|
||||||
|
const webpackPluginRegistrations = nxJsonPlugins.filter(
|
||||||
|
(plugin): plugin is ExpandedPluginConfiguration<WebpackPluginOptions> =>
|
||||||
|
typeof plugin !== 'string' && plugin.plugin === '@nx/webpack/plugin'
|
||||||
|
);
|
||||||
|
expect(webpackPluginRegistrations.length).toBe(1);
|
||||||
|
expect(webpackPluginRegistrations[0].include).toBeUndefined();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should keep the higher "memoryLimit" value in the build configuration', async () => {
|
it('should keep the higher "memoryLimit" value in the build configuration', async () => {
|
||||||
|
|||||||
@ -2,20 +2,20 @@ import {
|
|||||||
addDependenciesToPackageJson,
|
addDependenciesToPackageJson,
|
||||||
createProjectGraphAsync,
|
createProjectGraphAsync,
|
||||||
formatFiles,
|
formatFiles,
|
||||||
type ProjectConfiguration,
|
|
||||||
runTasksInSerial,
|
runTasksInSerial,
|
||||||
|
type ProjectConfiguration,
|
||||||
type Tree,
|
type Tree,
|
||||||
} from '@nx/devkit';
|
} from '@nx/devkit';
|
||||||
import { AggregatedLog } from '@nx/devkit/src/generators/plugin-migrations/aggregate-log-util';
|
import { AggregatedLog } from '@nx/devkit/src/generators/plugin-migrations/aggregate-log-util';
|
||||||
import { migrateExecutorToPlugin } from '@nx/devkit/src/generators/plugin-migrations/executor-to-plugin-migrator';
|
import { migrateProjectExecutorsToPlugin } from '@nx/devkit/src/generators/plugin-migrations/executor-to-plugin-migrator';
|
||||||
import { tsquery } from '@phenomnomnominal/tsquery';
|
import { tsquery } from '@phenomnomnominal/tsquery';
|
||||||
import * as ts from 'typescript';
|
import * as ts from 'typescript';
|
||||||
import { createNodesV2, type WebpackPluginOptions } from '../../plugins/plugin';
|
import { createNodesV2, type WebpackPluginOptions } from '../../plugins/plugin';
|
||||||
import { webpackCliVersion } from '../../utils/versions';
|
import { webpackCliVersion } from '../../utils/versions';
|
||||||
import {
|
import {
|
||||||
buildPostTargetTransformerFactory,
|
buildPostTargetTransformerFactory,
|
||||||
type MigrationContext,
|
|
||||||
servePostTargetTransformerFactory,
|
servePostTargetTransformerFactory,
|
||||||
|
type MigrationContext,
|
||||||
} from './utils';
|
} from './utils';
|
||||||
|
|
||||||
interface Schema {
|
interface Schema {
|
||||||
@ -31,85 +31,38 @@ export async function convertToInferred(tree: Tree, options: Schema) {
|
|||||||
workspaceRoot: tree.root,
|
workspaceRoot: tree.root,
|
||||||
};
|
};
|
||||||
|
|
||||||
// build
|
|
||||||
const migratedBuildProjects =
|
|
||||||
await migrateExecutorToPlugin<WebpackPluginOptions>(
|
|
||||||
tree,
|
|
||||||
projectGraph,
|
|
||||||
'@nx/webpack:webpack',
|
|
||||||
'@nx/webpack/plugin',
|
|
||||||
(targetName) => ({
|
|
||||||
buildTargetName: targetName,
|
|
||||||
previewTargetName: 'preview',
|
|
||||||
serveStaticTargetName: 'serve-static',
|
|
||||||
serveTargetName: 'serve',
|
|
||||||
}),
|
|
||||||
buildPostTargetTransformerFactory(migrationContext),
|
|
||||||
createNodesV2,
|
|
||||||
options.project,
|
|
||||||
{ skipProjectFilter: skipProjectFilterFactory(tree) }
|
|
||||||
);
|
|
||||||
const migratedBuildProjectsLegacy =
|
|
||||||
await migrateExecutorToPlugin<WebpackPluginOptions>(
|
|
||||||
tree,
|
|
||||||
projectGraph,
|
|
||||||
'@nrwl/webpack:webpack',
|
|
||||||
'@nx/webpack/plugin',
|
|
||||||
(targetName) => ({
|
|
||||||
buildTargetName: targetName,
|
|
||||||
previewTargetName: 'preview',
|
|
||||||
serveStaticTargetName: 'serve-static',
|
|
||||||
serveTargetName: 'serve',
|
|
||||||
}),
|
|
||||||
buildPostTargetTransformerFactory(migrationContext),
|
|
||||||
createNodesV2,
|
|
||||||
options.project,
|
|
||||||
{ skipProjectFilter: skipProjectFilterFactory(tree) }
|
|
||||||
);
|
|
||||||
|
|
||||||
// serve
|
|
||||||
const migratedServeProjects =
|
|
||||||
await migrateExecutorToPlugin<WebpackPluginOptions>(
|
|
||||||
tree,
|
|
||||||
projectGraph,
|
|
||||||
'@nx/webpack:dev-server',
|
|
||||||
'@nx/webpack/plugin',
|
|
||||||
(targetName) => ({
|
|
||||||
buildTargetName: 'build',
|
|
||||||
previewTargetName: 'preview',
|
|
||||||
serveStaticTargetName: 'serve-static',
|
|
||||||
serveTargetName: targetName,
|
|
||||||
}),
|
|
||||||
servePostTargetTransformerFactory(migrationContext),
|
|
||||||
createNodesV2,
|
|
||||||
options.project,
|
|
||||||
{ skipProjectFilter: skipProjectFilterFactory(tree) }
|
|
||||||
);
|
|
||||||
const migratedServeProjectsLegacy =
|
|
||||||
await migrateExecutorToPlugin<WebpackPluginOptions>(
|
|
||||||
tree,
|
|
||||||
projectGraph,
|
|
||||||
'@nrwl/webpack:dev-server',
|
|
||||||
'@nx/webpack/plugin',
|
|
||||||
(targetName) => ({
|
|
||||||
buildTargetName: 'build',
|
|
||||||
previewTargetName: 'preview',
|
|
||||||
serveStaticTargetName: 'serve-static',
|
|
||||||
serveTargetName: targetName,
|
|
||||||
}),
|
|
||||||
servePostTargetTransformerFactory(migrationContext),
|
|
||||||
createNodesV2,
|
|
||||||
options.project,
|
|
||||||
{ skipProjectFilter: skipProjectFilterFactory(tree) }
|
|
||||||
);
|
|
||||||
|
|
||||||
const migratedProjects =
|
const migratedProjects =
|
||||||
migratedBuildProjects.size +
|
await migrateProjectExecutorsToPlugin<WebpackPluginOptions>(
|
||||||
migratedBuildProjectsLegacy.size +
|
tree,
|
||||||
migratedServeProjects.size +
|
projectGraph,
|
||||||
migratedServeProjectsLegacy.size;
|
'@nx/webpack/plugin',
|
||||||
|
createNodesV2,
|
||||||
|
{
|
||||||
|
buildTargetName: 'build',
|
||||||
|
previewTargetName: 'preview',
|
||||||
|
serveStaticTargetName: 'serve-static',
|
||||||
|
serveTargetName: 'serve',
|
||||||
|
},
|
||||||
|
[
|
||||||
|
{
|
||||||
|
executors: ['@nx/webpack:webpack', '@nrwl/webpack:webpack'],
|
||||||
|
postTargetTransformer:
|
||||||
|
buildPostTargetTransformerFactory(migrationContext),
|
||||||
|
targetPluginOptionMapper: (target) => ({ buildTargetName: target }),
|
||||||
|
skipProjectFilter: skipProjectFilterFactory(tree),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
executors: ['@nx/webpack:dev-server', '@nrwl/webpack:dev-server'],
|
||||||
|
postTargetTransformer:
|
||||||
|
servePostTargetTransformerFactory(migrationContext),
|
||||||
|
targetPluginOptionMapper: (target) => ({ serveTargetName: target }),
|
||||||
|
skipProjectFilter: skipProjectFilterFactory(tree),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
options.project
|
||||||
|
);
|
||||||
|
|
||||||
if (migratedProjects === 0) {
|
if (migratedProjects.size === 0) {
|
||||||
throw new Error('Could not find any targets to migrate.');
|
throw new Error('Could not find any targets to migrate.');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user