<!-- 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` --> ## 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 #
162 lines
4.6 KiB
TypeScript
162 lines
4.6 KiB
TypeScript
import { projectGraphCacheDirectory } from 'nx/src/utils/cache-directory';
|
|
import { basename, dirname, join } from 'path';
|
|
import { existsSync, readdirSync } from 'fs';
|
|
import {
|
|
type TargetConfiguration,
|
|
type CreateDependencies,
|
|
type CreateNodes,
|
|
readJsonFile,
|
|
writeJsonFile,
|
|
detectPackageManager,
|
|
CreateNodesContext,
|
|
joinPathFragments,
|
|
} from '@nx/devkit';
|
|
import { calculateHashForCreateNodes } from '@nx/devkit/src/utils/calculate-hash-for-create-nodes';
|
|
import { getLockFileName } from '@nx/js';
|
|
import { getNamedInputs } from '@nx/devkit/src/utils/get-named-inputs';
|
|
import { type RollupOptions } from 'rollup';
|
|
|
|
// This import causes an error due to the module resolution used. If we switch to bundler or nodenext in the future we remove this ignore.
|
|
// @ts-ignore
|
|
import { loadConfigFile } from 'rollup/loadConfigFile';
|
|
|
|
const cachePath = join(projectGraphCacheDirectory, 'rollup.hash');
|
|
const targetsCache = readTargetsCache();
|
|
|
|
function readTargetsCache(): Record<
|
|
string,
|
|
Record<string, TargetConfiguration>
|
|
> {
|
|
return existsSync(cachePath) ? readJsonFile(cachePath) : {};
|
|
}
|
|
|
|
function writeTargetsToCache() {
|
|
const oldCache = readTargetsCache();
|
|
writeJsonFile(cachePath, {
|
|
...oldCache,
|
|
...targetsCache,
|
|
});
|
|
}
|
|
|
|
export const createDependencies: CreateDependencies = () => {
|
|
writeTargetsToCache();
|
|
return [];
|
|
};
|
|
|
|
export interface RollupPluginOptions {
|
|
buildTargetName?: string;
|
|
}
|
|
|
|
export const createNodes: CreateNodes<RollupPluginOptions> = [
|
|
'**/rollup.config.{js,cjs,mjs}',
|
|
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 = 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,
|
|
options: RollupPluginOptions,
|
|
context: CreateNodesContext
|
|
): Promise<Record<string, TargetConfiguration>> {
|
|
const namedInputs = getNamedInputs(projectRoot, context);
|
|
const rollupConfig = (
|
|
(await loadConfigFile(
|
|
joinPathFragments(context.workspaceRoot, configFilePath),
|
|
{},
|
|
true // Enable watch mode so that rollup properly reloads config files without reusing a cached version
|
|
)) as { options: RollupOptions[] }
|
|
).options;
|
|
const outputs = getOutputs(rollupConfig, projectRoot);
|
|
|
|
const targets: Record<string, TargetConfiguration> = {};
|
|
targets[options.buildTargetName] = {
|
|
command: `rollup -c ${basename(configFilePath)}`,
|
|
options: { cwd: projectRoot },
|
|
cache: true,
|
|
dependsOn: [`^${options.buildTargetName}`],
|
|
inputs: [
|
|
...('production' in namedInputs
|
|
? ['production', '^production']
|
|
: ['default', '^default']),
|
|
{ externalDependencies: ['rollup'] },
|
|
],
|
|
outputs,
|
|
};
|
|
return targets;
|
|
}
|
|
|
|
function getOutputs(
|
|
rollupConfigs: RollupOptions[],
|
|
projectRoot: string
|
|
): string[] {
|
|
const outputs = new Set<string>();
|
|
for (const rollupConfig of rollupConfigs) {
|
|
if (rollupConfig.output) {
|
|
const rollupConfigOutputs = [];
|
|
if (Array.isArray(rollupConfig.output)) {
|
|
rollupConfigOutputs.push(...rollupConfig.output);
|
|
} else {
|
|
rollupConfigOutputs.push(rollupConfig.output);
|
|
}
|
|
|
|
for (const output of rollupConfigOutputs) {
|
|
const outputPathFromConfig = output.dir
|
|
? output.dir
|
|
: output.file
|
|
? dirname(output.file)
|
|
: 'dist';
|
|
const outputPath =
|
|
projectRoot === '.'
|
|
? joinPathFragments(`{workspaceRoot}`, outputPathFromConfig)
|
|
: joinPathFragments(
|
|
`{workspaceRoot}`,
|
|
projectRoot,
|
|
outputPathFromConfig
|
|
);
|
|
outputs.add(outputPath);
|
|
}
|
|
}
|
|
}
|
|
return Array.from(outputs);
|
|
}
|
|
|
|
function normalizeOptions(options: RollupPluginOptions) {
|
|
options ??= {};
|
|
options.buildTargetName ??= 'build';
|
|
|
|
return options;
|
|
}
|