feat(js): support esbuild and swc bundlers with the new ts solution config setup (#28409)

<!-- 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 #

---------

Co-authored-by: Jack Hsu <jack.hsu@gmail.com>
This commit is contained in:
Leosvel Pérez Espinosa 2024-10-14 09:30:43 +02:00 committed by GitHub
parent 74bdc583b9
commit db47dc30a5
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
9 changed files with 240 additions and 219 deletions

View File

@ -24,6 +24,8 @@
"description": "The bundler to use. Choosing 'none' means this library is not buildable.", "description": "The bundler to use. Choosing 'none' means this library is not buildable.",
"type": "string", "type": "string",
"enum": ["swc", "tsc", "rollup", "vite", "esbuild", "none"], "enum": ["swc", "tsc", "rollup", "vite", "esbuild", "none"],
"default": "tsc",
"x-prompt": "Which bundler would you like to use to build the library? Choose 'none' to skip build setup.",
"x-priority": "important" "x-priority": "important"
}, },
"linter": { "linter": {

View File

@ -48,6 +48,7 @@ describe('EsBuild Plugin', () => {
private: true, private: true,
type: 'commonjs', type: 'commonjs',
main: './index.cjs', main: './index.cjs',
typings: './index.d.ts',
dependencies: {}, dependencies: {},
}); });

View File

