feat(bundling): add createNodesV2 for rollup plugin (#28090)

<!-- 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 -->
There is no implementation for `createNodesV2`.

## Expected Behavior
<!-- This is the behavior we should expect with the changes in this PR
-->
There should be an implementation for `createNodesV2`.

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

Fixes #
This commit is contained in:
Phillip Barta 2024-11-04 16:07:49 +01:00 committed by GitHub
parent 7ba7f3e798
commit 38448da34f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 217 additions and 107 deletions

View File

@ -1 +1,5 @@
export { createNodes, RollupPluginOptions } from './src/plugins/plugin';
export {
createNodes,
createNodesV2,
RollupPluginOptions,
} from './src/plugins/plugin';

View File

@ -1,70 +1,110 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`@nx/rollup/plugin non-root project should create nodes 1`] = `
{
"projects": {
"mylib": {
"root": "mylib",
"targets": {
"build": {
"cache": true,
"command": "rollup -c rollup.config.js",
"dependsOn": [
"^build",
],
"inputs": [
"production",
"^production",
{
"externalDependencies": [
"rollup",
[
[
"mylib/rollup.config.js",
{
"projects": {
"mylib": {
"root": "mylib",
"targets": {
"build": {
"cache": true,
"command": "rollup -c rollup.config.js",
"dependsOn": [
"^build",
],
"inputs": [
"production",
"^production",
{
"externalDependencies": [
"rollup",
],
},
],
"metadata": {
"description": "Run Rollup",
"help": {
"command": "npx rollup --help",
"example": {
"options": {
"sourcemap": true,
"watch": true,
},
},
},
"technologies": [
"rollup",
],
},
"options": {
"cwd": "mylib",
},
"outputs": [
"{workspaceRoot}/mylib/build",
"{workspaceRoot}/mylib/dist",
],
},
],
"options": {
"cwd": "mylib",
},
"outputs": [
"{workspaceRoot}/mylib/build",
"{workspaceRoot}/mylib/dist",
],
},
},
},
},
}
],
]
`;
exports[`@nx/rollup/plugin root project should create nodes 1`] = `
{
"projects": {
".": {
"root": ".",
"targets": {
"build": {
"cache": true,
"command": "rollup -c rollup.config.js",
"dependsOn": [
"^build",
],
"inputs": [
"production",
"^production",
{
"externalDependencies": [
"rollup",
[
[
"rollup.config.js",
{
"projects": {
".": {
"root": ".",
"targets": {
"build": {
"cache": true,
"command": "rollup -c rollup.config.js",
"dependsOn": [
"^build",
],
"inputs": [
"production",
"^production",
{
"externalDependencies": [
"rollup",
],
},
],
"metadata": {
"description": "Run Rollup",
"help": {
"command": "npx rollup --help",
"example": {
"options": {
"sourcemap": true,
"watch": true,
},
},
},
"technologies": [
"rollup",
],
},
"options": {
"cwd": ".",
},
"outputs": [
"{workspaceRoot}/dist",
],
},
],
"options": {
"cwd": ".",
},
"outputs": [
"{workspaceRoot}/dist",
],
},
},
},
},
}
],
]
`;

View File

