@nx/rollup
Version:
300 lines (299 loc) • 15.3 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.withNx = withNx;
const devkit_1 = require("@nx/devkit");
const type_definitions_1 = require("@nx/js/src/plugins/rollup/type-definitions");
const buildable_libs_utils_1 = require("@nx/js/src/utils/buildable-libs-utils");
const ts_solution_setup_1 = require("@nx/js/src/utils/typescript/ts-solution-setup");
const plugin_babel_1 = require("@rollup/plugin-babel");
const plugin_node_resolve_1 = require("@rollup/plugin-node-resolve");
const autoprefixer = require("autoprefixer");
const node_fs_1 = require("node:fs");
const node_path_1 = require("node:path");
const analyze_1 = require("../analyze");
const delete_output_1 = require("../delete-output");
const generate_package_json_1 = require("../package-json/generate-package-json");
const swc_1 = require("../swc");
const get_project_node_1 = require("./get-project-node");
const normalize_options_1 = require("./normalize-options");
// These use require because the ES import isn't correct.
const commonjs = require('@rollup/plugin-commonjs');
const image = require('@rollup/plugin-image');
const json = require('@rollup/plugin-json');
const copy = require('rollup-plugin-copy');
const postcss = require('rollup-plugin-postcss');
const fileExtensions = ['.js', '.jsx', '.ts', '.tsx'];
let ts;
function ensureTypeScript() {
if (!ts) {
try {
ts = require('typescript');
}
catch (e) {
throw new Error('TypeScript is required for the @nx/rollup plugin. Please install it in your workspace.');
}
}
return ts;
}
function withNx(rawOptions, rollupConfig = {},
// Passed by @nx/rollup:rollup executor to previous behavior of remapping tsconfig paths based on buildable dependencies remains intact.
dependencies) {
const finalConfig = { ...rollupConfig };
// Since this is invoked by the executor, the graph has already been created and cached.
const projectNode = (0, get_project_node_1.getProjectNode)();
const projectRoot = (0, node_path_1.join)(devkit_1.workspaceRoot, projectNode.data.root);
// Cannot read in graph during construction, but we only need it during build time.
const projectGraph = global.NX_GRAPH_CREATION
? null
: (0, devkit_1.readCachedProjectGraph)();
// If dependencies are not passed from executor, calculate them from project graph.
if (!dependencies && !global.NX_GRAPH_CREATION) {
const result = (0, buildable_libs_utils_1.calculateProjectBuildableDependencies)(undefined, projectGraph, devkit_1.workspaceRoot, projectNode.name, process.env.NX_TASK_TARGET_TARGET, process.env.NX_TASK_TARGET_CONFIGURATION, true);
dependencies = result.dependencies;
}
const projectSourceRoot = (0, ts_solution_setup_1.getProjectSourceRoot)(projectNode.data);
const options = (0, normalize_options_1.normalizeOptions)(projectNode.data.root, projectSourceRoot, rawOptions);
const useBabel = options.compiler === 'babel';
const useSwc = options.compiler === 'swc';
const tsConfigPath = options.buildLibsFromSource || global.NX_GRAPH_CREATION
? (0, node_path_1.join)(devkit_1.workspaceRoot, options.tsConfig)
: (0, buildable_libs_utils_1.createTmpTsConfig)(options.tsConfig, devkit_1.workspaceRoot, projectRoot, dependencies);
ensureTypeScript();
const tsConfigFile = ts.readConfigFile(tsConfigPath, ts.sys.readFile);
const tsConfig = ts.parseJsonConfigFileContent(tsConfigFile.config, ts.sys, (0, node_path_1.dirname)(tsConfigPath));
if (!options.format || !options.format.length) {
options.format = readCompatibleFormats(tsConfig);
}
if (rollupConfig.input &&
(options.main || options.additionalEntryPoints.length > 0)) {
devkit_1.logger.warn(`Setting "input" in rollup config overrides "main" and "additionalEntryPoints" options.`);
}
// If user provides their own input, override our defaults.
finalConfig.input = rollupConfig.input || createInput(options);
if (options.format) {
if (Array.isArray(rollupConfig.output)) {
throw new Error(`Cannot use Rollup array output option and withNx format option together. Use an object instead.`);
}
if (rollupConfig.output?.format || rollupConfig.output?.dir) {
devkit_1.logger.warn(`"output.dir" and "output.format" are overridden by "withNx".`);
}
finalConfig.output = options.format.map((format) => ({
// These options could be overridden by the user, especially if they use a single format.
entryFileNames: `[name].${format}.js`,
chunkFileNames: `[name].${format}.js`,
...rollupConfig.output,
// Format and dir cannot be overridden by user or else the behavior will break.
format,
dir: global.NX_GRAPH_CREATION
? // Options are not normalized with project root during graph creation due to the lack of project and project root.
// Cannot be joined with workspace root now, but will be handled by @nx/rollup/plugin.
options.outputPath
: (0, node_path_1.join)(devkit_1.workspaceRoot, options.outputPath),
sourcemap: options.sourceMap,
}));
}
let packageJson;
if (!global.NX_GRAPH_CREATION) {
const packageJsonPath = options.project
? (0, node_path_1.join)(devkit_1.workspaceRoot, options.project)
: (0, node_path_1.join)(projectRoot, 'package.json');
if (!(0, node_fs_1.existsSync)(packageJsonPath)) {
throw new Error(`Cannot find ${packageJsonPath}.`);
}
packageJson = (0, devkit_1.readJsonFile)(packageJsonPath);
if (packageJson.type === 'module') {
if (options.format.includes('cjs')) {
devkit_1.logger.warn(`Package type is set to "module" but "cjs" format is included. Going to use "esm" format instead. You can change the package type to "commonjs" or remove type in the package.json file.`);
}
options.format = ['esm'];
}
else if (packageJson.type === 'commonjs') {
if (options.format.includes('esm')) {
devkit_1.logger.warn(`Package type is set to "commonjs" but "esm" format is included. Going to use "cjs" format instead. You can change the package type to "module" or remove type in the package.json file.`);
}
options.format = ['cjs'];
}
}
// User may wish to customize how external behaves by overriding our default.
if (!rollupConfig.external && !global.NX_GRAPH_CREATION) {
const npmDeps = (projectGraph.dependencies[projectNode.name] ?? [])
.filter((d) => d.target.startsWith('npm:'))
.map((d) => d.target.slice(4));
let externalPackages = [
...Object.keys(packageJson.dependencies || {}),
...Object.keys(packageJson.peerDependencies || {}),
]; // If external is set to none, include all dependencies and peerDependencies in externalPackages
if (options.external === 'all') {
externalPackages = externalPackages.concat(npmDeps);
}
else if (Array.isArray(options.external) && options.external.length > 0) {
externalPackages = externalPackages.concat(options.external);
}
externalPackages = [...new Set(externalPackages)];
finalConfig.external = (id) => {
return externalPackages.some((name) => id === name || id.startsWith(`${name}/`));
};
}
if (!global.NX_GRAPH_CREATION) {
// Ensure TypeScript is available before any plugin initialization
ensureTypeScript();
const isTsSolutionSetup = (0, ts_solution_setup_1.isUsingTsSolutionSetup)();
if (isTsSolutionSetup) {
if (options.generatePackageJson) {
throw new Error(`Setting 'generatePackageJson: true' is not supported with the current TypeScript setup. Update the 'package.json' file at the project root as needed and unset the 'generatePackageJson' option.`);
}
if (options.generateExportsField) {
throw new Error(`Setting 'generateExportsField: true' is not supported with the current TypeScript setup. Set 'exports' field in the 'package.json' file at the project root and unset the 'generateExportsField' option.`);
}
}
else {
options.generatePackageJson ??= true;
}
const compilerOptions = createTsCompilerOptions(projectRoot, tsConfig, options, dependencies);
compilerOptions.outDir = Array.isArray(finalConfig.output)
? finalConfig.output[0].dir
: finalConfig.output.dir;
finalConfig.plugins = [
copy({
targets: convertCopyAssetsToRollupOptions(options.outputPath, options.assets),
}),
image(),
json(),
// TypeScript compilation and declaration generation
// TODO(v22): Change default value of useLegacyTypescriptPlugin to false for Nx 22
options.useLegacyTypescriptPlugin !== false
? (() => {
// TODO(v23): Remove in Nx 23
// Show deprecation warning
devkit_1.logger.warn(`rollup-plugin-typescript2 usage is deprecated and will be removed in Nx 23. ` +
`Set 'useLegacyTypescriptPlugin: false' to use the official @rollup/plugin-typescript.`);
return require('rollup-plugin-typescript2')({
check: !options.skipTypeCheck,
tsconfig: tsConfigPath,
tsconfigOverride: {
compilerOptions,
},
});
})()
: (() => {
// @rollup/plugin-typescript needs outDir and declarationDir to match Rollup's output directory
const { outDir, declarationDir, ...tsCompilerOptions } = compilerOptions;
const rollupOutputDir = Array.isArray(finalConfig.output)
? finalConfig.output[0].dir
: finalConfig.output.dir;
return require('@rollup/plugin-typescript')({
tsconfig: tsConfigPath,
compilerOptions: {
...tsCompilerOptions,
outDir: rollupOutputDir,
declarationDir: rollupOutputDir,
},
declaration: true,
declarationMap: !!options.sourceMap,
noEmitOnError: !options.skipTypeCheck,
});
})(),
(0, type_definitions_1.typeDefinitions)({
projectRoot,
}),
postcss({
inject: true,
extract: options.extractCss,
autoModules: true,
plugins: [autoprefixer],
use: {
less: {
javascriptEnabled: options.javascriptEnabled,
},
},
}),
(0, plugin_node_resolve_1.default)({
preferBuiltins: true,
extensions: fileExtensions,
}),
useSwc && (0, swc_1.swc)(),
useBabel &&
(0, plugin_babel_1.getBabelInputPlugin)({
// Lets `@nx/js/babel` preset know that we are packaging.
caller: {
// @ts-ignore
// Ignoring type checks for caller since we have custom attributes
isNxPackage: true,
// Always target esnext and let rollup handle cjs
supportsStaticESM: true,
isModern: true,
},
cwd: (0, node_path_1.join)(devkit_1.workspaceRoot, projectSourceRoot),
rootMode: options.babelUpwardRootMode ? 'upward' : undefined,
babelrc: true,
extensions: fileExtensions,
babelHelpers: 'bundled',
skipPreflightCheck: true, // pre-flight check may yield false positives and also slows down the build
exclude: /node_modules/,
}),
commonjs(),
(0, analyze_1.analyze)(),
options.generatePackageJson && (0, generate_package_json_1.generatePackageJson)(options, packageJson),
].filter(Boolean);
if (Array.isArray(rollupConfig.plugins)) {
finalConfig.plugins.push(...rollupConfig.plugins);
}
if (options.deleteOutputPath) {
finalConfig.plugins.push((0, delete_output_1.deleteOutput)({
dirs: Array.isArray(finalConfig.output)
? finalConfig.output.map((o) => o.dir)
: [finalConfig.output.dir],
}));
}
}
return finalConfig;
}
function createInput(options) {
// During graph creation, these input entries don't affect target configuration, so we can skip them.
// If convert-to-inferred generator is used, and project uses configurations, some options like main might be missing from default options.
if (global.NX_GRAPH_CREATION)
return {};
const mainEntryFileName = options.outputFileName || options.main;
const input = {};
input[(0, node_path_1.parse)(mainEntryFileName).name] = (0, devkit_1.normalizePath)((0, node_path_1.join)(devkit_1.workspaceRoot, options.main));
options.additionalEntryPoints?.forEach((entry) => {
input[(0, node_path_1.parse)(entry).name] = (0, devkit_1.normalizePath)((0, node_path_1.join)(devkit_1.workspaceRoot, entry));
});
return input;
}
function createTsCompilerOptions(projectRoot, config, options, dependencies) {
const compilerOptionPaths = (0, buildable_libs_utils_1.computeCompilerOptionsPaths)(config, dependencies ?? []);
const compilerOptions = {
rootDir: projectRoot,
allowJs: options.allowJs,
declaration: true,
paths: compilerOptionPaths,
};
ensureTypeScript();
if (config.options.module === ts.ModuleKind.CommonJS) {
compilerOptions['module'] = 'ESNext';
}
if (options.compiler === 'swc') {
compilerOptions['emitDeclarationOnly'] = true;
}
return compilerOptions;
}
function convertCopyAssetsToRollupOptions(outputPath, assets) {
return assets
? assets.map((a) => ({
src: (0, node_path_1.join)(a.input, a.glob).replace(/\\/g, '/'),
dest: (0, node_path_1.join)(devkit_1.workspaceRoot, outputPath, a.output).replace(/\\/g, '/'),
}))
: undefined;
}
function readCompatibleFormats(config) {
ensureTypeScript();
switch (config.options.module) {
case ts.ModuleKind.CommonJS:
case ts.ModuleKind.UMD:
case ts.ModuleKind.AMD:
return ['cjs'];
default:
return ['esm'];
}
}