@ -1,30 +1,39 @@
import { joinPathFragments, logger, type ExecutorContext } from '@nx/devkit';
import { readTsConfig } from '@nx/js';
import { isUsingTsSolutionSetup } from '@nx/js/src/utils/typescript/ts-solution-setup';
import * as esbuild from 'esbuild';
import * as fs from 'fs'; import * as fs from 'fs';
import * as path from 'path'; import * as path from 'path';
import { import * as pc from 'picocolors';
import type {
EsBuildExecutorOptions, EsBuildExecutorOptions,
NormalizedEsBuildExecutorOptions, NormalizedEsBuildExecutorOptions,
} from '../schema'; } from '../schema';
import { ExecutorContext, joinPathFragments, logger } from '@nx/devkit';
import * as pc from 'picocolors';
import * as esbuild from 'esbuild';
import { readTsConfig } from '@nx/js';
export function normalizeOptions( export function normalizeOptions(
options: EsBuildExecutorOptions, options: EsBuildExecutorOptions,
context: ExecutorContext context: ExecutorContext
): NormalizedEsBuildExecutorOptions { ): NormalizedEsBuildExecutorOptions {
const isTsSolutionSetup = isUsingTsSolutionSetup();
if (isTsSolutionSetup && options.generatePackageJson) {
throw new Error(
`Setting 'generatePackageJson: true' is not allowed with the current TypeScript setup. Please update the 'package.json' file at the project root as needed and don't set the 'generatePackageJson' option.`
);
}
const tsConfig = readTsConfig(options.tsConfig); const tsConfig = readTsConfig(options.tsConfig);
// If we're not generating package.json file, then copy it as-is as an asset. // If we're not generating package.json file, then copy it as-is as an asset when not using ts solution setup.
const assets = options.generatePackageJson const assets =
? options.assets options.generatePackageJson || isTsSolutionSetup
: [ ? options.assets
...options.assets, : [
joinPathFragments( ...options.assets,
context.projectGraph.nodes[context.projectName].data.root, joinPathFragments(
'package.json' context.projectGraph.nodes[context.projectName].data.root,
), 'package.json'
]; ),
];
if (!options.bundle && options.thirdParty) { if (!options.bundle && options.thirdParty) {
logger.info( logger.info(
@ -33,7 +42,7 @@ export function normalizeOptions(
'bundle:false' 'bundle:false'
)} and ${pc.bold( )} and ${pc.bold(
'thirdParty:true' 'thirdParty:true'
)}. Your package.json depedencies might not be generated correctly so we added an update ${pc.bold( )}. Your package.json dependencies might not be generated correctly so we added an update ${pc.bold(
'thirdParty:false' 'thirdParty:false'
)}` )}`
) )
@ -42,8 +51,6 @@ export function normalizeOptions(
const thirdParty = !options.bundle ? false : options.thirdParty; const thirdParty = !options.bundle ? false : options.thirdParty;
const { root: projectRoot } =
context.projectsConfigurations.projects[context.projectName];
const declarationRootDir = options.declarationRootDir const declarationRootDir = options.declarationRootDir
? path.join(context.root, options.declarationRootDir) ? path.join(context.root, options.declarationRootDir)
: undefined; : undefined;

View File

@ -1,9 +1,10 @@
import { ExecutorContext, readJsonFile } from '@nx/devkit'; import { ExecutorContext, output, readJsonFile } from '@nx/devkit';
import { assetGlobsToFiles, FileInputOutput } from '../../utils/assets/assets';
import { sync as globSync } from 'fast-glob'; import { sync as globSync } from 'fast-glob';
import { rmSync } from 'node:fs'; import { rmSync } from 'node:fs';
import { dirname, join, relative, resolve, normalize } from 'path'; import { dirname, join, normalize, relative, resolve } from 'path';
import { copyAssets } from '../../utils/assets'; import { copyAssets } from '../../utils/assets';
import { assetGlobsToFiles, FileInputOutput } from '../../utils/assets/assets';
import type { DependentBuildableProjectNode } from '../../utils/buildable-libs-utils';
import { checkDependencies } from '../../utils/check-dependencies'; import { checkDependencies } from '../../utils/check-dependencies';
import { import {
getHelperDependency, getHelperDependency,
@ -13,16 +14,20 @@ import {
handleInliningBuild, handleInliningBuild,
isInlineGraphEmpty, isInlineGraphEmpty,
postProcessInlinedDependencies, postProcessInlinedDependencies,
type InlineProjectGraph,
} from '../../utils/inline'; } from '../../utils/inline';
import { copyPackageJson } from '../../utils/package-json'; import {
copyPackageJson,
type CopyPackageJsonResult,
} from '../../utils/package-json';
import { import {
NormalizedSwcExecutorOptions, NormalizedSwcExecutorOptions,
SwcCliOptions,
SwcExecutorOptions, SwcExecutorOptions,
} from '../../utils/schema'; } from '../../utils/schema';
import { compileSwc, compileSwcWatch } from '../../utils/swc/compile-swc'; import { compileSwc, compileSwcWatch } from '../../utils/swc/compile-swc';
import { getSwcrcPath } from '../../utils/swc/get-swcrc-path'; import { getSwcrcPath } from '../../utils/swc/get-swcrc-path';
import { generateTmpSwcrc } from '../../utils/swc/inline'; import { generateTmpSwcrc } from '../../utils/swc/inline';
import { isUsingTsSolutionSetup } from '../../utils/typescript/ts-solution-setup';
function normalizeOptions( function normalizeOptions(
options: SwcExecutorOptions, options: SwcExecutorOptions,
@ -30,6 +35,25 @@ function normalizeOptions(
sourceRoot: string, sourceRoot: string,
projectRoot: string projectRoot: string
): NormalizedSwcExecutorOptions { ): NormalizedSwcExecutorOptions {
const isTsSolutionSetup = isUsingTsSolutionSetup();
if (isTsSolutionSetup) {
if (options.generateLockfile) {
throw new Error(
`Setting 'generateLockfile: true' is not supported with the current TypeScript setup. Unset the 'generateLockfile' option and try again.`
);
}
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.`
);
}
if (options.additionalEntryPoints?.length) {
throw new Error(
`Setting 'additionalEntryPoints' is not supported with the current TypeScript setup. Set additional entry points in the 'package.json' file at the project root and unset the 'additionalEntryPoints' option.`
);
}
}
const outputPath = join(root, options.outputPath); const outputPath = join(root, options.outputPath);
if (options.skipTypeCheck == null) { if (options.skipTypeCheck == null) {
@ -87,6 +111,7 @@ function normalizeOptions(
tsConfig: join(root, options.tsConfig), tsConfig: join(root, options.tsConfig),
swcCliOptions, swcCliOptions,
tmpSwcrcPath, tmpSwcrcPath,
isTsSolutionSetup: isTsSolutionSetup,
} as NormalizedSwcExecutorOptions; } as NormalizedSwcExecutorOptions;
} }
@ -97,56 +122,61 @@ export async function* swcExecutor(
const { sourceRoot, root } = const { sourceRoot, root } =
context.projectsConfigurations.projects[context.projectName]; context.projectsConfigurations.projects[context.projectName];
const options = normalizeOptions(_options, context.root, sourceRoot, root); const options = normalizeOptions(_options, context.root, sourceRoot, root);
const { tmpTsConfig, dependencies } = checkDependencies(
context,
options.tsConfig
);
if (tmpTsConfig) { let swcHelperDependency: DependentBuildableProjectNode;
options.tsConfig = tmpTsConfig; let inlineProjectGraph: InlineProjectGraph;
} if (!options.isTsSolutionSetup) {
const { tmpTsConfig, dependencies } = checkDependencies(
context,
options.tsConfig
);
const swcHelperDependency = getHelperDependency( if (tmpTsConfig) {
HelperDependency.swc, options.tsConfig = tmpTsConfig;
options.swcCliOptions.swcrcPath,
dependencies,
context.projectGraph
);
if (swcHelperDependency) {
dependencies.push(swcHelperDependency);
}
const inlineProjectGraph = handleInliningBuild(
context,
options,
options.tsConfig
);
if (!isInlineGraphEmpty(inlineProjectGraph)) {
if (options.stripLeadingPaths) {
throw new Error(`Cannot use --strip-leading-paths with inlining.`);
} }
options.projectRoot = '.'; // set to root of workspace to include other libs for type check swcHelperDependency = getHelperDependency(
HelperDependency.swc,
// remap paths for SWC compilation
options.inline = true;
options.swcCliOptions.swcCwd = '.';
options.swcCliOptions.srcPath = options.swcCliOptions.swcCwd;
options.swcCliOptions.destPath = join(
options.swcCliOptions.destPath.split(normalize('../')).at(-1),
options.swcCliOptions.srcPath
);
// tmp swcrc with dependencies to exclude
// - buildable libraries
// - other libraries that are not dependent on the current project
options.swcCliOptions.swcrcPath = generateTmpSwcrc(
inlineProjectGraph,
options.swcCliOptions.swcrcPath, options.swcCliOptions.swcrcPath,
options.tmpSwcrcPath dependencies,
context.projectGraph
); );
if (swcHelperDependency) {
dependencies.push(swcHelperDependency);
}
inlineProjectGraph = handleInliningBuild(
context,
options,
options.tsConfig
);
if (!isInlineGraphEmpty(inlineProjectGraph)) {
if (options.stripLeadingPaths) {
throw new Error(`Cannot use --strip-leading-paths with inlining.`);
}
options.projectRoot = '.'; // set to root of workspace to include other libs for type check
// remap paths for SWC compilation
options.inline = true;
options.swcCliOptions.swcCwd = '.';
options.swcCliOptions.srcPath = options.swcCliOptions.swcCwd;
options.swcCliOptions.destPath = join(
options.swcCliOptions.destPath.split(normalize('../')).at(-1),
options.swcCliOptions.srcPath
);
// tmp swcrc with dependencies to exclude
// - buildable libraries
// - other libraries that are not dependent on the current project
options.swcCliOptions.swcrcPath = generateTmpSwcrc(
inlineProjectGraph,
options.swcCliOptions.swcrcPath,
options.tmpSwcrcPath
);
}
} }
function determineModuleFormatFromSwcrc( function determineModuleFormatFromSwcrc(
@ -163,16 +193,19 @@ export async function* swcExecutor(
return yield* compileSwcWatch(context, options, async () => { return yield* compileSwcWatch(context, options, async () => {
const assetResult = await copyAssets(options, context); const assetResult = await copyAssets(options, context);
const packageJsonResult = await copyPackageJson( let packageJsonResult: CopyPackageJsonResult;
{ if (!options.isTsSolutionSetup) {
...options, packageJsonResult = await copyPackageJson(
additionalEntryPoints: createEntryPoints(options, context), {
format: [ ...options,
determineModuleFormatFromSwcrc(options.swcCliOptions.swcrcPath), additionalEntryPoints: createEntryPoints(options, context),
], format: [
}, determineModuleFormatFromSwcrc(options.swcCliOptions.swcrcPath),
context ],
); },
context
);
}
removeTmpSwcrc(options.swcCliOptions.swcrcPath); removeTmpSwcrc(options.swcCliOptions.swcrcPath);
disposeFn = () => { disposeFn = () => {
assetResult?.stop(); assetResult?.stop();
@ -182,23 +215,25 @@ export async function* swcExecutor(
} else { } else {
return yield compileSwc(context, options, async () => { return yield compileSwc(context, options, async () => {
await copyAssets(options, context); await copyAssets(options, context);
await copyPackageJson( if (!options.isTsSolutionSetup) {
{ await copyPackageJson(
...options, {
additionalEntryPoints: createEntryPoints(options, context), ...options,
format: [ additionalEntryPoints: createEntryPoints(options, context),
determineModuleFormatFromSwcrc(options.swcCliOptions.swcrcPath), format: [
], determineModuleFormatFromSwcrc(options.swcCliOptions.swcrcPath),
extraDependencies: swcHelperDependency ? [swcHelperDependency] : [], ],
}, extraDependencies: swcHelperDependency ? [swcHelperDependency] : [],
context },
); context
);
postProcessInlinedDependencies(
options.outputPath,
options.originalProjectRoot,
inlineProjectGraph
);
}
removeTmpSwcrc(options.swcCliOptions.swcrcPath); removeTmpSwcrc(options.swcCliOptions.swcrcPath);
postProcessInlinedDependencies(
options.outputPath,
options.originalProjectRoot,
inlineProjectGraph
);
}); });
} }
} }

View File

@ -1561,6 +1561,7 @@ describe('lib', () => {
"name": "@proj/my-lib", "name": "@proj/my-lib",
"nx": { "nx": {
"name": "my-lib", "name": "my-lib",
"sourceRoot": "my-lib/src",
}, },
"private": true, "private": true,
"version": "0.0.1", "version": "0.0.1",

View File

@ -266,31 +266,6 @@ async function configureProject(
updateNxJson(tree, nxJson); updateNxJson(tree, nxJson);
} }
if (!options.useProjectJson) {
// we create a cleaner project configuration for the package.json file
const projectConfiguration: ProjectConfiguration = {
root: options.projectRoot,
};
if (options.name !== options.importPath) {
// if the name is different than the package.json name, we need to set
// the proper name in the configuration
projectConfiguration.name = options.name;
}
if (options.parsedTags?.length) {
projectConfiguration.tags = options.parsedTags;
}
if (options.publishable) {
await addProjectToNxReleaseConfig(tree, options, projectConfiguration);
}
updateProjectConfiguration(tree, options.name, projectConfiguration);
return;
}
const projectConfiguration: ProjectConfiguration = { const projectConfiguration: ProjectConfiguration = {
root: options.projectRoot, root: options.projectRoot,
sourceRoot: joinPathFragments(options.projectRoot, 'src'), sourceRoot: joinPathFragments(options.projectRoot, 'src'),
@ -300,34 +275,42 @@ async function configureProject(
}; };
if ( if (
options.bundler && options.config !== 'npm-scripts' &&
options.bundler !== 'none' && (options.bundler === 'swc' ||
options.config !== 'npm-scripts' options.bundler === 'esbuild' ||
(!options.isUsingTsSolutionConfig && options.bundler === 'tsc'))
) { ) {
if (options.bundler !== 'rollup') { const outputPath = getOutputPath(options);
const outputPath = getOutputPath(options); const executor = getBuildExecutor(options.bundler);
const executor = getBuildExecutor(options.bundler); addBuildTargetDefaults(tree, executor);
addBuildTargetDefaults(tree, executor);
projectConfiguration.targets.build = { projectConfiguration.targets.build = {
executor, executor,
outputs: ['{options.outputPath}'], outputs: ['{options.outputPath}'],
options: { options: {
outputPath, outputPath,
main: main: `${options.projectRoot}/src/index` + (options.js ? '.js' : '.ts'),
`${options.projectRoot}/src/index` + (options.js ? '.js' : '.ts'), tsConfig: `${options.projectRoot}/tsconfig.lib.json`,
tsConfig: `${options.projectRoot}/tsconfig.lib.json`, },
assets: [], };
},
}; if (options.bundler === 'esbuild') {
projectConfiguration.targets.build.options.format = ['cjs'];
}
if (options.bundler === 'swc' && options.skipTypeCheck) {
projectConfiguration.targets.build.options.skipTypeCheck = true;
}
if (options.isUsingTsSolutionConfig) {
if (options.bundler === 'esbuild') {
projectConfiguration.targets.build.options.declarationRootDir = `${options.projectRoot}/src`;
}
} else {
projectConfiguration.targets.build.options.assets = [];
if (options.bundler === 'esbuild') { if (options.bundler === 'esbuild') {
projectConfiguration.targets.build.options.generatePackageJson = true; projectConfiguration.targets.build.options.generatePackageJson = true;
projectConfiguration.targets.build.options.format = ['cjs'];
}
if (options.bundler === 'swc' && options.skipTypeCheck) {
projectConfiguration.targets.build.options.skipTypeCheck = true;
} }
if (!options.minimal) { if (!options.minimal) {
@ -337,8 +320,10 @@ async function configureProject(
); );
} }
} }
}
if (options.publishable) { if (options.publishable) {
if (!options.isUsingTsSolutionConfig) {
const packageRoot = joinPathFragments( const packageRoot = joinPathFragments(
defaultOutputDirectory, defaultOutputDirectory,
'{projectRoot}' '{projectRoot}'
@ -361,12 +346,22 @@ async function configureProject(
}, },
}, },
}; };
await addProjectToNxReleaseConfig(tree, options, projectConfiguration);
} }
await addProjectToNxReleaseConfig(tree, options, projectConfiguration);
} }
if (options.config === 'workspace' || options.config === 'project') { if (!options.useProjectJson) {
// we want the package.json as clean as possible, with the bare minimum
if (!projectConfiguration.tags?.length) {
delete projectConfiguration.tags;
}
// automatically inferred as `library`
delete projectConfiguration.projectType;
// empty targets are cleaned up automatically by `updateProjectConfiguration`
updateProjectConfiguration(tree, options.name, projectConfiguration);
} else if (options.config === 'workspace' || options.config === 'project') {
addProjectConfiguration(tree, options.name, projectConfiguration); addProjectConfiguration(tree, options.name, projectConfiguration);
} else { } else {
addProjectConfiguration(tree, options.name, { addProjectConfiguration(tree, options.name, {
@ -716,30 +711,6 @@ async function normalizeOptions(
const isUsingTsSolutionConfig = isUsingTsSolutionSetup(tree); const isUsingTsSolutionConfig = isUsingTsSolutionSetup(tree);
if (isUsingTsSolutionConfig) { if (isUsingTsSolutionConfig) {
if (options.bundler === 'esbuild' || options.bundler === 'swc') {
throw new Error(
`Cannot use the "${options.bundler}" bundler when using the @nx/js/typescript plugin.`
);
}
if (options.bundler === undefined && options.compiler === undefined) {
options.bundler = await promptWhenInteractive<{ bundler: Bundler }>(
{
type: 'select',
name: 'bundler',
message: `Which bundler would you like to use to build the library? Choose 'none' to skip build setup.`,
choices: [
{ name: 'tsc' },
{ name: 'rollup' },
{ name: 'vite' },
{ name: 'none' },
],
initial: 0,
},
{ bundler: 'tsc' }
).then(({ bundler }) => bundler);
}
options.linter ??= await promptWhenInteractive<{ options.linter ??= await promptWhenInteractive<{
linter: 'none' | 'eslint'; linter: 'none' | 'eslint';
}>( }>(
@ -766,50 +737,6 @@ async function normalizeOptions(
{ unitTestRunner: 'none' } { unitTestRunner: 'none' }
).then(({ unitTestRunner }) => unitTestRunner); ).then(({ unitTestRunner }) => unitTestRunner);
} else { } else {
if (options.bundler === undefined && options.compiler === undefined) {
options.bundler = await promptWhenInteractive<{ bundler: Bundler }>(
{
type: 'select',
name: 'bundler',
message: `Which bundler would you like to use to build the library? Choose 'none' to skip build setup.`,
choices: [
{ name: 'swc' },
{ name: 'tsc' },
{ name: 'rollup' },
{ name: 'vite' },
{ name: 'esbuild' },
{ name: 'none' },
],
initial: 1,
},
{ bundler: 'tsc' }
).then(({ bundler }) => bundler);
} else {
/**
* We are deprecating the compiler and the buildable options.
* However, we want to keep the existing behavior for now.
*
* So, if the user has not provided a bundler, we will use the compiler option, if any.
*
* If the user has not provided a bundler and no compiler, but has set buildable to true,
* we will use tsc, since that is the compiler the old generator used to default to, if buildable was true
* and no compiler was provided.
*
* If the user has not provided a bundler and no compiler, and has not set buildable to true, then
* set the bundler to tsc, to preserve old default behaviour (buildable: true by default).
*
* If it's publishable, we need to build the code before publishing it, so again
* we default to `tsc`. In the previous version of this, it would set `buildable` to true
* and that would default to `tsc`.
*
* In the past, the only way to get a non-buildable library was to set buildable to false.
* Now, the only way to get a non-buildble library is to set bundler to none.
* By default, with nothing provided, libraries are buildable with `@nx/js:tsc`.
*/
options.bundler ??= options.compiler;
}
options.linter ??= await promptWhenInteractive<{ options.linter ??= await promptWhenInteractive<{
linter: 'none' | 'eslint'; linter: 'none' | 'eslint';
}>( }>(
@ -843,6 +770,29 @@ async function normalizeOptions(
} }
} }
/**
* We are deprecating the compiler and the buildable options.
* However, we want to keep the existing behavior for now.
*
* So, if the user has not provided a bundler, we will use the compiler option, if any.
*
* If the user has not provided a bundler and no compiler, but has set buildable to true,
* we will use tsc, since that is the compiler the old generator used to default to, if buildable was true
* and no compiler was provided.
*
* If the user has not provided a bundler and no compiler, and has not set buildable to true, then
* set the bundler to tsc, to preserve old default behaviour (buildable: true by default).
*
* If it's publishable, we need to build the code before publishing it, so again
* we default to `tsc`. In the previous version of this, it would set `buildable` to true
* and that would default to `tsc`.
*
* In the past, the only way to get a non-buildable library was to set buildable to false.
* Now, the only way to get a non-buildble library is to set bundler to none.
* By default, with nothing provided, libraries are buildable with `@nx/js:tsc`.
*/
options.bundler ??= options.compiler ?? 'tsc';
// ensure programmatic runs have an expected default // ensure programmatic runs have an expected default
if (!options.config) { if (!options.config) {
options.config = 'project'; options.config = 'project';
@ -994,6 +944,11 @@ function getBuildExecutor(bundler: Bundler) {
} }
function getOutputPath(options: NormalizedLibraryGeneratorOptions) { function getOutputPath(options: NormalizedLibraryGeneratorOptions) {
if (options.isUsingTsSolutionConfig) {
// Executors expect paths relative to workspace root, so we prepend the project root
return joinPathFragments(options.projectRoot, 'dist');
}
const parts = [defaultOutputDirectory]; const parts = [defaultOutputDirectory];
if (options.projectRoot === '.') { if (options.projectRoot === '.') {
parts.push(options.name); parts.push(options.name);
@ -1170,8 +1125,12 @@ function determineEntryFields(
case 'swc': case 'swc':
return { return {
type: 'commonjs', type: 'commonjs',
main: './src/index.js', main: options.isUsingTsSolutionConfig
typings: './src/index.d.ts', ? './dist/src/index.js'
: './src/index.js',
typings: options.isUsingTsSolutionConfig
? './dist/src/index.d.ts'
: './src/index.d.ts',
}; };
case 'rollup': case 'rollup':
return { return {
@ -1202,8 +1161,12 @@ function determineEntryFields(
// For libraries intended for Node, use CJS. // For libraries intended for Node, use CJS.
return { return {
type: 'commonjs', type: 'commonjs',
main: './index.cjs', main: options.isUsingTsSolutionConfig
// typings is missing for esbuild currently ? './dist/index.cjs'
: './index.cjs',
typings: options.isUsingTsSolutionConfig
? './dist/index.d.ts'
: './index.d.ts',
}; };
default: { default: {
return { return {

View File

@ -24,6 +24,8 @@
"description": "The bundler to use. Choosing 'none' means this library is not buildable.", "description": "The bundler to use. Choosing 'none' means this library is not buildable.",
"type": "string", "type": "string",
"enum": ["swc", "tsc", "rollup", "vite", "esbuild", "none"], "enum": ["swc", "tsc", "rollup", "vite", "esbuild", "none"],
"default": "tsc",
"x-prompt": "Which bundler would you like to use to build the library? Choose 'none' to skip build setup.",
"x-priority": "important" "x-priority": "important"
}, },
"linter": { "linter": {

View File

@ -53,6 +53,7 @@ export interface NormalizedSwcExecutorOptions
skipTypeCheck: boolean; skipTypeCheck: boolean;
swcCliOptions: SwcCliOptions; swcCliOptions: SwcCliOptions;
tmpSwcrcPath: string; tmpSwcrcPath: string;
isTsSolutionSetup: boolean;
sourceRoot?: string; sourceRoot?: string;
// TODO(v21): remove inline feature // TODO(v21): remove inline feature
inline?: boolean; inline?: boolean;

View File

@ -1,4 +1,11 @@
import { output, readJson, readNxJson, type Tree } from '@nx/devkit'; import {
output,
readJson,
readNxJson,
workspaceRoot,
type Tree,
} from '@nx/devkit';
import { FsTree } from 'nx/src/generators/tree';
import { isUsingPackageManagerWorkspaces } from '../package-manager-workspaces'; import { isUsingPackageManagerWorkspaces } from '../package-manager-workspaces';
export function isUsingTypeScriptPlugin(tree: Tree): boolean { export function isUsingTypeScriptPlugin(tree: Tree): boolean {
@ -13,7 +20,9 @@ export function isUsingTypeScriptPlugin(tree: Tree): boolean {
); );
} }
export function isUsingTsSolutionSetup(tree: Tree): boolean { export function isUsingTsSolutionSetup(tree?: Tree): boolean {
tree ??= new FsTree(workspaceRoot, false);
return ( return (
isUsingPackageManagerWorkspaces(tree) && isUsingPackageManagerWorkspaces(tree) &&
isWorkspaceSetupWithTsSolution(tree) isWorkspaceSetupWithTsSolution(tree)