@ -1,5 +1,5 @@
import { type CreateNodesContext } from '@nx/devkit';
import { createNodes } from './plugin';
import { createNodesV2 } from './plugin';
import { TempFs } from 'nx/src/internal-testing-utils/temp-fs';
// Jest 29 does not support dynamic import() unless --experimental-vm-modules is set.
@ -11,7 +11,7 @@ jest.mock('rollup/loadConfigFile', () => {
});
describe('@nx/rollup/plugin', () => {
let createNodesFunction = createNodes[1];
let createNodesFunction = createNodesV2[1];
let context: CreateNodesContext;
let cwd = process.cwd();
@ -77,7 +77,7 @@ describe('@nx/rollup/plugin', () => {
it('should create nodes', async () => {
// ACT
const nodes = await createNodesFunction(
'rollup.config.js',
['rollup.config.js'],
{
buildTargetName: 'build',
},
@ -154,7 +154,7 @@ describe('@nx/rollup/plugin', () => {
it('should create nodes', async () => {
// ACT
const nodes = await createNodesFunction(
'mylib/rollup.config.js',
['mylib/rollup.config.js'],
{
buildTargetName: 'build',
},

View File

@ -5,8 +5,12 @@ import {
type CreateDependencies,
type CreateNodes,
CreateNodesContext,
createNodesFromFiles,
CreateNodesV2,
detectPackageManager,
getPackageManagerCommand,
joinPathFragments,
logger,
readJsonFile,
type TargetConfiguration,
writeJsonFile,
@ -15,27 +19,27 @@ import { calculateHashForCreateNodes } from '@nx/devkit/src/utils/calculate-hash
import { getLockFileName } from '@nx/js';
import { getNamedInputs } from '@nx/devkit/src/utils/get-named-inputs';
import { type RollupOptions } from 'rollup';
import { hashObject } from 'nx/src/hasher/file-hasher';
const cachePath = join(workspaceDataDirectory, 'rollup.hash');
const targetsCache = readTargetsCache();
const pmc = getPackageManagerCommand();
function readTargetsCache(): Record<
string,
Record<string, TargetConfiguration>
> {
function readTargetsCache(
cachePath: string
): Record<string, Record<string, TargetConfiguration>> {
return existsSync(cachePath) ? readJsonFile(cachePath) : {};
}
function writeTargetsToCache() {
const oldCache = readTargetsCache();
writeJsonFile(cachePath, {
...oldCache,
...targetsCache,
});
function writeTargetsToCache(
cachePath: string,
results: Record<string, Record<string, TargetConfiguration>>
) {
writeJsonFile(cachePath, results);
}
/**
* @deprecated The 'createDependencies' function is now a no-op. This functionality is included in 'createNodesV2'.
*/
export const createDependencies: CreateDependencies = () => {
writeTargetsToCache();
return [];
};
@ -43,47 +47,95 @@ export interface RollupPluginOptions {
buildTargetName?: string;
}
const rollupConfigGlob = '**/rollup.config.{js,cjs,mjs}';
export const createNodes: CreateNodes<RollupPluginOptions> = [
'**/rollup.config.{js,cjs,mjs}',
rollupConfigGlob,
async (configFilePath, options, context) => {
const projectRoot = dirname(configFilePath);
const fullyQualifiedProjectRoot = join(context.workspaceRoot, projectRoot);
// Do not create a project if package.json and project.json do not exist
const siblingFiles = readdirSync(fullyQualifiedProjectRoot);
if (
!siblingFiles.includes('package.json') &&
!siblingFiles.includes('project.json')
) {
return {};
}
options = normalizeOptions(options);
const hash = await calculateHashForCreateNodes(
projectRoot,
options,
context,
[getLockFileName(detectPackageManager(context.workspaceRoot))]
logger.warn(
'`createNodes` is deprecated. Update your plugin to utilize createNodesV2 instead. In Nx 20, this will change to the createNodesV2 API.'
);
targetsCache[hash] ??= await buildRollupTarget(
return createNodesInternal(
configFilePath,
projectRoot,
options,
context
normalizeOptions(options),
context,
{}
);
return {
projects: {
[projectRoot]: {
root: projectRoot,
targets: targetsCache[hash],
},
},
};
},
];
export const createNodesV2: CreateNodesV2<RollupPluginOptions> = [
rollupConfigGlob,
async (configFilePaths, options, context) => {
const normalizedOptions = normalizeOptions(options);
const optionsHash = hashObject(normalizedOptions);
const cachePath = join(
workspaceDataDirectory,
`rollup-${optionsHash}.hash`
);
const targetsCache = readTargetsCache(cachePath);
try {
return await createNodesFromFiles(
(configFile, _, context) =>
createNodesInternal(
configFile,
normalizedOptions,
context,
targetsCache
),
configFilePaths,
normalizedOptions,
context
);
} finally {
writeTargetsToCache(cachePath, targetsCache);
}
},
];
async function createNodesInternal(
configFilePath: string,
options: Required<RollupPluginOptions>,
context: CreateNodesContext,
targetsCache: Record<string, Record<string, TargetConfiguration>>
) {
const projectRoot = dirname(configFilePath);
const fullyQualifiedProjectRoot = join(context.workspaceRoot, projectRoot);
// Do not create a project if package.json and project.json do not exist
const siblingFiles = readdirSync(fullyQualifiedProjectRoot);
if (
!siblingFiles.includes('package.json') &&
!siblingFiles.includes('project.json')
) {
return {};
}
const hash = await calculateHashForCreateNodes(
projectRoot,
options,
context,
[getLockFileName(detectPackageManager(context.workspaceRoot))]
);
targetsCache[hash] ??= await buildRollupTarget(
configFilePath,
projectRoot,
options,
context
);
return {
projects: {
[projectRoot]: {
root: projectRoot,
targets: targetsCache[hash],
},
},
};
}
async function buildRollupTarget(
configFilePath: string,
projectRoot: string,
@ -134,6 +186,19 @@ async function buildRollupTarget(
{ externalDependencies: ['rollup'] },
],
outputs,
metadata: {
technologies: ['rollup'],
description: 'Run Rollup',
help: {
command: `${pmc.exec} rollup --help`,
example: {
options: {
sourcemap: true,
watch: true,
},
},
},
},
};
return targets;
}
@ -173,9 +238,10 @@ function getOutputs(
return Array.from(outputs);
}
function normalizeOptions(options: RollupPluginOptions) {
options ??= {};
options.buildTargetName ??= 'build';
return options;
function normalizeOptions(
options: RollupPluginOptions
): Required<RollupPluginOptions> {
return {
buildTargetName: options.buildTargetName ?? 'build',
};
}