feat(js): update the setup-build generator to support the new ts setup (#28446)
Update the `@nx/js:setup-build` and the generators it depends on to support the new TS setup with project references. <!-- 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 #
This commit is contained in:
parent
1fec637514
commit
f357b4ed53
@ -61,6 +61,12 @@
|
|||||||
"description": "The build target to add.",
|
"description": "The build target to add.",
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"default": "build"
|
"default": "build"
|
||||||
|
},
|
||||||
|
"format": {
|
||||||
|
"description": "The format to build the library (esm or cjs).",
|
||||||
|
"type": "array",
|
||||||
|
"items": { "type": "string", "enum": ["esm", "cjs"] },
|
||||||
|
"default": ["esm"]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"required": [],
|
"required": [],
|
||||||
|
|||||||
@ -130,12 +130,12 @@
|
|||||||
"description": "Generate a lockfile (e.g. package-lock.json) that matches the workspace lockfile to ensure package versions match.",
|
"description": "Generate a lockfile (e.g. package-lock.json) that matches the workspace lockfile to ensure package versions match.",
|
||||||
"default": false,
|
"default": false,
|
||||||
"x-priority": "internal"
|
"x-priority": "internal"
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"stripLeadingPaths": {
|
"stripLeadingPaths": {
|
||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
"description": "Remove leading directory from output (e.g. src). See: https://swc.rs/docs/usage/cli#--strip-leading-paths",
|
"description": "Remove leading directory from output (e.g. src). See: https://swc.rs/docs/usage/cli#--strip-leading-paths",
|
||||||
"default": false
|
"default": false
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"required": ["main", "outputPath", "tsConfig"],
|
"required": ["main", "outputPath", "tsConfig"],
|
||||||
"definitions": {
|
"definitions": {
|
||||||
|
|||||||
@ -26,13 +26,13 @@
|
|||||||
},
|
},
|
||||||
"main": {
|
"main": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"description": "Path relative to the workspace root for the main entry file. Defaults to '<projectRoot>/src/main.ts'.",
|
"description": "Path relative to the workspace root for the main entry file. Defaults to '<projectRoot>/src/index.ts'.",
|
||||||
"alias": "entryFile",
|
"alias": "entryFile",
|
||||||
"x-priority": "important"
|
"x-priority": "important"
|
||||||
},
|
},
|
||||||
"tsConfig": {
|
"tsConfig": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"description": "Path relative to the workspace root for the tsconfig file to build with. Defaults to '<projectRoot>/tsconfig.app.json'.",
|
"description": "Path relative to the workspace root for the tsconfig file to build with. Defaults to '<projectRoot>/tsconfig.lib.json'.",
|
||||||
"x-priority": "important"
|
"x-priority": "important"
|
||||||
},
|
},
|
||||||
"skipFormat": {
|
"skipFormat": {
|
||||||
|
|||||||
@ -214,14 +214,20 @@ describe('packaging libs', () => {
|
|||||||
|
|
||||||
expect(readJson(`dist/libs/${tscLib}/package.json`).exports).toEqual({
|
expect(readJson(`dist/libs/${tscLib}/package.json`).exports).toEqual({
|
||||||
'./package.json': './package.json',
|
'./package.json': './package.json',
|
||||||
'.': './src/index.js',
|
'.': {
|
||||||
|
default: './src/index.js',
|
||||||
|
types: './src/index.d.ts',
|
||||||
|
},
|
||||||
'./foo/bar': './src/foo/bar.js',
|
'./foo/bar': './src/foo/bar.js',
|
||||||
'./foo/faz': './src/foo/faz.js',
|
'./foo/faz': './src/foo/faz.js',
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(readJson(`dist/libs/${swcLib}/package.json`).exports).toEqual({
|
expect(readJson(`dist/libs/${swcLib}/package.json`).exports).toEqual({
|
||||||
'./package.json': './package.json',
|
'./package.json': './package.json',
|
||||||
'.': './src/index.js',
|
'.': {
|
||||||
|
default: './src/index.js',
|
||||||
|
types: './src/index.d.ts',
|
||||||
|
},
|
||||||
'./foo/bar': './src/foo/bar.js',
|
'./foo/bar': './src/foo/bar.js',
|
||||||
'./foo/faz': './src/foo/faz.js',
|
'./foo/faz': './src/foo/faz.js',
|
||||||
});
|
});
|
||||||
|
|||||||
@ -18,7 +18,10 @@ import {
|
|||||||
import * as esbuild from 'esbuild';
|
import * as esbuild from 'esbuild';
|
||||||
import { normalizeOptions } from './lib/normalize';
|
import { normalizeOptions } from './lib/normalize';
|
||||||
|
|
||||||
import { EsBuildExecutorOptions } from './schema';
|
import {
|
||||||
|
EsBuildExecutorOptions,
|
||||||
|
NormalizedEsBuildExecutorOptions,
|
||||||
|
} from './schema';
|
||||||
import { createAsyncIterable } from '@nx/devkit/src/utils/async-iterable';
|
import { createAsyncIterable } from '@nx/devkit/src/utils/async-iterable';
|
||||||
import {
|
import {
|
||||||
buildEsbuildOptions,
|
buildEsbuildOptions,
|
||||||
@ -213,7 +216,7 @@ export async function* esbuildExecutor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
function getTypeCheckOptions(
|
function getTypeCheckOptions(
|
||||||
options: EsBuildExecutorOptions,
|
options: NormalizedEsBuildExecutorOptions,
|
||||||
context: ExecutorContext
|
context: ExecutorContext
|
||||||
) {
|
) {
|
||||||
const { watch, tsConfig, outputPath } = options;
|
const { watch, tsConfig, outputPath } = options;
|
||||||
@ -243,7 +246,7 @@ function getTypeCheckOptions(
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function runTypeCheck(
|
async function runTypeCheck(
|
||||||
options: EsBuildExecutorOptions,
|
options: NormalizedEsBuildExecutorOptions,
|
||||||
context: ExecutorContext
|
context: ExecutorContext
|
||||||
) {
|
) {
|
||||||
const { errors, warnings } = await _runTypeCheck(
|
const { errors, warnings } = await _runTypeCheck(
|
||||||
|
|||||||
@ -125,7 +125,7 @@ export function buildEsbuildOptions(
|
|||||||
|
|
||||||
export function getOutExtension(
|
export function getOutExtension(
|
||||||
format: 'cjs' | 'esm',
|
format: 'cjs' | 'esm',
|
||||||
options: NormalizedEsBuildExecutorOptions
|
options: Pick<NormalizedEsBuildExecutorOptions, 'userDefinedBuildOptions'>
|
||||||
): '.cjs' | '.mjs' | '.js' {
|
): '.cjs' | '.mjs' | '.js' {
|
||||||
const userDefinedExt = options.userDefinedBuildOptions?.outExtension?.['.js'];
|
const userDefinedExt = options.userDefinedBuildOptions?.outExtension?.['.js'];
|
||||||
// Allow users to change the output extensions from default CJS and ESM extensions.
|
// Allow users to change the output extensions from default CJS and ESM extensions.
|
||||||
|
|||||||
@ -17,7 +17,7 @@ export function normalizeOptions(
|
|||||||
const isTsSolutionSetup = isUsingTsSolutionSetup();
|
const isTsSolutionSetup = isUsingTsSolutionSetup();
|
||||||
if (isTsSolutionSetup && options.generatePackageJson) {
|
if (isTsSolutionSetup && options.generatePackageJson) {
|
||||||
throw new Error(
|
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.`
|
`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.`
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -26,7 +26,7 @@ export function normalizeOptions(
|
|||||||
// If we're not generating package.json file, then copy it as-is as an asset when not using ts solution setup.
|
// If we're not generating package.json file, then copy it as-is as an asset when not using ts solution setup.
|
||||||
const assets =
|
const assets =
|
||||||
options.generatePackageJson || isTsSolutionSetup
|
options.generatePackageJson || isTsSolutionSetup
|
||||||
? options.assets
|
? options.assets ?? []
|
||||||
: [
|
: [
|
||||||
...options.assets,
|
...options.assets,
|
||||||
joinPathFragments(
|
joinPathFragments(
|
||||||
|
|||||||
@ -5,7 +5,7 @@ type Compiler = 'babel' | 'swc';
|
|||||||
|
|
||||||
export interface EsBuildExecutorOptions {
|
export interface EsBuildExecutorOptions {
|
||||||
additionalEntryPoints?: string[];
|
additionalEntryPoints?: string[];
|
||||||
assets: (AssetGlob | string)[];
|
assets?: (AssetGlob | string)[];
|
||||||
bundle?: boolean;
|
bundle?: boolean;
|
||||||
declaration?: boolean;
|
declaration?: boolean;
|
||||||
declarationRootDir?: string;
|
declarationRootDir?: string;
|
||||||
@ -32,7 +32,8 @@ export interface EsBuildExecutorOptions {
|
|||||||
|
|
||||||
export interface NormalizedEsBuildExecutorOptions
|
export interface NormalizedEsBuildExecutorOptions
|
||||||
extends Omit<EsBuildExecutorOptions, 'esbuildOptions' | 'esbuildConfig'> {
|
extends Omit<EsBuildExecutorOptions, 'esbuildOptions' | 'esbuildConfig'> {
|
||||||
|
assets: (AssetGlob | string)[];
|
||||||
singleEntry: boolean;
|
singleEntry: boolean;
|
||||||
external: string[];
|
external: string[];
|
||||||
userDefinedBuildOptions: esbuild.BuildOptions;
|
userDefinedBuildOptions: esbuild.BuildOptions | undefined;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,33 +1,38 @@
|
|||||||
import {
|
import {
|
||||||
formatFiles,
|
formatFiles,
|
||||||
joinPathFragments,
|
joinPathFragments,
|
||||||
|
readJson,
|
||||||
|
readNxJson,
|
||||||
readProjectConfiguration,
|
readProjectConfiguration,
|
||||||
Tree,
|
Tree,
|
||||||
updateProjectConfiguration,
|
updateProjectConfiguration,
|
||||||
writeJson,
|
writeJson,
|
||||||
} from '@nx/devkit';
|
} from '@nx/devkit';
|
||||||
|
|
||||||
import { getImportPath } from '@nx/js/src/utils/get-import-path';
|
|
||||||
import { assertNotUsingTsSolutionSetup } from '@nx/js/src/utils/typescript/ts-solution-setup';
|
|
||||||
|
|
||||||
import { esbuildInitGenerator } from '../init/init';
|
|
||||||
import { EsBuildExecutorOptions } from '../../executors/esbuild/schema';
|
|
||||||
import { EsBuildProjectSchema } from './schema';
|
|
||||||
import { addBuildTargetDefaults } from '@nx/devkit/src/generators/target-defaults-utils';
|
import { addBuildTargetDefaults } from '@nx/devkit/src/generators/target-defaults-utils';
|
||||||
|
import { getOutputDir, getUpdatedPackageJsonContent } from '@nx/js';
|
||||||
|
import { getImportPath } from '@nx/js/src/utils/get-import-path';
|
||||||
|
import { isUsingTsSolutionSetup } from '@nx/js/src/utils/typescript/ts-solution-setup';
|
||||||
|
import { basename, dirname, join } from 'node:path/posix';
|
||||||
|
import { mergeTargetConfigurations } from 'nx/src/devkit-internals';
|
||||||
|
import { PackageJson } from 'nx/src/utils/package-json';
|
||||||
|
import { getOutExtension } from '../../executors/esbuild/lib/build-esbuild-options';
|
||||||
|
import { EsBuildExecutorOptions } from '../../executors/esbuild/schema';
|
||||||
|
import { esbuildInitGenerator } from '../init/init';
|
||||||
|
import { EsBuildProjectSchema } from './schema';
|
||||||
|
|
||||||
export async function configurationGenerator(
|
export async function configurationGenerator(
|
||||||
tree: Tree,
|
tree: Tree,
|
||||||
options: EsBuildProjectSchema
|
options: EsBuildProjectSchema
|
||||||
) {
|
) {
|
||||||
assertNotUsingTsSolutionSetup(tree, 'esbuild', 'configuration');
|
|
||||||
|
|
||||||
const task = await esbuildInitGenerator(tree, {
|
const task = await esbuildInitGenerator(tree, {
|
||||||
...options,
|
...options,
|
||||||
skipFormat: true,
|
skipFormat: true,
|
||||||
});
|
});
|
||||||
options.buildTarget ??= 'build';
|
options.buildTarget ??= 'build';
|
||||||
|
const isTsSolutionSetup = isUsingTsSolutionSetup(tree);
|
||||||
checkForTargetConflicts(tree, options);
|
checkForTargetConflicts(tree, options);
|
||||||
addBuildTarget(tree, options);
|
addBuildTarget(tree, options, isTsSolutionSetup);
|
||||||
|
updatePackageJson(tree, options, isTsSolutionSetup);
|
||||||
await formatFiles(tree);
|
await formatFiles(tree);
|
||||||
return task;
|
return task;
|
||||||
}
|
}
|
||||||
@ -42,53 +47,58 @@ function checkForTargetConflicts(tree: Tree, options: EsBuildProjectSchema) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function addBuildTarget(tree: Tree, options: EsBuildProjectSchema) {
|
function addBuildTarget(
|
||||||
|
tree: Tree,
|
||||||
|
options: EsBuildProjectSchema,
|
||||||
|
isTsSolutionSetup: boolean
|
||||||
|
) {
|
||||||
addBuildTargetDefaults(tree, '@nx/esbuild:esbuild', options.buildTarget);
|
addBuildTargetDefaults(tree, '@nx/esbuild:esbuild', options.buildTarget);
|
||||||
const project = readProjectConfiguration(tree, options.project);
|
const project = readProjectConfiguration(tree, options.project);
|
||||||
const packageJsonPath = joinPathFragments(project.root, 'package.json');
|
|
||||||
|
|
||||||
if (!tree.exists(packageJsonPath)) {
|
|
||||||
const importPath =
|
|
||||||
options.importPath || getImportPath(tree, options.project);
|
|
||||||
writeJson(tree, packageJsonPath, {
|
|
||||||
name: importPath,
|
|
||||||
version: '0.0.1',
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
const prevBuildOptions = project.targets?.[options.buildTarget]?.options;
|
const prevBuildOptions = project.targets?.[options.buildTarget]?.options;
|
||||||
|
|
||||||
const tsConfig = prevBuildOptions?.tsConfig ?? getTsConfigFile(tree, options);
|
const tsConfig = prevBuildOptions?.tsConfig ?? getTsConfigFile(tree, options);
|
||||||
|
|
||||||
|
let outputPath = prevBuildOptions?.outputPath;
|
||||||
|
if (!outputPath) {
|
||||||
|
outputPath = isTsSolutionSetup
|
||||||
|
? joinPathFragments(project.root, 'dist')
|
||||||
|
: joinPathFragments(
|
||||||
|
'dist',
|
||||||
|
project.root === '.' ? options.project : project.root
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
const buildOptions: EsBuildExecutorOptions = {
|
const buildOptions: EsBuildExecutorOptions = {
|
||||||
main: prevBuildOptions?.main ?? getMainFile(tree, options),
|
main: prevBuildOptions?.main ?? getMainFile(tree, options),
|
||||||
outputPath:
|
outputPath,
|
||||||
prevBuildOptions?.outputPath ??
|
|
||||||
joinPathFragments(
|
|
||||||
'dist',
|
|
||||||
project.root === '.' ? options.project : project.root
|
|
||||||
),
|
|
||||||
outputFileName: 'main.js',
|
outputFileName: 'main.js',
|
||||||
tsConfig,
|
tsConfig,
|
||||||
assets: [],
|
|
||||||
platform: options.platform,
|
platform: options.platform,
|
||||||
|
format: options.format,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (isTsSolutionSetup) {
|
||||||
|
buildOptions.declarationRootDir =
|
||||||
|
project.sourceRoot ?? tree.exists(`${project.root}/src`)
|
||||||
|
? `${project.root}/src`
|
||||||
|
: project.root;
|
||||||
|
} else {
|
||||||
|
buildOptions.assets = [];
|
||||||
|
|
||||||
|
if (tree.exists(joinPathFragments(project.root, 'README.md'))) {
|
||||||
|
buildOptions.assets.push({
|
||||||
|
glob: `${project.root}/README.md`,
|
||||||
|
input: '.',
|
||||||
|
output: '.',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (options.platform === 'browser') {
|
if (options.platform === 'browser') {
|
||||||
buildOptions.outputHashing = 'all';
|
buildOptions.outputHashing = 'all';
|
||||||
buildOptions.minify = true;
|
buildOptions.minify = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tree.exists(joinPathFragments(project.root, 'README.md'))) {
|
|
||||||
buildOptions.assets = [
|
|
||||||
{
|
|
||||||
glob: `${project.root}/README.md`,
|
|
||||||
input: '.',
|
|
||||||
output: '.',
|
|
||||||
},
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
updateProjectConfiguration(tree, options.project, {
|
updateProjectConfiguration(tree, options.project, {
|
||||||
...project,
|
...project,
|
||||||
targets: {
|
targets: {
|
||||||
@ -111,6 +121,89 @@ function addBuildTarget(tree: Tree, options: EsBuildProjectSchema) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function updatePackageJson(
|
||||||
|
tree: Tree,
|
||||||
|
options: EsBuildProjectSchema,
|
||||||
|
isTsSolutionSetup: boolean
|
||||||
|
) {
|
||||||
|
const project = readProjectConfiguration(tree, options.project);
|
||||||
|
|
||||||
|
const packageJsonPath = join(project.root, 'package.json');
|
||||||
|
let packageJson: PackageJson;
|
||||||
|
if (tree.exists(packageJsonPath)) {
|
||||||
|
if (!isTsSolutionSetup) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
packageJson = readJson(tree, packageJsonPath);
|
||||||
|
} else {
|
||||||
|
packageJson = {
|
||||||
|
name: getImportPath(tree, options.project),
|
||||||
|
version: '0.0.1',
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isTsSolutionSetup) {
|
||||||
|
const nxJson = readNxJson(tree);
|
||||||
|
const projectTarget = project.targets[options.buildTarget];
|
||||||
|
const mergedTarget = mergeTargetConfigurations(
|
||||||
|
projectTarget,
|
||||||
|
(projectTarget.executor
|
||||||
|
? nxJson.targetDefaults?.[projectTarget.executor]
|
||||||
|
: undefined) ?? nxJson.targetDefaults?.[options.buildTarget]
|
||||||
|
);
|
||||||
|
|
||||||
|
const {
|
||||||
|
declarationRootDir = '.',
|
||||||
|
main,
|
||||||
|
outputPath,
|
||||||
|
outputFileName,
|
||||||
|
// the executor option defaults to [esm]
|
||||||
|
format = ['esm'],
|
||||||
|
esbuildOptions,
|
||||||
|
} = mergedTarget.options;
|
||||||
|
|
||||||
|
// can't use the declarationRootDir as rootDir because it only affects the typings,
|
||||||
|
// not the runtime entry point
|
||||||
|
packageJson = getUpdatedPackageJsonContent(packageJson, {
|
||||||
|
main,
|
||||||
|
outputPath,
|
||||||
|
projectRoot: project.root,
|
||||||
|
generateExportsField: true,
|
||||||
|
packageJsonPath,
|
||||||
|
format,
|
||||||
|
outputFileName,
|
||||||
|
outputFileExtensionForCjs: getOutExtension('cjs', {
|
||||||
|
// there's very little chance that the user would have defined a custom esbuild config
|
||||||
|
// since that's an Nx specific file that we're not generating here and we're setting up
|
||||||
|
// the build for esbuild now
|
||||||
|
userDefinedBuildOptions: esbuildOptions,
|
||||||
|
}),
|
||||||
|
outputFileExtensionForEsm: getOutExtension('esm', {
|
||||||
|
userDefinedBuildOptions: esbuildOptions,
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
|
||||||
|
if (declarationRootDir !== dirname(main)) {
|
||||||
|
// the declaration file entry point will be output to a location
|
||||||
|
// different than the runtime entry point, adjust accodingly
|
||||||
|
const outputDir = getOutputDir({
|
||||||
|
main,
|
||||||
|
outputPath,
|
||||||
|
projectRoot: project.root,
|
||||||
|
packageJsonPath,
|
||||||
|
rootDir: declarationRootDir,
|
||||||
|
});
|
||||||
|
const mainFile = basename(options.main).replace(/\.[tj]s$/, '');
|
||||||
|
const typingsFile = `${outputDir}${mainFile}.d.ts`;
|
||||||
|
packageJson.types = typingsFile;
|
||||||
|
packageJson.exports['.'].types = typingsFile;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
writeJson(tree, packageJsonPath, packageJson);
|
||||||
|
}
|
||||||
|
|
||||||
function getMainFile(tree: Tree, options: EsBuildProjectSchema) {
|
function getMainFile(tree: Tree, options: EsBuildProjectSchema) {
|
||||||
const project = readProjectConfiguration(tree, options.project);
|
const project = readProjectConfiguration(tree, options.project);
|
||||||
const candidates = [
|
const candidates = [
|
||||||
|
|||||||
@ -1,3 +1,5 @@
|
|||||||
|
import type { SupportedFormat } from '@nx/js';
|
||||||
|
|
||||||
export interface EsBuildProjectSchema {
|
export interface EsBuildProjectSchema {
|
||||||
project: string;
|
project: string;
|
||||||
main?: string;
|
main?: string;
|
||||||
@ -10,4 +12,5 @@ export interface EsBuildProjectSchema {
|
|||||||
esbuildConfig?: string;
|
esbuildConfig?: string;
|
||||||
platform?: 'node' | 'browser' | 'neutral';
|
platform?: 'node' | 'browser' | 'neutral';
|
||||||
buildTarget?: string;
|
buildTarget?: string;
|
||||||
|
format?: SupportedFormat[];
|
||||||
}
|
}
|
||||||
|
|||||||
@ -60,6 +60,15 @@
|
|||||||
"description": "The build target to add.",
|
"description": "The build target to add.",
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"default": "build"
|
"default": "build"
|
||||||
|
},
|
||||||
|
"format": {
|
||||||
|
"description": "The format to build the library (esm or cjs).",
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": ["esm", "cjs"]
|
||||||
|
},
|
||||||
|
"default": ["esm"]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"required": [],
|
"required": [],
|
||||||
|
|||||||
@ -4,14 +4,11 @@ import {
|
|||||||
GeneratorCallback,
|
GeneratorCallback,
|
||||||
Tree,
|
Tree,
|
||||||
} from '@nx/devkit';
|
} from '@nx/devkit';
|
||||||
import { assertNotUsingTsSolutionSetup } from '@nx/js/src/utils/typescript/ts-solution-setup';
|
|
||||||
import { esbuildVersion } from '@nx/js/src/utils/versions';
|
import { esbuildVersion } from '@nx/js/src/utils/versions';
|
||||||
import { nxVersion } from '../../utils/versions';
|
import { nxVersion } from '../../utils/versions';
|
||||||
import { Schema } from './schema';
|
import { Schema } from './schema';
|
||||||
|
|
||||||
export async function esbuildInitGenerator(tree: Tree, schema: Schema) {
|
export async function esbuildInitGenerator(tree: Tree, schema: Schema) {
|
||||||
assertNotUsingTsSolutionSetup(tree, 'esbuild', 'init');
|
|
||||||
|
|
||||||
let installTask: GeneratorCallback = () => {};
|
let installTask: GeneratorCallback = () => {};
|
||||||
if (!schema.skipPackageJson) {
|
if (!schema.skipPackageJson) {
|
||||||
installTask = addDependenciesToPackageJson(
|
installTask = addDependenciesToPackageJson(
|
||||||
|
|||||||
@ -73,13 +73,13 @@ export async function expoLibraryGeneratorInternal(
|
|||||||
}
|
}
|
||||||
initRootBabelConfig(host);
|
initRootBabelConfig(host);
|
||||||
|
|
||||||
|
createFiles(host, options);
|
||||||
|
|
||||||
const addProjectTask = await addProject(host, options);
|
const addProjectTask = await addProject(host, options);
|
||||||
if (addProjectTask) {
|
if (addProjectTask) {
|
||||||
tasks.push(addProjectTask);
|
tasks.push(addProjectTask);
|
||||||
}
|
}
|
||||||
|
|
||||||
createFiles(host, options);
|
|
||||||
|
|
||||||
const lintTask = await addLinting(host, {
|
const lintTask = await addLinting(host, {
|
||||||
...options,
|
...options,
|
||||||
projectName: options.name,
|
projectName: options.name,
|
||||||
|
|||||||
@ -113,12 +113,12 @@
|
|||||||
"description": "Generate a lockfile (e.g. package-lock.json) that matches the workspace lockfile to ensure package versions match.",
|
"description": "Generate a lockfile (e.g. package-lock.json) that matches the workspace lockfile to ensure package versions match.",
|
||||||
"default": false,
|
"default": false,
|
||||||
"x-priority": "internal"
|
"x-priority": "internal"
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"stripLeadingPaths": {
|
"stripLeadingPaths": {
|
||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
"description": "Remove leading directory from output (e.g. src). See: https://swc.rs/docs/usage/cli#--strip-leading-paths",
|
"description": "Remove leading directory from output (e.g. src). See: https://swc.rs/docs/usage/cli#--strip-leading-paths",
|
||||||
"default": false
|
"default": false
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"required": ["main", "outputPath", "tsConfig"],
|
"required": ["main", "outputPath", "tsConfig"],
|
||||||
"definitions": {
|
"definitions": {
|
||||||
|
|||||||
@ -1,6 +1,12 @@
|
|||||||
import 'nx/src/internal-testing-utils/mock-project-graph';
|
import 'nx/src/internal-testing-utils/mock-project-graph';
|
||||||
|
|
||||||
import { readProjectConfiguration, Tree } from '@nx/devkit';
|
import {
|
||||||
|
addProjectConfiguration,
|
||||||
|
readJson,
|
||||||
|
readProjectConfiguration,
|
||||||
|
Tree,
|
||||||
|
writeJson,
|
||||||
|
} from '@nx/devkit';
|
||||||
import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing';
|
import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing';
|
||||||
import { join } from 'path';
|
import { join } from 'path';
|
||||||
import { LibraryGeneratorSchema } from '../library/schema';
|
import { LibraryGeneratorSchema } from '../library/schema';
|
||||||
@ -23,10 +29,8 @@ describe('convert to swc', () => {
|
|||||||
bundler: 'tsc',
|
bundler: 'tsc',
|
||||||
};
|
};
|
||||||
|
|
||||||
beforeAll(() => {
|
beforeEach(() => {
|
||||||
tree = createTreeWithEmptyWorkspace();
|
tree = createTreeWithEmptyWorkspace();
|
||||||
tree.write('/.gitignore', '');
|
|
||||||
tree.write('/.gitignore', '');
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should convert tsc to swc', async () => {
|
it('should convert tsc to swc', async () => {
|
||||||
@ -50,9 +54,33 @@ describe('convert to swc', () => {
|
|||||||
join(readProjectConfiguration(tree, 'tsc-lib').root, '.swcrc')
|
join(readProjectConfiguration(tree, 'tsc-lib').root, '.swcrc')
|
||||||
)
|
)
|
||||||
).toEqual(true);
|
).toEqual(true);
|
||||||
expect(tree.read('package.json', 'utf-8')).toContain('@swc/core');
|
expect(
|
||||||
expect(tree.read('tsc-lib/package.json', 'utf-8')).toContain(
|
readJson(tree, 'package.json').devDependencies['@swc/core']
|
||||||
'@swc/helpers'
|
).toBeDefined();
|
||||||
);
|
expect(
|
||||||
|
readJson(tree, 'tsc-lib/package.json').dependencies['@swc/helpers']
|
||||||
|
).toBeDefined();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should handle project configuration without targets', async () => {
|
||||||
|
addProjectConfiguration(tree, 'lib1', { root: 'lib1' });
|
||||||
|
|
||||||
|
await expect(
|
||||||
|
convertToSwcGenerator(tree, { project: 'lib1' })
|
||||||
|
).resolves.not.toThrow();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not add swc dependencies when no target was updated', async () => {
|
||||||
|
addProjectConfiguration(tree, 'lib1', { root: 'lib1' });
|
||||||
|
writeJson(tree, 'lib1/package.json', { dependencies: {} });
|
||||||
|
|
||||||
|
await convertToSwcGenerator(tree, { project: 'lib1' });
|
||||||
|
|
||||||
|
expect(
|
||||||
|
readJson(tree, 'package.json').devDependencies['@swc/core']
|
||||||
|
).not.toBeDefined();
|
||||||
|
expect(
|
||||||
|
readJson(tree, 'lib1/package.json').dependencies['@swc/helpers']
|
||||||
|
).not.toBeDefined();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@ -20,13 +20,14 @@ export async function convertToSwcGenerator(
|
|||||||
const options = normalizeOptions(schema);
|
const options = normalizeOptions(schema);
|
||||||
const projectConfiguration = readProjectConfiguration(tree, options.project);
|
const projectConfiguration = readProjectConfiguration(tree, options.project);
|
||||||
|
|
||||||
updateProjectBuildTargets(
|
const updated = updateProjectBuildTargets(
|
||||||
tree,
|
tree,
|
||||||
projectConfiguration,
|
projectConfiguration,
|
||||||
options.project,
|
options.project,
|
||||||
options.targets
|
options.targets
|
||||||
);
|
);
|
||||||
return checkSwcDependencies(tree, projectConfiguration);
|
|
||||||
|
return updated ? checkSwcDependencies(tree, projectConfiguration) : () => {};
|
||||||
}
|
}
|
||||||
|
|
||||||
function normalizeOptions(
|
function normalizeOptions(
|
||||||
@ -47,8 +48,9 @@ function updateProjectBuildTargets(
|
|||||||
projectName: string,
|
projectName: string,
|
||||||
projectTargets: string[]
|
projectTargets: string[]
|
||||||
) {
|
) {
|
||||||
|
let updated = false;
|
||||||
for (const target of projectTargets) {
|
for (const target of projectTargets) {
|
||||||
const targetConfiguration = projectConfiguration.targets[target];
|
const targetConfiguration = projectConfiguration.targets?.[target];
|
||||||
if (
|
if (
|
||||||
!targetConfiguration ||
|
!targetConfiguration ||
|
||||||
(targetConfiguration.executor !== '@nx/js:tsc' &&
|
(targetConfiguration.executor !== '@nx/js:tsc' &&
|
||||||
@ -56,9 +58,14 @@ function updateProjectBuildTargets(
|
|||||||
)
|
)
|
||||||
continue;
|
continue;
|
||||||
targetConfiguration.executor = '@nx/js:swc';
|
targetConfiguration.executor = '@nx/js:swc';
|
||||||
|
updated = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (updated) {
|
||||||
updateProjectConfiguration(tree, projectName, projectConfiguration);
|
updateProjectConfiguration(tree, projectName, projectConfiguration);
|
||||||
|
}
|
||||||
|
|
||||||
|
return updated;
|
||||||
}
|
}
|
||||||
|
|
||||||
function checkSwcDependencies(
|
function checkSwcDependencies(
|
||||||
|
|||||||
@ -67,7 +67,7 @@ import { getProjectPackageManagerWorkspaceStateWarningTask } from './utils/packa
|
|||||||
import {
|
import {
|
||||||
ensureProjectIsExcludedFromPluginRegistrations,
|
ensureProjectIsExcludedFromPluginRegistrations,
|
||||||
ensureProjectIsIncludedInPluginRegistrations,
|
ensureProjectIsIncludedInPluginRegistrations,
|
||||||
} from './utils/plugin-registrations';
|
} from '../../utils/typescript/plugin';
|
||||||
|
|
||||||
const defaultOutputDirectory = 'dist';
|
const defaultOutputDirectory = 'dist';
|
||||||
|
|
||||||
|
|||||||
@ -1,18 +1,37 @@
|
|||||||
import {
|
import {
|
||||||
ensurePackage,
|
ensurePackage,
|
||||||
formatFiles,
|
formatFiles,
|
||||||
type GeneratorCallback,
|
|
||||||
joinPathFragments,
|
joinPathFragments,
|
||||||
|
readJson,
|
||||||
|
readNxJson,
|
||||||
readProjectConfiguration,
|
readProjectConfiguration,
|
||||||
runTasksInSerial,
|
runTasksInSerial,
|
||||||
type Tree,
|
updateNxJson,
|
||||||
updateProjectConfiguration,
|
updateProjectConfiguration,
|
||||||
|
writeJson,
|
||||||
|
type GeneratorCallback,
|
||||||
|
type ProjectConfiguration,
|
||||||
|
type Tree,
|
||||||
} from '@nx/devkit';
|
} from '@nx/devkit';
|
||||||
|
import { addBuildTargetDefaults } from '@nx/devkit/src/generators/target-defaults-utils';
|
||||||
|
import { basename, dirname, join } from 'node:path/posix';
|
||||||
|
import { mergeTargetConfigurations } from 'nx/src/devkit-internals';
|
||||||
|
import type { PackageJson } from 'nx/src/utils/package-json';
|
||||||
|
import { ensureProjectIsIncludedInPluginRegistrations } from '../..//utils/typescript/plugin';
|
||||||
|
import { getImportPath } from '../../utils/get-import-path';
|
||||||
|
import {
|
||||||
|
getUpdatedPackageJsonContent,
|
||||||
|
type SupportedFormat,
|
||||||
|
} from '../../utils/package-json/update-package-json';
|
||||||
import { addSwcConfig } from '../../utils/swc/add-swc-config';
|
import { addSwcConfig } from '../../utils/swc/add-swc-config';
|
||||||
import { addSwcDependencies } from '../../utils/swc/add-swc-dependencies';
|
import { addSwcDependencies } from '../../utils/swc/add-swc-dependencies';
|
||||||
|
import { ensureTypescript } from '../../utils/typescript/ensure-typescript';
|
||||||
|
import { readTsConfig } from '../../utils/typescript/ts-config';
|
||||||
|
import { isUsingTsSolutionSetup } from '../../utils/typescript/ts-solution-setup';
|
||||||
import { nxVersion } from '../../utils/versions';
|
import { nxVersion } from '../../utils/versions';
|
||||||
import { SetupBuildGeneratorSchema } from './schema';
|
import { SetupBuildGeneratorSchema } from './schema';
|
||||||
import { addBuildTargetDefaults } from '@nx/devkit/src/generators/target-defaults-utils';
|
|
||||||
|
let ts: typeof import('typescript');
|
||||||
|
|
||||||
export async function setupBuildGenerator(
|
export async function setupBuildGenerator(
|
||||||
tree: Tree,
|
tree: Tree,
|
||||||
@ -20,8 +39,8 @@ export async function setupBuildGenerator(
|
|||||||
): Promise<GeneratorCallback> {
|
): Promise<GeneratorCallback> {
|
||||||
const tasks: GeneratorCallback[] = [];
|
const tasks: GeneratorCallback[] = [];
|
||||||
const project = readProjectConfiguration(tree, options.project);
|
const project = readProjectConfiguration(tree, options.project);
|
||||||
const buildTarget = options.buildTarget ?? 'build';
|
options.buildTarget ??= 'build';
|
||||||
const prevBuildOptions = project.targets?.[buildTarget]?.options;
|
const prevBuildOptions = project.targets?.[options.buildTarget]?.options;
|
||||||
|
|
||||||
project.targets ??= {};
|
project.targets ??= {};
|
||||||
|
|
||||||
@ -49,6 +68,7 @@ export async function setupBuildGenerator(
|
|||||||
`Cannot locate a main file for ${options.project}. Please specify one using --main=<file-path>.`
|
`Cannot locate a main file for ${options.project}. Please specify one using --main=<file-path>.`
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
options.main = mainFile;
|
||||||
|
|
||||||
let tsConfigFile: string;
|
let tsConfigFile: string;
|
||||||
if (prevBuildOptions?.tsConfig) {
|
if (prevBuildOptions?.tsConfig) {
|
||||||
@ -73,6 +93,13 @@ export async function setupBuildGenerator(
|
|||||||
`Cannot locate a tsConfig file for ${options.project}. Please specify one using --tsConfig=<file-path>.`
|
`Cannot locate a tsConfig file for ${options.project}. Please specify one using --tsConfig=<file-path>.`
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
options.tsConfig = tsConfigFile;
|
||||||
|
|
||||||
|
const isTsSolutionSetup = isUsingTsSolutionSetup(tree);
|
||||||
|
const nxJson = readNxJson(tree);
|
||||||
|
const addPlugin =
|
||||||
|
process.env.NX_ADD_PLUGINS !== 'false' &&
|
||||||
|
nxJson.useInferencePlugins !== false;
|
||||||
|
|
||||||
switch (options.bundler) {
|
switch (options.bundler) {
|
||||||
case 'vite': {
|
case 'vite': {
|
||||||
@ -83,10 +110,11 @@ export async function setupBuildGenerator(
|
|||||||
const task = await viteConfigurationGenerator(tree, {
|
const task = await viteConfigurationGenerator(tree, {
|
||||||
buildTarget: options.buildTarget,
|
buildTarget: options.buildTarget,
|
||||||
project: options.project,
|
project: options.project,
|
||||||
newProject: true,
|
newProject: false,
|
||||||
uiFramework: 'none',
|
uiFramework: 'none',
|
||||||
includeVitest: false,
|
includeVitest: false,
|
||||||
includeLib: true,
|
includeLib: true,
|
||||||
|
addPlugin,
|
||||||
skipFormat: true,
|
skipFormat: true,
|
||||||
});
|
});
|
||||||
tasks.push(task);
|
tasks.push(task);
|
||||||
@ -103,6 +131,7 @@ export async function setupBuildGenerator(
|
|||||||
project: options.project,
|
project: options.project,
|
||||||
skipFormat: true,
|
skipFormat: true,
|
||||||
skipValidation: true,
|
skipValidation: true,
|
||||||
|
format: ['cjs'],
|
||||||
});
|
});
|
||||||
tasks.push(task);
|
tasks.push(task);
|
||||||
break;
|
break;
|
||||||
@ -116,6 +145,7 @@ export async function setupBuildGenerator(
|
|||||||
project: options.project,
|
project: options.project,
|
||||||
compiler: 'tsc',
|
compiler: 'tsc',
|
||||||
format: ['cjs', 'esm'],
|
format: ['cjs', 'esm'],
|
||||||
|
addPlugin,
|
||||||
skipFormat: true,
|
skipFormat: true,
|
||||||
skipValidation: true,
|
skipValidation: true,
|
||||||
});
|
});
|
||||||
@ -123,10 +153,20 @@ export async function setupBuildGenerator(
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 'tsc': {
|
case 'tsc': {
|
||||||
|
if (isTsSolutionSetup) {
|
||||||
|
const nxJson = readNxJson(tree);
|
||||||
|
ensureProjectIsIncludedInPluginRegistrations(
|
||||||
|
nxJson,
|
||||||
|
project.root,
|
||||||
|
options.buildTarget
|
||||||
|
);
|
||||||
|
updateNxJson(tree, nxJson);
|
||||||
|
updatePackageJsonForTsc(tree, options, project);
|
||||||
|
} else {
|
||||||
addBuildTargetDefaults(tree, '@nx/js:tsc');
|
addBuildTargetDefaults(tree, '@nx/js:tsc');
|
||||||
|
|
||||||
const outputPath = joinPathFragments('dist', project.root);
|
const outputPath = joinPathFragments('dist', project.root);
|
||||||
project.targets[buildTarget] = {
|
project.targets[options.buildTarget] = {
|
||||||
executor: `@nx/js:tsc`,
|
executor: `@nx/js:tsc`,
|
||||||
outputs: ['{options.outputPath}'],
|
outputs: ['{options.outputPath}'],
|
||||||
options: {
|
options: {
|
||||||
@ -137,25 +177,37 @@ export async function setupBuildGenerator(
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
updateProjectConfiguration(tree, options.project, project);
|
updateProjectConfiguration(tree, options.project, project);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 'swc': {
|
case 'swc': {
|
||||||
addBuildTargetDefaults(tree, '@nx/js:swc');
|
addBuildTargetDefaults(tree, '@nx/js:swc');
|
||||||
|
|
||||||
const outputPath = joinPathFragments('dist', project.root);
|
const outputPath = isTsSolutionSetup
|
||||||
project.targets[buildTarget] = {
|
? joinPathFragments(project.root, 'dist')
|
||||||
|
: joinPathFragments('dist', project.root);
|
||||||
|
project.targets[options.buildTarget] = {
|
||||||
executor: `@nx/js:swc`,
|
executor: `@nx/js:swc`,
|
||||||
outputs: ['{options.outputPath}'],
|
outputs: ['{options.outputPath}'],
|
||||||
options: {
|
options: {
|
||||||
outputPath,
|
outputPath,
|
||||||
main: mainFile,
|
main: mainFile,
|
||||||
tsConfig: tsConfigFile,
|
tsConfig: tsConfigFile,
|
||||||
assets: [],
|
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (isTsSolutionSetup) {
|
||||||
|
project.targets[options.buildTarget].options.stripLeadingPaths = true;
|
||||||
|
} else {
|
||||||
|
project.targets[options.buildTarget].options.assets = [];
|
||||||
|
}
|
||||||
|
|
||||||
updateProjectConfiguration(tree, options.project, project);
|
updateProjectConfiguration(tree, options.project, project);
|
||||||
addSwcDependencies(tree);
|
tasks.push(addSwcDependencies(tree));
|
||||||
addSwcConfig(tree, project.root, 'es6');
|
addSwcConfig(tree, project.root, 'commonjs');
|
||||||
|
if (isTsSolutionSetup) {
|
||||||
|
updatePackageJsonForSwc(tree, options, project);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -165,3 +217,138 @@ export async function setupBuildGenerator(
|
|||||||
}
|
}
|
||||||
|
|
||||||
export default setupBuildGenerator;
|
export default setupBuildGenerator;
|
||||||
|
|
||||||
|
function updatePackageJsonForTsc(
|
||||||
|
tree: Tree,
|
||||||
|
options: SetupBuildGeneratorSchema,
|
||||||
|
project: ProjectConfiguration
|
||||||
|
) {
|
||||||
|
if (!ts) {
|
||||||
|
ts = ensureTypescript();
|
||||||
|
}
|
||||||
|
|
||||||
|
const tsconfig = readTsConfig(options.tsConfig, {
|
||||||
|
...ts.sys,
|
||||||
|
readFile: (p) => tree.read(p, 'utf-8'),
|
||||||
|
fileExists: (p) => tree.exists(p),
|
||||||
|
});
|
||||||
|
|
||||||
|
let main: string;
|
||||||
|
let rootDir: string;
|
||||||
|
let outputPath: string;
|
||||||
|
if (project.targets?.[options.buildTarget]) {
|
||||||
|
const mergedTarget = mergeTargetDefaults(
|
||||||
|
tree,
|
||||||
|
project,
|
||||||
|
options.buildTarget
|
||||||
|
);
|
||||||
|
({ main, rootDir, outputPath } = mergedTarget.options);
|
||||||
|
} else {
|
||||||
|
main = options.main;
|
||||||
|
|
||||||
|
({ rootDir = project.root, outDir: outputPath } = tsconfig.options);
|
||||||
|
const tsOutFile = tsconfig.options.outFile;
|
||||||
|
|
||||||
|
if (tsOutFile) {
|
||||||
|
main = join(project.root, basename(tsOutFile));
|
||||||
|
outputPath = dirname(tsOutFile);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!outputPath) {
|
||||||
|
outputPath = project.root;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const module = Object.keys(ts.ModuleKind).find(
|
||||||
|
(m) => ts.ModuleKind[m] === tsconfig.options.module
|
||||||
|
);
|
||||||
|
const format: SupportedFormat[] = module.toLowerCase().startsWith('es')
|
||||||
|
? ['esm']
|
||||||
|
: ['cjs'];
|
||||||
|
|
||||||
|
updatePackageJson(
|
||||||
|
tree,
|
||||||
|
options.project,
|
||||||
|
project.root,
|
||||||
|
main,
|
||||||
|
outputPath,
|
||||||
|
rootDir,
|
||||||
|
format
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function updatePackageJsonForSwc(
|
||||||
|
tree: Tree,
|
||||||
|
options: SetupBuildGeneratorSchema,
|
||||||
|
project: ProjectConfiguration
|
||||||
|
) {
|
||||||
|
const mergedTarget = mergeTargetDefaults(tree, project, options.buildTarget);
|
||||||
|
const {
|
||||||
|
main,
|
||||||
|
outputPath,
|
||||||
|
swcrc: swcrcPath = join(project.root, '.swcrc'),
|
||||||
|
} = mergedTarget.options;
|
||||||
|
|
||||||
|
const swcrc = readJson(tree, swcrcPath);
|
||||||
|
const format: SupportedFormat[] = swcrc.module?.type?.startsWith('es')
|
||||||
|
? ['esm']
|
||||||
|
: ['cjs'];
|
||||||
|
|
||||||
|
updatePackageJson(
|
||||||
|
tree,
|
||||||
|
options.project,
|
||||||
|
project.root,
|
||||||
|
main,
|
||||||
|
outputPath,
|
||||||
|
// we set the `stripLeadingPaths` option, so the rootDir would match the dirname of the entry point
|
||||||
|
dirname(main),
|
||||||
|
format
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function updatePackageJson(
|
||||||
|
tree: Tree,
|
||||||
|
projectName: string,
|
||||||
|
projectRoot: string,
|
||||||
|
main: string,
|
||||||
|
outputPath: string,
|
||||||
|
rootDir: string,
|
||||||
|
format?: SupportedFormat[]
|
||||||
|
) {
|
||||||
|
const packageJsonPath = join(projectRoot, 'package.json');
|
||||||
|
let packageJson: PackageJson;
|
||||||
|
if (tree.exists(packageJsonPath)) {
|
||||||
|
packageJson = readJson(tree, packageJsonPath);
|
||||||
|
} else {
|
||||||
|
packageJson = {
|
||||||
|
name: getImportPath(tree, projectName),
|
||||||
|
version: '0.0.1',
|
||||||
|
};
|
||||||
|
}
|
||||||
|
packageJson = getUpdatedPackageJsonContent(packageJson, {
|
||||||
|
main,
|
||||||
|
outputPath,
|
||||||
|
projectRoot,
|
||||||
|
generateExportsField: true,
|
||||||
|
packageJsonPath,
|
||||||
|
rootDir,
|
||||||
|
format,
|
||||||
|
});
|
||||||
|
writeJson(tree, packageJsonPath, packageJson);
|
||||||
|
}
|
||||||
|
|
||||||
|
function mergeTargetDefaults(
|
||||||
|
tree: Tree,
|
||||||
|
project: ProjectConfiguration,
|
||||||
|
buildTarget: string
|
||||||
|
) {
|
||||||
|
const nxJson = readNxJson(tree);
|
||||||
|
const projectTarget = project.targets[buildTarget];
|
||||||
|
|
||||||
|
return mergeTargetConfigurations(
|
||||||
|
projectTarget,
|
||||||
|
(projectTarget.executor
|
||||||
|
? nxJson.targetDefaults?.[projectTarget.executor]
|
||||||
|
: undefined) ?? nxJson.targetDefaults?.[buildTarget]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|||||||
@ -156,7 +156,10 @@ describe('getUpdatedPackageJsonContent', () => {
|
|||||||
types: './src/index.d.ts',
|
types: './src/index.d.ts',
|
||||||
version: '0.0.1',
|
version: '0.0.1',
|
||||||
exports: {
|
exports: {
|
||||||
'.': './src/index.js',
|
'.': {
|
||||||
|
import: './src/index.js',
|
||||||
|
types: './src/index.d.ts',
|
||||||
|
},
|
||||||
'./package.json': './package.json',
|
'./package.json': './package.json',
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
@ -185,7 +188,10 @@ describe('getUpdatedPackageJsonContent', () => {
|
|||||||
version: '0.0.1',
|
version: '0.0.1',
|
||||||
type: 'commonjs',
|
type: 'commonjs',
|
||||||
exports: {
|
exports: {
|
||||||
'.': './src/index.cjs',
|
'.': {
|
||||||
|
default: './src/index.cjs',
|
||||||
|
types: './src/index.d.ts',
|
||||||
|
},
|
||||||
'./package.json': './package.json',
|
'./package.json': './package.json',
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
@ -220,7 +226,10 @@ describe('getUpdatedPackageJsonContent', () => {
|
|||||||
types: './src/index.d.ts',
|
types: './src/index.d.ts',
|
||||||
version: '0.0.1',
|
version: '0.0.1',
|
||||||
exports: {
|
exports: {
|
||||||
'.': './src/index.js',
|
'.': {
|
||||||
|
default: './src/index.js',
|
||||||
|
types: './src/index.d.ts',
|
||||||
|
},
|
||||||
'./foo': './src/foo.js',
|
'./foo': './src/foo.js',
|
||||||
'./bar': './src/bar.js',
|
'./bar': './src/bar.js',
|
||||||
'./package.json': './package.json',
|
'./package.json': './package.json',
|
||||||
@ -258,7 +267,10 @@ describe('getUpdatedPackageJsonContent', () => {
|
|||||||
types: './src/index.d.ts',
|
types: './src/index.d.ts',
|
||||||
version: '0.0.1',
|
version: '0.0.1',
|
||||||
exports: {
|
exports: {
|
||||||
'.': './src/index.js',
|
'.': {
|
||||||
|
import: './src/index.js',
|
||||||
|
types: './src/index.d.ts',
|
||||||
|
},
|
||||||
'./foo': './src/foo.js',
|
'./foo': './src/foo.js',
|
||||||
'./bar': './src/bar.js',
|
'./bar': './src/bar.js',
|
||||||
'./package.json': './package.json',
|
'./package.json': './package.json',
|
||||||
@ -298,6 +310,7 @@ describe('getUpdatedPackageJsonContent', () => {
|
|||||||
'.': {
|
'.': {
|
||||||
import: './src/index.js',
|
import: './src/index.js',
|
||||||
default: './src/index.cjs',
|
default: './src/index.cjs',
|
||||||
|
types: './src/index.d.ts',
|
||||||
},
|
},
|
||||||
'./foo': {
|
'./foo': {
|
||||||
import: './src/foo.js',
|
import: './src/foo.js',
|
||||||
@ -351,6 +364,7 @@ describe('getUpdatedPackageJsonContent', () => {
|
|||||||
'.': {
|
'.': {
|
||||||
import: './src/index.js',
|
import: './src/index.js',
|
||||||
default: './src/index.cjs',
|
default: './src/index.cjs',
|
||||||
|
types: './src/index.d.ts',
|
||||||
},
|
},
|
||||||
'./package.json': './package.json',
|
'./package.json': './package.json',
|
||||||
'./custom': './custom.js',
|
'./custom': './custom.js',
|
||||||
@ -383,7 +397,10 @@ describe('getUpdatedPackageJsonContent', () => {
|
|||||||
version: '0.0.1',
|
version: '0.0.1',
|
||||||
type: 'module',
|
type: 'module',
|
||||||
exports: {
|
exports: {
|
||||||
'.': './src/index.cjs',
|
'.': {
|
||||||
|
default: './src/index.cjs',
|
||||||
|
types: './src/index.d.ts',
|
||||||
|
},
|
||||||
'./package.json': './package.json',
|
'./package.json': './package.json',
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|||||||
@ -22,7 +22,7 @@ import {
|
|||||||
} from '@nx/devkit';
|
} from '@nx/devkit';
|
||||||
import { DependentBuildableProjectNode } from '../buildable-libs-utils';
|
import { DependentBuildableProjectNode } from '../buildable-libs-utils';
|
||||||
import { existsSync, writeFileSync } from 'node:fs';
|
import { existsSync, writeFileSync } from 'node:fs';
|
||||||
import { basename, join, parse } from 'path';
|
import { basename, dirname, join, parse, relative } from 'path';
|
||||||
import { fileExists } from 'nx/src/utils/fileutils';
|
import { fileExists } from 'nx/src/utils/fileutils';
|
||||||
import type { PackageJson } from 'nx/src/utils/package-json';
|
import type { PackageJson } from 'nx/src/utils/package-json';
|
||||||
import { readFileMapCache } from 'nx/src/project-graph/nx-deps-cache';
|
import { readFileMapCache } from 'nx/src/project-graph/nx-deps-cache';
|
||||||
@ -47,6 +47,7 @@ export interface UpdatePackageJsonOption {
|
|||||||
updateBuildableProjectDepsInPackageJson?: boolean;
|
updateBuildableProjectDepsInPackageJson?: boolean;
|
||||||
buildableProjectDepsInPackageJsonType?: 'dependencies' | 'peerDependencies';
|
buildableProjectDepsInPackageJsonType?: 'dependencies' | 'peerDependencies';
|
||||||
generateLockfile?: boolean;
|
generateLockfile?: boolean;
|
||||||
|
packageJsonPath?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function updatePackageJson(
|
export function updatePackageJson(
|
||||||
@ -233,21 +234,18 @@ export function getExports(
|
|||||||
| 'projectRoot'
|
| 'projectRoot'
|
||||||
| 'outputFileName'
|
| 'outputFileName'
|
||||||
| 'additionalEntryPoints'
|
| 'additionalEntryPoints'
|
||||||
|
| 'outputPath'
|
||||||
|
| 'packageJsonPath'
|
||||||
> & {
|
> & {
|
||||||
fileExt: string;
|
fileExt: string;
|
||||||
}
|
}
|
||||||
): Exports {
|
): Exports {
|
||||||
|
const outputDir = getOutputDir(options);
|
||||||
const mainFile = options.outputFileName
|
const mainFile = options.outputFileName
|
||||||
? options.outputFileName.replace(/\.[tj]s$/, '')
|
? options.outputFileName.replace(/\.[tj]s$/, '')
|
||||||
: basename(options.main).replace(/\.[tj]s$/, '');
|
: basename(options.main).replace(/\.[tj]s$/, '');
|
||||||
const relativeMainFileDir = options.outputFileName
|
|
||||||
? './'
|
|
||||||
: getRelativeDirectoryToProjectRoot(
|
|
||||||
options.main,
|
|
||||||
options.rootDir ?? options.projectRoot
|
|
||||||
);
|
|
||||||
const exports: Exports = {
|
const exports: Exports = {
|
||||||
'.': relativeMainFileDir + mainFile + options.fileExt,
|
'.': outputDir + mainFile + options.fileExt,
|
||||||
};
|
};
|
||||||
|
|
||||||
if (options.additionalEntryPoints) {
|
if (options.additionalEntryPoints) {
|
||||||
@ -289,6 +287,24 @@ export function getUpdatedPackageJsonContent(
|
|||||||
packageJson.exports['./package.json'] ??= './package.json';
|
packageJson.exports['./package.json'] ??= './package.json';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!options.skipTypings) {
|
||||||
|
const mainFile = basename(options.main).replace(/\.[tj]s$/, '');
|
||||||
|
const outputDir = getOutputDir(options);
|
||||||
|
const typingsFile = `${outputDir}${mainFile}.d.ts`;
|
||||||
|
packageJson.types ??= typingsFile;
|
||||||
|
|
||||||
|
if (options.generateExportsField) {
|
||||||
|
if (!packageJson.exports['.']) {
|
||||||
|
packageJson.exports['.'] = { types: typingsFile };
|
||||||
|
} else if (
|
||||||
|
typeof packageJson.exports['.'] === 'object' &&
|
||||||
|
!packageJson.exports['.'].types
|
||||||
|
) {
|
||||||
|
packageJson.exports['.'].types = typingsFile;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (hasEsmFormat) {
|
if (hasEsmFormat) {
|
||||||
const esmExports = getExports({
|
const esmExports = getExports({
|
||||||
...options,
|
...options,
|
||||||
@ -304,9 +320,13 @@ export function getUpdatedPackageJsonContent(
|
|||||||
|
|
||||||
if (options.generateExportsField) {
|
if (options.generateExportsField) {
|
||||||
for (const [exportEntry, filePath] of Object.entries(esmExports)) {
|
for (const [exportEntry, filePath] of Object.entries(esmExports)) {
|
||||||
|
if (!packageJson.exports[exportEntry]) {
|
||||||
packageJson.exports[exportEntry] ??= hasCjsFormat
|
packageJson.exports[exportEntry] ??= hasCjsFormat
|
||||||
? { import: filePath }
|
? { import: filePath }
|
||||||
: filePath;
|
: filePath;
|
||||||
|
} else if (typeof packageJson.exports[exportEntry] === 'object') {
|
||||||
|
packageJson.exports[exportEntry].import ??= filePath;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -327,24 +347,39 @@ export function getUpdatedPackageJsonContent(
|
|||||||
|
|
||||||
if (options.generateExportsField) {
|
if (options.generateExportsField) {
|
||||||
for (const [exportEntry, filePath] of Object.entries(cjsExports)) {
|
for (const [exportEntry, filePath] of Object.entries(cjsExports)) {
|
||||||
if (hasEsmFormat) {
|
if (!packageJson.exports[exportEntry]) {
|
||||||
packageJson.exports[exportEntry]['default'] ??= filePath;
|
packageJson.exports[exportEntry] ??= hasEsmFormat
|
||||||
} else {
|
? { default: filePath }
|
||||||
packageJson.exports[exportEntry] ??= filePath;
|
: filePath;
|
||||||
|
} else if (typeof packageJson.exports[exportEntry] === 'object') {
|
||||||
|
packageJson.exports[exportEntry].default ??= filePath;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!options.skipTypings) {
|
|
||||||
const mainFile = basename(options.main).replace(/\.[tj]s$/, '');
|
|
||||||
const relativeMainFileDir = getRelativeDirectoryToProjectRoot(
|
|
||||||
options.main,
|
|
||||||
options.projectRoot
|
|
||||||
);
|
|
||||||
const typingsFile = `${relativeMainFileDir}${mainFile}.d.ts`;
|
|
||||||
packageJson.types ??= typingsFile;
|
|
||||||
}
|
|
||||||
|
|
||||||
return packageJson;
|
return packageJson;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function getOutputDir(
|
||||||
|
options: Pick<
|
||||||
|
UpdatePackageJsonOption,
|
||||||
|
| 'main'
|
||||||
|
| 'rootDir'
|
||||||
|
| 'projectRoot'
|
||||||
|
| 'outputFileName'
|
||||||
|
| 'outputPath'
|
||||||
|
| 'packageJsonPath'
|
||||||
|
>
|
||||||
|
): string {
|
||||||
|
const packageJsonDir = options.packageJsonPath
|
||||||
|
? dirname(options.packageJsonPath)
|
||||||
|
: options.outputPath;
|
||||||
|
const relativeOutputPath = relative(packageJsonDir, options.outputPath);
|
||||||
|
const relativeMainDir = options.outputFileName
|
||||||
|
? ''
|
||||||
|
: relative(options.rootDir ?? options.projectRoot, dirname(options.main));
|
||||||
|
const outputDir = join(relativeOutputPath, relativeMainDir);
|
||||||
|
|
||||||
|
return outputDir === '.' ? `./` : `./${outputDir}/`;
|
||||||
|
}
|
||||||
|
|||||||
@ -2,33 +2,9 @@ import type { NxJsonConfiguration } from '@nx/devkit';
|
|||||||
import {
|
import {
|
||||||
ensureProjectIsExcludedFromPluginRegistrations,
|
ensureProjectIsExcludedFromPluginRegistrations,
|
||||||
ensureProjectIsIncludedInPluginRegistrations,
|
ensureProjectIsIncludedInPluginRegistrations,
|
||||||
} from './plugin-registrations';
|
} from './plugin';
|
||||||
|
|
||||||
describe('ensureProjectIsIncludedInPluginRegistrations', () => {
|
describe('ensureProjectIsIncludedInPluginRegistrations', () => {
|
||||||
it('should do nothing when there is no `plugin` entry', () => {
|
|
||||||
const nxJson: NxJsonConfiguration = {};
|
|
||||||
|
|
||||||
ensureProjectIsIncludedInPluginRegistrations(nxJson, 'packages/pkg1');
|
|
||||||
|
|
||||||
expect(nxJson).toStrictEqual({});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should do nothing when the there are no plugins', () => {
|
|
||||||
const nxJson: NxJsonConfiguration = { plugins: [] };
|
|
||||||
|
|
||||||
ensureProjectIsIncludedInPluginRegistrations(nxJson, 'packages/pkg1');
|
|
||||||
|
|
||||||
expect(nxJson).toStrictEqual({ plugins: [] });
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should do nothing when the are no registrations for the `@nx/js/typescript` plugin', () => {
|
|
||||||
const nxJson: NxJsonConfiguration = { plugins: ['@foo/bar/plugin'] };
|
|
||||||
|
|
||||||
ensureProjectIsIncludedInPluginRegistrations(nxJson, 'packages/pkg1');
|
|
||||||
|
|
||||||
expect(nxJson).toStrictEqual({ plugins: ['@foo/bar/plugin'] });
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should do nothing when `include`/`exclude` are not set in a plugin registration that infers both targets', () => {
|
it('should do nothing when `include`/`exclude` are not set in a plugin registration that infers both targets', () => {
|
||||||
const originalNxJson: NxJsonConfiguration = {
|
const originalNxJson: NxJsonConfiguration = {
|
||||||
plugins: [
|
plugins: [
|
||||||
@ -203,6 +179,44 @@ describe('ensureProjectIsIncludedInPluginRegistrations', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should exclude a project from a plugin registration with a different build target nama and add a new plugin registration that includes it', () => {
|
||||||
|
const nxJson: NxJsonConfiguration = {
|
||||||
|
plugins: [
|
||||||
|
{
|
||||||
|
plugin: '@nx/js/typescript',
|
||||||
|
options: { typecheck: { targetName: 'typecheck' } },
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
ensureProjectIsIncludedInPluginRegistrations(
|
||||||
|
nxJson,
|
||||||
|
'packages/pkg1',
|
||||||
|
'build-tsc'
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(nxJson).toStrictEqual({
|
||||||
|
plugins: [
|
||||||
|
{
|
||||||
|
plugin: '@nx/js/typescript',
|
||||||
|
exclude: ['packages/pkg1/*'],
|
||||||
|
options: { typecheck: { targetName: 'typecheck' } },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
plugin: '@nx/js/typescript',
|
||||||
|
include: ['packages/pkg1/*'],
|
||||||
|
options: {
|
||||||
|
typecheck: { targetName: 'typecheck' },
|
||||||
|
build: {
|
||||||
|
targetName: 'build-tsc',
|
||||||
|
configName: 'tsconfig.lib.json',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
it('should include a project in a plugin registration that infers both targets and with `include` set but not including the project', () => {
|
it('should include a project in a plugin registration that infers both targets and with `include` set but not including the project', () => {
|
||||||
const nxJson: NxJsonConfiguration = {
|
const nxJson: NxJsonConfiguration = {
|
||||||
plugins: [
|
plugins: [
|
||||||
@ -239,6 +253,57 @@ describe('ensureProjectIsIncludedInPluginRegistrations', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should not include a project in a plugin registration that infers both targets with a different build target name and with `include` set but not including the project', () => {
|
||||||
|
const nxJson: NxJsonConfiguration = {
|
||||||
|
plugins: [
|
||||||
|
{
|
||||||
|
plugin: '@nx/js/typescript',
|
||||||
|
include: ['packages/pkg1/*'],
|
||||||
|
options: {
|
||||||
|
typecheck: { targetName: 'typecheck' },
|
||||||
|
build: {
|
||||||
|
targetName: 'build',
|
||||||
|
configName: 'tsconfig.lib.json',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
ensureProjectIsIncludedInPluginRegistrations(
|
||||||
|
nxJson,
|
||||||
|
'packages/pkg2',
|
||||||
|
'build-tsc'
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(nxJson).toStrictEqual({
|
||||||
|
plugins: [
|
||||||
|
{
|
||||||
|
plugin: '@nx/js/typescript',
|
||||||
|
include: ['packages/pkg1/*'],
|
||||||
|
options: {
|
||||||
|
typecheck: { targetName: 'typecheck' },
|
||||||
|
build: {
|
||||||
|
targetName: 'build',
|
||||||
|
configName: 'tsconfig.lib.json',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
plugin: '@nx/js/typescript',
|
||||||
|
include: ['packages/pkg2/*'],
|
||||||
|
options: {
|
||||||
|
typecheck: { targetName: 'typecheck' },
|
||||||
|
build: {
|
||||||
|
targetName: 'build-tsc',
|
||||||
|
configName: 'tsconfig.lib.json',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
it('should add a new plugin registration including the project when there is an existing plugin registration that infers both targets and with `exclude` set excluding the project', () => {
|
it('should add a new plugin registration including the project when there is an existing plugin registration that infers both targets and with `exclude` set excluding the project', () => {
|
||||||
const nxJson: NxJsonConfiguration = {
|
const nxJson: NxJsonConfiguration = {
|
||||||
plugins: [
|
plugins: [
|
||||||
@ -285,6 +350,42 @@ describe('ensureProjectIsIncludedInPluginRegistrations', () => {
|
|||||||
],
|
],
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should remove glob pattern from `exclude` when it matches exactly the project root glob pattern', () => {
|
||||||
|
const nxJson: NxJsonConfiguration = {
|
||||||
|
plugins: [
|
||||||
|
{
|
||||||
|
plugin: '@nx/js/typescript',
|
||||||
|
exclude: ['packages/pkg1/*', 'packages/pkg2/*'],
|
||||||
|
options: {
|
||||||
|
typecheck: { targetName: 'typecheck' },
|
||||||
|
build: {
|
||||||
|
targetName: 'build',
|
||||||
|
configName: 'tsconfig.lib.json',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
ensureProjectIsIncludedInPluginRegistrations(nxJson, 'packages/pkg1');
|
||||||
|
|
||||||
|
expect(nxJson).toStrictEqual({
|
||||||
|
plugins: [
|
||||||
|
{
|
||||||
|
plugin: '@nx/js/typescript',
|
||||||
|
exclude: ['packages/pkg2/*'],
|
||||||
|
options: {
|
||||||
|
typecheck: { targetName: 'typecheck' },
|
||||||
|
build: {
|
||||||
|
targetName: 'build',
|
||||||
|
configName: 'tsconfig.lib.json',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('ensureProjectIsExcludedFromPluginRegistrations', () => {
|
describe('ensureProjectIsExcludedFromPluginRegistrations', () => {
|
||||||
@ -3,19 +3,14 @@ import type {
|
|||||||
NxJsonConfiguration,
|
NxJsonConfiguration,
|
||||||
} from '@nx/devkit';
|
} from '@nx/devkit';
|
||||||
import { findMatchingConfigFiles } from 'nx/src/devkit-internals';
|
import { findMatchingConfigFiles } from 'nx/src/devkit-internals';
|
||||||
import type { TscPluginOptions } from '../../../plugins/typescript/plugin';
|
import type { TscPluginOptions } from '../../plugins/typescript/plugin';
|
||||||
|
|
||||||
export function ensureProjectIsIncludedInPluginRegistrations(
|
export function ensureProjectIsIncludedInPluginRegistrations(
|
||||||
nxJson: NxJsonConfiguration,
|
nxJson: NxJsonConfiguration,
|
||||||
projectRoot: string
|
projectRoot: string,
|
||||||
|
buildTargetName: string = 'build'
|
||||||
): void {
|
): void {
|
||||||
if (
|
nxJson.plugins ??= [];
|
||||||
!nxJson.plugins?.length ||
|
|
||||||
!nxJson.plugins.some(isTypeScriptPluginRegistration)
|
|
||||||
) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
let isIncluded = false;
|
let isIncluded = false;
|
||||||
let index = 0;
|
let index = 0;
|
||||||
for (const registration of nxJson.plugins) {
|
for (const registration of nxJson.plugins) {
|
||||||
@ -26,7 +21,7 @@ export function ensureProjectIsIncludedInPluginRegistrations(
|
|||||||
|
|
||||||
if (typeof registration === 'string') {
|
if (typeof registration === 'string') {
|
||||||
// if it's a string all projects are included but the are no user-specified options
|
// if it's a string all projects are included but the are no user-specified options
|
||||||
// and the `build` task is not inferred by default, so we need to exclude it
|
// and the build task is not inferred by default, so we need to exclude it
|
||||||
nxJson.plugins[index] = {
|
nxJson.plugins[index] = {
|
||||||
plugin: '@nx/js/typescript',
|
plugin: '@nx/js/typescript',
|
||||||
exclude: [`${projectRoot}/*`],
|
exclude: [`${projectRoot}/*`],
|
||||||
@ -41,20 +36,25 @@ export function ensureProjectIsIncludedInPluginRegistrations(
|
|||||||
);
|
);
|
||||||
if (matchingConfigFiles.length) {
|
if (matchingConfigFiles.length) {
|
||||||
// it's included by the plugin registration, check if the user-specified options would result
|
// it's included by the plugin registration, check if the user-specified options would result
|
||||||
// in a `build` task being inferred, if not, we need to exclude it
|
// in the appropriate build task being inferred, if not, we need to exclude it
|
||||||
if (registration.options?.typecheck && registration.options?.build) {
|
if (
|
||||||
// it has the desired options, do nothing
|
registration.options?.typecheck !== false &&
|
||||||
|
matchesBuildTarget(registration.options?.build, buildTargetName)
|
||||||
|
) {
|
||||||
|
// it has the desired options, do nothing, but continue processing
|
||||||
|
// other registrations to exclude as needed
|
||||||
isIncluded = true;
|
isIncluded = true;
|
||||||
} else {
|
} else {
|
||||||
// it would not have the `build` task inferred, so we need to exclude it
|
// it would not have the typecheck or build task inferred, so we need to exclude it
|
||||||
registration.exclude ??= [];
|
registration.exclude ??= [];
|
||||||
registration.exclude.push(`${projectRoot}/*`);
|
registration.exclude.push(`${projectRoot}/*`);
|
||||||
}
|
}
|
||||||
} else if (
|
} else if (
|
||||||
registration.options?.typecheck &&
|
!isIncluded &&
|
||||||
registration.options?.build &&
|
registration.options?.typecheck !== false &&
|
||||||
!registration.exclude?.length
|
matchesBuildTarget(registration.options?.build, buildTargetName)
|
||||||
) {
|
) {
|
||||||
|
if (!registration.exclude?.length) {
|
||||||
// negative pattern are not supported by the `exclude` option so we
|
// negative pattern are not supported by the `exclude` option so we
|
||||||
// can't update it to not exclude the project, so we only update the
|
// can't update it to not exclude the project, so we only update the
|
||||||
// plugin registration if there's no `exclude` option, in which case
|
// plugin registration if there's no `exclude` option, in which case
|
||||||
@ -63,21 +63,31 @@ export function ensureProjectIsIncludedInPluginRegistrations(
|
|||||||
isIncluded = true;
|
isIncluded = true;
|
||||||
registration.include ??= [];
|
registration.include ??= [];
|
||||||
registration.include.push(`${projectRoot}/*`);
|
registration.include.push(`${projectRoot}/*`);
|
||||||
|
} else if (registration.exclude?.includes(`${projectRoot}/*`)) {
|
||||||
|
isIncluded = true;
|
||||||
|
registration.exclude = registration.exclude.filter(
|
||||||
|
(e) => e !== `${projectRoot}/*`
|
||||||
|
);
|
||||||
|
if (!registration.exclude.length) {
|
||||||
|
// if there's no `exclude` option left, we can remove the exclude option
|
||||||
|
delete registration.exclude;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
index++;
|
index++;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!isIncluded) {
|
if (!isIncluded) {
|
||||||
// the project is not included by any plugin registration with an inferred `build` task,
|
// the project is not included by any plugin registration with an inferred build task
|
||||||
// so we create a new plugin registration for it
|
// with the given name, so we create a new plugin registration for it
|
||||||
nxJson.plugins.push({
|
nxJson.plugins.push({
|
||||||
plugin: '@nx/js/typescript',
|
plugin: '@nx/js/typescript',
|
||||||
include: [`${projectRoot}/*`],
|
include: [`${projectRoot}/*`],
|
||||||
options: {
|
options: {
|
||||||
typecheck: { targetName: 'typecheck' },
|
typecheck: { targetName: 'typecheck' },
|
||||||
build: {
|
build: {
|
||||||
targetName: 'build',
|
targetName: buildTargetName,
|
||||||
configName: 'tsconfig.lib.json',
|
configName: 'tsconfig.lib.json',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -139,3 +149,21 @@ function isTypeScriptPluginRegistration(
|
|||||||
(typeof plugin !== 'string' && plugin.plugin === '@nx/js/typescript')
|
(typeof plugin !== 'string' && plugin.plugin === '@nx/js/typescript')
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function matchesBuildTarget(
|
||||||
|
buildOptions: TscPluginOptions['build'],
|
||||||
|
buildTargetName: string
|
||||||
|
): boolean {
|
||||||
|
if (buildOptions === undefined || buildOptions === false) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (buildOptions === true && buildTargetName === 'build') {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
typeof buildOptions === 'object' &&
|
||||||
|
buildOptions.targetName === buildTargetName
|
||||||
|
);
|
||||||
|
}
|
||||||
@ -1,22 +1,25 @@
|
|||||||
import { offsetFromRoot, Tree, updateJson, workspaceRoot } from '@nx/devkit';
|
import { offsetFromRoot, Tree, updateJson, workspaceRoot } from '@nx/devkit';
|
||||||
import { existsSync } from 'fs';
|
import { existsSync } from 'fs';
|
||||||
import { dirname, join } from 'path';
|
import { dirname, join } from 'path';
|
||||||
import * as ts from 'typescript';
|
import type * as ts from 'typescript';
|
||||||
import { ensureTypescript } from './ensure-typescript';
|
import { ensureTypescript } from './ensure-typescript';
|
||||||
|
|
||||||
let tsModule: typeof import('typescript');
|
let tsModule: typeof import('typescript');
|
||||||
|
|
||||||
export function readTsConfig(tsConfigPath: string): ts.ParsedCommandLine {
|
export function readTsConfig(
|
||||||
|
tsConfigPath: string,
|
||||||
|
sys?: ts.System
|
||||||
|
): ts.ParsedCommandLine {
|
||||||
if (!tsModule) {
|
if (!tsModule) {
|
||||||
tsModule = require('typescript');
|
tsModule = require('typescript');
|
||||||
}
|
}
|
||||||
const readResult = tsModule.readConfigFile(
|
|
||||||
tsConfigPath,
|
sys ??= tsModule.sys;
|
||||||
tsModule.sys.readFile
|
|
||||||
);
|
const readResult = tsModule.readConfigFile(tsConfigPath, sys.readFile);
|
||||||
return tsModule.parseJsonConfigFileContent(
|
return tsModule.parseJsonConfigFileContent(
|
||||||
readResult.config,
|
readResult.config,
|
||||||
tsModule.sys,
|
sys,
|
||||||
dirname(tsConfigPath)
|
dirname(tsConfigPath)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -71,13 +71,13 @@ export async function reactNativeLibraryGeneratorInternal(
|
|||||||
tasks.push(ensureDependencies(host));
|
tasks.push(ensureDependencies(host));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
createFiles(host, options);
|
||||||
|
|
||||||
const addProjectTask = await addProject(host, options);
|
const addProjectTask = await addProject(host, options);
|
||||||
if (addProjectTask) {
|
if (addProjectTask) {
|
||||||
tasks.push(addProjectTask);
|
tasks.push(addProjectTask);
|
||||||
}
|
}
|
||||||
|
|
||||||
createFiles(host, options);
|
|
||||||
|
|
||||||
const lintTask = await addLinting(host, {
|
const lintTask = await addLinting(host, {
|
||||||
...options,
|
...options,
|
||||||
projectName: options.name,
|
projectName: options.name,
|
||||||
|
|||||||
@ -56,7 +56,7 @@ describe('configurationGenerator', () => {
|
|||||||
it('should support --main option', async () => {
|
it('should support --main option', async () => {
|
||||||
await configurationGenerator(tree, {
|
await configurationGenerator(tree, {
|
||||||
project: 'mypkg',
|
project: 'mypkg',
|
||||||
main: './src/index.ts',
|
main: './libs/mypkg/src/index.ts',
|
||||||
});
|
});
|
||||||
|
|
||||||
const rollupConfig = tree.read('libs/mypkg/rollup.config.js', 'utf-8');
|
const rollupConfig = tree.read('libs/mypkg/rollup.config.js', 'utf-8');
|
||||||
@ -85,7 +85,7 @@ module.exports = withNx(
|
|||||||
it('should support --tsConfig option', async () => {
|
it('should support --tsConfig option', async () => {
|
||||||
await configurationGenerator(tree, {
|
await configurationGenerator(tree, {
|
||||||
project: 'mypkg',
|
project: 'mypkg',
|
||||||
tsConfig: './tsconfig.custom.json',
|
tsConfig: 'libs/mypkg/tsconfig.custom.json',
|
||||||
});
|
});
|
||||||
|
|
||||||
const rollupConfig = tree.read('libs/mypkg/rollup.config.js', 'utf-8');
|
const rollupConfig = tree.read('libs/mypkg/rollup.config.js', 'utf-8');
|
||||||
|
|||||||
@ -3,24 +3,31 @@ import {
|
|||||||
GeneratorCallback,
|
GeneratorCallback,
|
||||||
joinPathFragments,
|
joinPathFragments,
|
||||||
offsetFromRoot,
|
offsetFromRoot,
|
||||||
|
readJson,
|
||||||
readNxJson,
|
readNxJson,
|
||||||
readProjectConfiguration,
|
readProjectConfiguration,
|
||||||
runTasksInSerial,
|
runTasksInSerial,
|
||||||
stripIndents,
|
|
||||||
Tree,
|
Tree,
|
||||||
|
updateJson,
|
||||||
updateProjectConfiguration,
|
updateProjectConfiguration,
|
||||||
writeJson,
|
writeJson,
|
||||||
} from '@nx/devkit';
|
} from '@nx/devkit';
|
||||||
import { getImportPath } from '@nx/js/src/utils/get-import-path';
|
|
||||||
import { isUsingTsSolutionSetup } from '@nx/js/src/utils/typescript/ts-solution-setup';
|
|
||||||
|
|
||||||
import { rollupInitGenerator } from '../init/init';
|
|
||||||
import { RollupExecutorOptions } from '../../executors/rollup/schema';
|
|
||||||
import { RollupProjectSchema } from './schema';
|
|
||||||
import { addBuildTargetDefaults } from '@nx/devkit/src/generators/target-defaults-utils';
|
import { addBuildTargetDefaults } from '@nx/devkit/src/generators/target-defaults-utils';
|
||||||
|
import { getUpdatedPackageJsonContent, readTsConfig } from '@nx/js';
|
||||||
|
import { getImportPath } from '@nx/js/src/utils/get-import-path';
|
||||||
|
import { ensureTypescript } from '@nx/js/src/utils/typescript/ensure-typescript';
|
||||||
|
import { isUsingTsSolutionSetup } from '@nx/js/src/utils/typescript/ts-solution-setup';
|
||||||
|
import { dirname, join, relative } from 'node:path/posix';
|
||||||
|
import { mergeTargetConfigurations } from 'nx/src/devkit-internals';
|
||||||
|
import type { PackageJson } from 'nx/src/utils/package-json';
|
||||||
|
import { RollupExecutorOptions } from '../../executors/rollup/schema';
|
||||||
|
import { RollupWithNxPluginOptions } from '../../plugins/with-nx/with-nx-options';
|
||||||
import { ensureDependencies } from '../../utils/ensure-dependencies';
|
import { ensureDependencies } from '../../utils/ensure-dependencies';
|
||||||
import { hasPlugin } from '../../utils/has-plugin';
|
import { hasPlugin } from '../../utils/has-plugin';
|
||||||
import { RollupWithNxPluginOptions } from '../../plugins/with-nx/with-nx-options';
|
import { rollupInitGenerator } from '../init/init';
|
||||||
|
import { RollupProjectSchema } from './schema';
|
||||||
|
|
||||||
|
let ts: typeof import('typescript');
|
||||||
|
|
||||||
export async function configurationGenerator(
|
export async function configurationGenerator(
|
||||||
tree: Tree,
|
tree: Tree,
|
||||||
@ -39,15 +46,20 @@ export async function configurationGenerator(
|
|||||||
tasks.push(ensureDependencies(tree, options));
|
tasks.push(ensureDependencies(tree, options));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const isTsSolutionSetup = isUsingTsSolutionSetup(tree);
|
||||||
|
let outputConfig: OutputConfig | undefined;
|
||||||
if (hasPlugin(tree)) {
|
if (hasPlugin(tree)) {
|
||||||
createRollupConfig(tree, options);
|
outputConfig = createRollupConfig(tree, options, isTsSolutionSetup);
|
||||||
} else {
|
} else {
|
||||||
options.buildTarget ??= 'build';
|
options.buildTarget ??= 'build';
|
||||||
checkForTargetConflicts(tree, options);
|
checkForTargetConflicts(tree, options);
|
||||||
addBuildTarget(tree, options);
|
addBuildTarget(tree, options, isTsSolutionSetup);
|
||||||
}
|
}
|
||||||
|
|
||||||
addPackageJson(tree, options);
|
updatePackageJson(tree, options, outputConfig, isTsSolutionSetup);
|
||||||
|
if (isTsSolutionSetup) {
|
||||||
|
updateTsConfig(tree, options);
|
||||||
|
}
|
||||||
|
|
||||||
if (!options.skipFormat) {
|
if (!options.skipFormat) {
|
||||||
await formatFiles(tree);
|
await formatFiles(tree);
|
||||||
@ -56,20 +68,34 @@ export async function configurationGenerator(
|
|||||||
return runTasksInSerial(...tasks);
|
return runTasksInSerial(...tasks);
|
||||||
}
|
}
|
||||||
|
|
||||||
function createRollupConfig(tree: Tree, options: RollupProjectSchema) {
|
type OutputConfig = {
|
||||||
const isUsingTsPlugin = isUsingTsSolutionSetup(tree);
|
main: string;
|
||||||
|
outputPath: string;
|
||||||
|
};
|
||||||
|
function createRollupConfig(
|
||||||
|
tree: Tree,
|
||||||
|
options: RollupProjectSchema,
|
||||||
|
isTsSolutionSetup: boolean
|
||||||
|
): OutputConfig {
|
||||||
const project = readProjectConfiguration(tree, options.project);
|
const project = readProjectConfiguration(tree, options.project);
|
||||||
const buildOptions: RollupWithNxPluginOptions = {
|
const main = options.main
|
||||||
outputPath: isUsingTsPlugin
|
? `./${relative(project.root, options.main)}`
|
||||||
|
: './src/index.ts';
|
||||||
|
const outputPath = isTsSolutionSetup
|
||||||
? './dist'
|
? './dist'
|
||||||
: joinPathFragments(
|
: joinPathFragments(
|
||||||
offsetFromRoot(project.root),
|
offsetFromRoot(project.root),
|
||||||
'dist',
|
'dist',
|
||||||
project.root === '.' ? project.name : project.root
|
project.root === '.' ? project.name : project.root
|
||||||
),
|
);
|
||||||
|
|
||||||
|
const buildOptions: RollupWithNxPluginOptions = {
|
||||||
|
outputPath,
|
||||||
compiler: options.compiler ?? 'babel',
|
compiler: options.compiler ?? 'babel',
|
||||||
main: options.main ?? './src/index.ts',
|
main,
|
||||||
tsConfig: options.tsConfig ?? './tsconfig.lib.json',
|
tsConfig: options.tsConfig
|
||||||
|
? `./${relative(project.root, options.tsConfig)}`
|
||||||
|
: './tsconfig.lib.json',
|
||||||
};
|
};
|
||||||
|
|
||||||
tree.write(
|
tree.write(
|
||||||
@ -82,8 +108,12 @@ module.exports = withNx(
|
|||||||
outputPath: '${buildOptions.outputPath}',
|
outputPath: '${buildOptions.outputPath}',
|
||||||
tsConfig: '${buildOptions.tsConfig}',
|
tsConfig: '${buildOptions.tsConfig}',
|
||||||
compiler: '${buildOptions.compiler}',
|
compiler: '${buildOptions.compiler}',
|
||||||
format: ${JSON.stringify(options.format ?? ['esm'])},
|
format: ${JSON.stringify(options.format ?? ['esm'])},${
|
||||||
assets: [{ input: '.', output: '.', glob:'*.md' }],
|
!isTsSolutionSetup
|
||||||
|
? `
|
||||||
|
assets: [{ input: '.', output: '.', glob:'*.md' }],`
|
||||||
|
: ''
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
// Provide additional rollup configuration here. See: https://rollupjs.org/configuration-options
|
// Provide additional rollup configuration here. See: https://rollupjs.org/configuration-options
|
||||||
@ -93,6 +123,11 @@ module.exports = withNx(
|
|||||||
);
|
);
|
||||||
`
|
`
|
||||||
);
|
);
|
||||||
|
|
||||||
|
return {
|
||||||
|
main: joinPathFragments(project.root, main),
|
||||||
|
outputPath: joinPathFragments(project.root, outputPath),
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function checkForTargetConflicts(tree: Tree, options: RollupProjectSchema) {
|
function checkForTargetConflicts(tree: Tree, options: RollupProjectSchema) {
|
||||||
@ -105,52 +140,120 @@ function checkForTargetConflicts(tree: Tree, options: RollupProjectSchema) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function addPackageJson(tree: Tree, options: RollupProjectSchema) {
|
function updatePackageJson(
|
||||||
|
tree: Tree,
|
||||||
|
options: RollupProjectSchema,
|
||||||
|
outputConfig: OutputConfig | undefined,
|
||||||
|
isTsSolutionSetup: boolean
|
||||||
|
) {
|
||||||
const project = readProjectConfiguration(tree, options.project);
|
const project = readProjectConfiguration(tree, options.project);
|
||||||
const packageJsonPath = joinPathFragments(project.root, 'package.json');
|
|
||||||
|
|
||||||
if (!tree.exists(packageJsonPath)) {
|
const packageJsonPath = join(project.root, 'package.json');
|
||||||
const importPath =
|
let packageJson: PackageJson;
|
||||||
options.importPath || getImportPath(tree, options.project);
|
if (tree.exists(packageJsonPath)) {
|
||||||
writeJson(tree, packageJsonPath, {
|
if (!isTsSolutionSetup) {
|
||||||
name: importPath,
|
return;
|
||||||
version: '0.0.1',
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
packageJson = readJson(tree, packageJsonPath);
|
||||||
|
} else {
|
||||||
|
packageJson = {
|
||||||
|
name: options.importPath || getImportPath(tree, options.project),
|
||||||
|
version: '0.0.1',
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isTsSolutionSetup) {
|
||||||
|
let main: string;
|
||||||
|
let outputPath: string;
|
||||||
|
if (outputConfig) {
|
||||||
|
({ main, outputPath } = outputConfig);
|
||||||
|
} else {
|
||||||
|
// target must exist if we don't receive an outputConfig
|
||||||
|
const projectTarget = project.targets[options.buildTarget];
|
||||||
|
const nxJson = readNxJson(tree);
|
||||||
|
const mergedTarget = mergeTargetConfigurations(
|
||||||
|
projectTarget,
|
||||||
|
(projectTarget.executor
|
||||||
|
? nxJson.targetDefaults?.[projectTarget.executor]
|
||||||
|
: undefined) ?? nxJson.targetDefaults?.[options.buildTarget]
|
||||||
|
);
|
||||||
|
({ main, outputPath } = mergedTarget.options);
|
||||||
|
}
|
||||||
|
|
||||||
|
packageJson = getUpdatedPackageJsonContent(packageJson, {
|
||||||
|
main,
|
||||||
|
outputPath,
|
||||||
|
projectRoot: project.root,
|
||||||
|
rootDir: dirname(main),
|
||||||
|
generateExportsField: true,
|
||||||
|
packageJsonPath,
|
||||||
|
format: options.format ?? ['esm'],
|
||||||
|
outputFileExtensionForCjs: '.cjs.js',
|
||||||
|
outputFileExtensionForEsm: '.esm.js',
|
||||||
|
});
|
||||||
|
|
||||||
|
// rollup has a specific declaration file generation not handled by the util above,
|
||||||
|
// adjust accordingly
|
||||||
|
const typingsFile = (packageJson.module ?? packageJson.main).replace(
|
||||||
|
/\.js$/,
|
||||||
|
'.d.ts'
|
||||||
|
);
|
||||||
|
packageJson.types = typingsFile;
|
||||||
|
packageJson.exports['.'].types = typingsFile;
|
||||||
|
}
|
||||||
|
|
||||||
|
writeJson(tree, packageJsonPath, packageJson);
|
||||||
}
|
}
|
||||||
|
|
||||||
function addBuildTarget(tree: Tree, options: RollupProjectSchema) {
|
function addBuildTarget(
|
||||||
|
tree: Tree,
|
||||||
|
options: RollupProjectSchema,
|
||||||
|
isTsSolutionSetup: boolean
|
||||||
|
) {
|
||||||
addBuildTargetDefaults(tree, '@nx/rollup:rollup', options.buildTarget);
|
addBuildTargetDefaults(tree, '@nx/rollup:rollup', options.buildTarget);
|
||||||
const project = readProjectConfiguration(tree, options.project);
|
const project = readProjectConfiguration(tree, options.project);
|
||||||
const prevBuildOptions = project.targets?.[options.buildTarget]?.options;
|
const prevBuildOptions = project.targets?.[options.buildTarget]?.options;
|
||||||
|
|
||||||
|
options.tsConfig ??=
|
||||||
|
prevBuildOptions?.tsConfig ??
|
||||||
|
joinPathFragments(project.root, 'tsconfig.lib.json');
|
||||||
|
|
||||||
|
let outputPath = prevBuildOptions?.outputPath;
|
||||||
|
if (!outputPath) {
|
||||||
|
outputPath = isTsSolutionSetup
|
||||||
|
? joinPathFragments(project.root, 'dist')
|
||||||
|
: joinPathFragments(
|
||||||
|
'dist',
|
||||||
|
project.root === '.' ? project.name : project.root
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
const buildOptions: RollupExecutorOptions = {
|
const buildOptions: RollupExecutorOptions = {
|
||||||
main:
|
main:
|
||||||
options.main ??
|
options.main ??
|
||||||
prevBuildOptions?.main ??
|
prevBuildOptions?.main ??
|
||||||
joinPathFragments(project.root, 'src/index.ts'),
|
joinPathFragments(project.root, 'src/index.ts'),
|
||||||
outputPath:
|
outputPath,
|
||||||
prevBuildOptions?.outputPath ??
|
tsConfig: options.tsConfig,
|
||||||
joinPathFragments(
|
// TODO(leo): see if we can use this when updating the package.json for the new setup
|
||||||
'dist',
|
// additionalEntryPoints: prevBuildOptions?.additionalEntryPoints,
|
||||||
project.root === '.' ? project.name : project.root
|
// generateExportsField: prevBuildOptions?.generateExportsField,
|
||||||
),
|
|
||||||
tsConfig:
|
|
||||||
options.tsConfig ??
|
|
||||||
prevBuildOptions?.tsConfig ??
|
|
||||||
joinPathFragments(project.root, 'tsconfig.lib.json'),
|
|
||||||
additionalEntryPoints: prevBuildOptions?.additionalEntryPoints,
|
|
||||||
generateExportsField: prevBuildOptions?.generateExportsField,
|
|
||||||
compiler: options.compiler ?? 'babel',
|
compiler: options.compiler ?? 'babel',
|
||||||
project: `${project.root}/package.json`,
|
project: `${project.root}/package.json`,
|
||||||
external: options.external,
|
external: options.external,
|
||||||
format: options.format,
|
format: options.format ?? isTsSolutionSetup ? ['esm'] : undefined,
|
||||||
};
|
};
|
||||||
|
|
||||||
if (options.rollupConfig) {
|
if (options.rollupConfig) {
|
||||||
buildOptions.rollupConfig = options.rollupConfig;
|
buildOptions.rollupConfig = options.rollupConfig;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!isTsSolutionSetup) {
|
||||||
|
buildOptions.additionalEntryPoints =
|
||||||
|
prevBuildOptions?.additionalEntryPoints;
|
||||||
|
buildOptions.generateExportsField = prevBuildOptions?.generateExportsField;
|
||||||
|
|
||||||
if (tree.exists(joinPathFragments(project.root, 'README.md'))) {
|
if (tree.exists(joinPathFragments(project.root, 'README.md'))) {
|
||||||
buildOptions.assets = [
|
buildOptions.assets = [
|
||||||
{
|
{
|
||||||
@ -160,6 +263,7 @@ function addBuildTarget(tree: Tree, options: RollupProjectSchema) {
|
|||||||
},
|
},
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
updateProjectConfiguration(tree, options.project, {
|
updateProjectConfiguration(tree, options.project, {
|
||||||
...project,
|
...project,
|
||||||
@ -174,4 +278,35 @@ function addBuildTarget(tree: Tree, options: RollupProjectSchema) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function updateTsConfig(tree: Tree, options: RollupProjectSchema): void {
|
||||||
|
const project = readProjectConfiguration(tree, options.project);
|
||||||
|
const tsconfigPath =
|
||||||
|
options.tsConfig ?? joinPathFragments(project.root, 'tsconfig.lib.json');
|
||||||
|
if (!tree.exists(tsconfigPath)) {
|
||||||
|
throw new Error(
|
||||||
|
`The '${tsconfigPath}' file doesn't exist. Provide the 'tsConfig' option with the correct path pointing to the tsconfig file to use for builds.`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!ts) {
|
||||||
|
ts = ensureTypescript();
|
||||||
|
}
|
||||||
|
|
||||||
|
const parsedTsConfig = readTsConfig(tsconfigPath, {
|
||||||
|
...ts.sys,
|
||||||
|
readFile: (p) => tree.read(p, 'utf-8'),
|
||||||
|
fileExists: (p) => tree.exists(p),
|
||||||
|
});
|
||||||
|
|
||||||
|
updateJson(tree, tsconfigPath, (json) => {
|
||||||
|
if (parsedTsConfig.options.module === ts.ModuleKind.NodeNext) {
|
||||||
|
json.compilerOptions ??= {};
|
||||||
|
json.compilerOptions.module = 'esnext';
|
||||||
|
json.compilerOptions.moduleResolution = 'bundler';
|
||||||
|
}
|
||||||
|
|
||||||
|
return json;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
export default configurationGenerator;
|
export default configurationGenerator;
|
||||||
|
|||||||
@ -25,13 +25,13 @@
|
|||||||
},
|
},
|
||||||
"main": {
|
"main": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"description": "Path relative to the workspace root for the main entry file. Defaults to '<projectRoot>/src/main.ts'.",
|
"description": "Path relative to the workspace root for the main entry file. Defaults to '<projectRoot>/src/index.ts'.",
|
||||||
"alias": "entryFile",
|
"alias": "entryFile",
|
||||||
"x-priority": "important"
|
"x-priority": "important"
|
||||||
},
|
},
|
||||||
"tsConfig": {
|
"tsConfig": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"description": "Path relative to the workspace root for the tsconfig file to build with. Defaults to '<projectRoot>/tsconfig.app.json'.",
|
"description": "Path relative to the workspace root for the tsconfig file to build with. Defaults to '<projectRoot>/tsconfig.lib.json'.",
|
||||||
"x-priority": "important"
|
"x-priority": "important"
|
||||||
},
|
},
|
||||||
"skipFormat": {
|
"skipFormat": {
|
||||||
|
|||||||
@ -76,6 +76,12 @@ export interface RollupWithNxPluginOptions {
|
|||||||
* The path to tsconfig file.
|
* The path to tsconfig file.
|
||||||
*/
|
*/
|
||||||
tsConfig: string;
|
tsConfig: string;
|
||||||
|
/**
|
||||||
|
* Whether to generate a package.json file in the output path. It's not supported when the workspace is
|
||||||
|
* set up with TypeScript Project References along with the package managers' Workspaces feature. Otherwise,
|
||||||
|
* it defaults to `true`.
|
||||||
|
*/
|
||||||
|
generatePackageJson?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface AssetGlobPattern {
|
export interface AssetGlobPattern {
|
||||||
|
|||||||
@ -28,6 +28,7 @@ import { deleteOutput } from '../delete-output';
|
|||||||
import { AssetGlobPattern, RollupWithNxPluginOptions } from './with-nx-options';
|
import { AssetGlobPattern, RollupWithNxPluginOptions } from './with-nx-options';
|
||||||
import { normalizeOptions } from './normalize-options';
|
import { normalizeOptions } from './normalize-options';
|
||||||
import { PackageJson } from 'nx/src/utils/package-json';
|
import { PackageJson } from 'nx/src/utils/package-json';
|
||||||
|
import { isUsingTsSolutionSetup } from '@nx/js/src/utils/typescript/ts-solution-setup';
|
||||||
|
|
||||||
// These use require because the ES import isn't correct.
|
// These use require because the ES import isn't correct.
|
||||||
const commonjs = require('@rollup/plugin-commonjs');
|
const commonjs = require('@rollup/plugin-commonjs');
|
||||||
@ -182,6 +183,22 @@ export function withNx(
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!global.NX_GRAPH_CREATION) {
|
if (!global.NX_GRAPH_CREATION) {
|
||||||
|
const isTsSolutionSetup = 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;
|
||||||
|
}
|
||||||
|
|
||||||
finalConfig.plugins = [
|
finalConfig.plugins = [
|
||||||
copy({
|
copy({
|
||||||
targets: convertCopyAssetsToRollupOptions(
|
targets: convertCopyAssetsToRollupOptions(
|
||||||
@ -247,7 +264,7 @@ export function withNx(
|
|||||||
}),
|
}),
|
||||||
commonjs(),
|
commonjs(),
|
||||||
analyze(),
|
analyze(),
|
||||||
generatePackageJson(options, packageJson),
|
options.generatePackageJson && generatePackageJson(options, packageJson),
|
||||||
];
|
];
|
||||||
if (Array.isArray(rollupConfig.plugins)) {
|
if (Array.isArray(rollupConfig.plugins)) {
|
||||||
finalConfig.plugins.push(...rollupConfig.plugins);
|
finalConfig.plugins.push(...rollupConfig.plugins);
|
||||||
|
|||||||
@ -285,6 +285,7 @@ export default defineConfig({
|
|||||||
exports[`@nx/vite:configuration library mode should set up non buildable library which already has vite.config.ts correctly 1`] = `
|
exports[`@nx/vite:configuration library mode should set up non buildable library which already has vite.config.ts correctly 1`] = `
|
||||||
"import dts from 'vite-plugin-dts';
|
"import dts from 'vite-plugin-dts';
|
||||||
import * as path from 'path';
|
import * as path from 'path';
|
||||||
|
import { nxCopyAssetsPlugin } from '@nx/vite/plugins/nx-copy-assets.plugin';
|
||||||
import { defineConfig } from 'vite';
|
import { defineConfig } from 'vite';
|
||||||
import react from '@vitejs/plugin-react';
|
import react from '@vitejs/plugin-react';
|
||||||
import { nxViteTsPaths } from '@nx/vite/plugins/nx-tsconfig-paths.plugin';
|
import { nxViteTsPaths } from '@nx/vite/plugins/nx-tsconfig-paths.plugin';
|
||||||
@ -395,7 +396,6 @@ exports[`@nx/vite:configuration transform React app to use Vite should move inde
|
|||||||
exports[`@nx/vite:configuration transform Web app to use Vite should create vite.config file at the root of the app 1`] = `
|
exports[`@nx/vite:configuration transform Web app to use Vite should create vite.config file at the root of the app 1`] = `
|
||||||
"/// <reference types='vitest' />
|
"/// <reference types='vitest' />
|
||||||
import { defineConfig } from 'vite';
|
import { defineConfig } from 'vite';
|
||||||
|
|
||||||
import { nxViteTsPaths } from '@nx/vite/plugins/nx-tsconfig-paths.plugin';
|
import { nxViteTsPaths } from '@nx/vite/plugins/nx-tsconfig-paths.plugin';
|
||||||
import { nxCopyAssetsPlugin } from '@nx/vite/plugins/nx-copy-assets.plugin';
|
import { nxCopyAssetsPlugin } from '@nx/vite/plugins/nx-copy-assets.plugin';
|
||||||
|
|
||||||
|
|||||||
@ -2,27 +2,34 @@ import {
|
|||||||
formatFiles,
|
formatFiles,
|
||||||
GeneratorCallback,
|
GeneratorCallback,
|
||||||
joinPathFragments,
|
joinPathFragments,
|
||||||
|
readJson,
|
||||||
readNxJson,
|
readNxJson,
|
||||||
readProjectConfiguration,
|
readProjectConfiguration,
|
||||||
runTasksInSerial,
|
runTasksInSerial,
|
||||||
Tree,
|
Tree,
|
||||||
updateJson,
|
updateJson,
|
||||||
|
writeJson,
|
||||||
} from '@nx/devkit';
|
} from '@nx/devkit';
|
||||||
import { initGenerator as jsInitGenerator } from '@nx/js';
|
import {
|
||||||
|
getUpdatedPackageJsonContent,
|
||||||
|
initGenerator as jsInitGenerator,
|
||||||
|
} from '@nx/js';
|
||||||
|
import { getImportPath } from '@nx/js/src/utils/get-import-path';
|
||||||
|
import { isUsingTsSolutionSetup } from '@nx/js/src/utils/typescript/ts-solution-setup';
|
||||||
|
import { join } from 'node:path/posix';
|
||||||
|
import type { PackageJson } from 'nx/src/utils/package-json';
|
||||||
|
import { ensureDependencies } from '../../utils/ensure-dependencies';
|
||||||
import {
|
import {
|
||||||
addBuildTarget,
|
addBuildTarget,
|
||||||
addServeTarget,
|
|
||||||
addPreviewTarget,
|
addPreviewTarget,
|
||||||
|
addServeTarget,
|
||||||
createOrEditViteConfig,
|
createOrEditViteConfig,
|
||||||
TargetFlags,
|
TargetFlags,
|
||||||
} from '../../utils/generator-utils';
|
} from '../../utils/generator-utils';
|
||||||
|
|
||||||
import initGenerator from '../init/init';
|
import initGenerator from '../init/init';
|
||||||
import vitestGenerator from '../vitest/vitest-generator';
|
import vitestGenerator from '../vitest/vitest-generator';
|
||||||
import { ViteConfigurationGeneratorSchema } from './schema';
|
|
||||||
import { ensureDependencies } from '../../utils/ensure-dependencies';
|
|
||||||
import { convertNonVite } from './lib/convert-non-vite';
|
import { convertNonVite } from './lib/convert-non-vite';
|
||||||
|
import { ViteConfigurationGeneratorSchema } from './schema';
|
||||||
|
|
||||||
export function viteConfigurationGenerator(
|
export function viteConfigurationGenerator(
|
||||||
host: Tree,
|
host: Tree,
|
||||||
@ -103,20 +110,10 @@ export async function viteConfigurationGeneratorInternal(
|
|||||||
tree,
|
tree,
|
||||||
joinPathFragments(projectRoot, 'tsconfig.lib.json'),
|
joinPathFragments(projectRoot, 'tsconfig.lib.json'),
|
||||||
(json) => {
|
(json) => {
|
||||||
if (!json.compilerOptions) {
|
json.compilerOptions ??= {};
|
||||||
json.compilerOptions = {};
|
json.compilerOptions.types ??= [];
|
||||||
}
|
|
||||||
if (!json.compilerOptions.types) {
|
|
||||||
json.compilerOptions.types = [];
|
|
||||||
}
|
|
||||||
if (!json.compilerOptions.types.includes('vite/client')) {
|
if (!json.compilerOptions.types.includes('vite/client')) {
|
||||||
return {
|
json.compilerOptions.types.push('vite/client');
|
||||||
...json,
|
|
||||||
compilerOptions: {
|
|
||||||
...json.compilerOptions,
|
|
||||||
types: [...json.compilerOptions.types, 'vite/client'],
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
return json;
|
return json;
|
||||||
}
|
}
|
||||||
@ -168,6 +165,10 @@ export async function viteConfigurationGeneratorInternal(
|
|||||||
tasks.push(vitestTask);
|
tasks.push(vitestTask);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (isUsingTsSolutionSetup(tree)) {
|
||||||
|
updatePackageJson(tree, schema);
|
||||||
|
}
|
||||||
|
|
||||||
if (!schema.skipFormat) {
|
if (!schema.skipFormat) {
|
||||||
await formatFiles(tree);
|
await formatFiles(tree);
|
||||||
}
|
}
|
||||||
@ -176,3 +177,44 @@ export async function viteConfigurationGeneratorInternal(
|
|||||||
}
|
}
|
||||||
|
|
||||||
export default viteConfigurationGenerator;
|
export default viteConfigurationGenerator;
|
||||||
|
|
||||||
|
function updatePackageJson(
|
||||||
|
tree: Tree,
|
||||||
|
options: ViteConfigurationGeneratorSchema
|
||||||
|
) {
|
||||||
|
const project = readProjectConfiguration(tree, options.project);
|
||||||
|
|
||||||
|
const packageJsonPath = join(project.root, 'package.json');
|
||||||
|
let packageJson: PackageJson;
|
||||||
|
if (tree.exists(packageJsonPath)) {
|
||||||
|
packageJson = readJson(tree, packageJsonPath);
|
||||||
|
} else {
|
||||||
|
packageJson = {
|
||||||
|
name: getImportPath(tree, options.project),
|
||||||
|
version: '0.0.1',
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// we always write/override the vite and project config with some set values,
|
||||||
|
// so we can rely on them
|
||||||
|
const main = join(project.root, 'src/index.ts');
|
||||||
|
// we configure the dts plugin with the entryRoot set to `src`
|
||||||
|
const rootDir = join(project.root, 'src');
|
||||||
|
const outputPath = joinPathFragments(project.root, 'dist');
|
||||||
|
|
||||||
|
packageJson = getUpdatedPackageJsonContent(packageJson, {
|
||||||
|
main,
|
||||||
|
outputPath,
|
||||||
|
projectRoot: project.root,
|
||||||
|
rootDir,
|
||||||
|
generateExportsField: true,
|
||||||
|
packageJsonPath,
|
||||||
|
format: ['esm', 'cjs'],
|
||||||
|
// when building both formats, we don't set the package.json "type" field, so
|
||||||
|
// we need to set the esm extension to ".mjs" to match vite output
|
||||||
|
// see the "File Extensions" callout in https://vite.dev/guide/build.html#library-mode
|
||||||
|
outputFileExtensionForEsm: '.mjs',
|
||||||
|
});
|
||||||
|
|
||||||
|
writeJson(tree, packageJsonPath, packageJson);
|
||||||
|
}
|
||||||
|
|||||||
@ -215,7 +215,6 @@ describe('generator utils', () => {
|
|||||||
.toMatchInlineSnapshot(`
|
.toMatchInlineSnapshot(`
|
||||||
"/// <reference types='vitest' />
|
"/// <reference types='vitest' />
|
||||||
import { defineConfig } from 'vite';
|
import { defineConfig } from 'vite';
|
||||||
|
|
||||||
import { nxViteTsPaths } from '@nx/vite/plugins/nx-tsconfig-paths.plugin';
|
import { nxViteTsPaths } from '@nx/vite/plugins/nx-tsconfig-paths.plugin';
|
||||||
import { nxCopyAssetsPlugin } from '@nx/vite/plugins/nx-copy-assets.plugin';
|
import { nxCopyAssetsPlugin } from '@nx/vite/plugins/nx-copy-assets.plugin';
|
||||||
|
|
||||||
|
|||||||
@ -118,8 +118,12 @@ export function addBuildTarget(
|
|||||||
) {
|
) {
|
||||||
addBuildTargetDefaults(tree, '@nx/vite:build');
|
addBuildTargetDefaults(tree, '@nx/vite:build');
|
||||||
const project = readProjectConfiguration(tree, options.project);
|
const project = readProjectConfiguration(tree, options.project);
|
||||||
|
|
||||||
|
const isTsSolutionSetup = isUsingTsSolutionSetup(tree);
|
||||||
const buildOptions: ViteBuildExecutorOptions = {
|
const buildOptions: ViteBuildExecutorOptions = {
|
||||||
outputPath: joinPathFragments(
|
outputPath: isTsSolutionSetup
|
||||||
|
? joinPathFragments(project.root, 'dist')
|
||||||
|
: joinPathFragments(
|
||||||
'dist',
|
'dist',
|
||||||
project.root != '.' ? project.root : options.project
|
project.root != '.' ? project.root : options.project
|
||||||
),
|
),
|
||||||
@ -228,7 +232,15 @@ export function editTsConfig(
|
|||||||
) {
|
) {
|
||||||
const projectConfig = readProjectConfiguration(tree, options.project);
|
const projectConfig = readProjectConfiguration(tree, options.project);
|
||||||
|
|
||||||
const config = readJson(tree, `${projectConfig.root}/tsconfig.json`);
|
let tsconfigPath = joinPathFragments(projectConfig.root, 'tsconfig.json');
|
||||||
|
const isTsSolutionSetup = isUsingTsSolutionSetup(tree);
|
||||||
|
if (isTsSolutionSetup) {
|
||||||
|
tsconfigPath = [
|
||||||
|
joinPathFragments(projectConfig.root, 'tsconfig.app.json'),
|
||||||
|
joinPathFragments(projectConfig.root, 'tsconfig.lib.json'),
|
||||||
|
].find((p) => tree.exists(p));
|
||||||
|
}
|
||||||
|
const config = readJson(tree, tsconfigPath);
|
||||||
|
|
||||||
switch (options.uiFramework) {
|
switch (options.uiFramework) {
|
||||||
case 'react':
|
case 'react':
|
||||||
@ -241,6 +253,7 @@ export function editTsConfig(
|
|||||||
};
|
};
|
||||||
break;
|
break;
|
||||||
case 'none':
|
case 'none':
|
||||||
|
if (!isTsSolutionSetup) {
|
||||||
config.compilerOptions = {
|
config.compilerOptions = {
|
||||||
module: 'commonjs',
|
module: 'commonjs',
|
||||||
forceConsistentCasingInFileNames: true,
|
forceConsistentCasingInFileNames: true,
|
||||||
@ -250,12 +263,13 @@ export function editTsConfig(
|
|||||||
noImplicitReturns: true,
|
noImplicitReturns: true,
|
||||||
noFallthroughCasesInSwitch: true,
|
noFallthroughCasesInSwitch: true,
|
||||||
};
|
};
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
writeJson(tree, `${projectConfig.root}/tsconfig.json`, config);
|
writeJson(tree, tsconfigPath, config);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function deleteWebpackConfig(
|
export function deleteWebpackConfig(
|
||||||
@ -405,7 +419,8 @@ export function createOrEditViteConfig(
|
|||||||
},
|
},
|
||||||
},`;
|
},`;
|
||||||
|
|
||||||
const imports: string[] = options.imports ? options.imports : [];
|
const imports: string[] = options.imports ? [...options.imports] : [];
|
||||||
|
const plugins: string[] = options.plugins ? [...options.plugins] : [];
|
||||||
|
|
||||||
if (!onlyVitest && options.includeLib) {
|
if (!onlyVitest && options.includeLib) {
|
||||||
imports.push(
|
imports.push(
|
||||||
@ -414,11 +429,13 @@ export function createOrEditViteConfig(
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
let viteConfigContent = '';
|
if (!isUsingTsPlugin) {
|
||||||
|
imports.push(
|
||||||
const plugins = options.plugins
|
`import { nxViteTsPaths } from '@nx/vite/plugins/nx-tsconfig-paths.plugin'`,
|
||||||
? [...options.plugins, `nxViteTsPaths()`, `nxCopyAssetsPlugin(['*.md'])`]
|
`import { nxCopyAssetsPlugin } from '@nx/vite/plugins/nx-copy-assets.plugin'`
|
||||||
: [`nxViteTsPaths()`, `nxCopyAssetsPlugin(['*.md'])`];
|
);
|
||||||
|
plugins.push(`nxViteTsPaths()`, `nxCopyAssetsPlugin(['*.md'])`);
|
||||||
|
}
|
||||||
|
|
||||||
if (!onlyVitest && options.includeLib) {
|
if (!onlyVitest && options.includeLib) {
|
||||||
plugins.push(
|
plugins.push(
|
||||||
@ -507,11 +524,9 @@ export function createOrEditViteConfig(
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
viteConfigContent = `/// <reference types='vitest' />
|
const viteConfigContent = `/// <reference types='vitest' />
|
||||||
import { defineConfig } from 'vite';
|
import { defineConfig } from 'vite';
|
||||||
${imports.join(';\n')}${imports.length ? ';' : ''}
|
${imports.join(';\n')}${imports.length ? ';' : ''}
|
||||||
import { nxViteTsPaths } from '@nx/vite/plugins/nx-tsconfig-paths.plugin';
|
|
||||||
import { nxCopyAssetsPlugin } from '@nx/vite/plugins/nx-copy-assets.plugin';
|
|
||||||
|
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
root: __dirname,
|
root: __dirname,
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user