feat(misc): set a development conditional export for buildable libraries when using the ts solution setup (#30451)
Update library generators to set a `development` conditional export for buildable libraries' `package.json` files and set the `customConditions` compiler options in `tsconfig.base.json`. This will only be done for workspaces using the TS solution setup. ## Current Behavior ## Expected Behavior ## Related Issue(s) Fixes #
This commit is contained in:
parent
533e9ffc25
commit
176c792e34
@ -167,6 +167,9 @@ function updatePackageJson(
|
|||||||
esbuildOptions,
|
esbuildOptions,
|
||||||
} = mergedTarget.options;
|
} = mergedTarget.options;
|
||||||
|
|
||||||
|
// the file must exist in the TS solution setup
|
||||||
|
const tsconfigBase = readJson(tree, 'tsconfig.base.json');
|
||||||
|
|
||||||
// can't use the declarationRootDir as rootDir because it only affects the typings,
|
// can't use the declarationRootDir as rootDir because it only affects the typings,
|
||||||
// not the runtime entry point
|
// not the runtime entry point
|
||||||
packageJson = getUpdatedPackageJsonContent(packageJson, {
|
packageJson = getUpdatedPackageJsonContent(packageJson, {
|
||||||
@ -186,6 +189,10 @@ function updatePackageJson(
|
|||||||
outputFileExtensionForEsm: getOutExtension('esm', {
|
outputFileExtensionForEsm: getOutExtension('esm', {
|
||||||
userDefinedBuildOptions: esbuildOptions,
|
userDefinedBuildOptions: esbuildOptions,
|
||||||
}),
|
}),
|
||||||
|
skipDevelopmentExports:
|
||||||
|
!tsconfigBase.compilerOptions?.customConditions?.includes(
|
||||||
|
'development'
|
||||||
|
),
|
||||||
});
|
});
|
||||||
|
|
||||||
if (declarationRootDir !== dirname(main)) {
|
if (declarationRootDir !== dirname(main)) {
|
||||||
|
|||||||
@ -467,6 +467,7 @@ describe('lib', () => {
|
|||||||
compilerOptions: {
|
compilerOptions: {
|
||||||
composite: true,
|
composite: true,
|
||||||
declaration: true,
|
declaration: true,
|
||||||
|
customConditions: ['development'],
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
writeJson(appTree, 'tsconfig.json', {
|
writeJson(appTree, 'tsconfig.json', {
|
||||||
@ -630,13 +631,14 @@ describe('lib', () => {
|
|||||||
{
|
{
|
||||||
"exports": {
|
"exports": {
|
||||||
".": {
|
".": {
|
||||||
"default": "./src/index.ts",
|
"default": "./dist/index.cjs.js",
|
||||||
"import": "./src/index.ts",
|
"development": "./src/index.ts",
|
||||||
|
"import": "./dist/index.esm.js",
|
||||||
"types": "./dist/index.esm.d.ts",
|
"types": "./dist/index.esm.d.ts",
|
||||||
},
|
},
|
||||||
"./package.json": "./package.json",
|
"./package.json": "./package.json",
|
||||||
},
|
},
|
||||||
"main": "./src/index.ts",
|
"main": "./dist/index.cjs.js",
|
||||||
"module": "./dist/index.esm.js",
|
"module": "./dist/index.esm.js",
|
||||||
"name": "@proj/my-lib",
|
"name": "@proj/my-lib",
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
@ -649,6 +651,25 @@ describe('lib', () => {
|
|||||||
`);
|
`);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should not set the "development" condition in exports when it does not exist in tsconfig.base.json', async () => {
|
||||||
|
updateJson(appTree, 'tsconfig.base.json', (json) => {
|
||||||
|
delete json.compilerOptions.customConditions;
|
||||||
|
return json;
|
||||||
|
});
|
||||||
|
|
||||||
|
await expoLibraryGenerator(appTree, {
|
||||||
|
...defaultSchema,
|
||||||
|
buildable: true,
|
||||||
|
strict: false,
|
||||||
|
useProjectJson: false,
|
||||||
|
skipFormat: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(
|
||||||
|
readJson(appTree, 'my-lib/package.json').exports['.']
|
||||||
|
).not.toHaveProperty('development');
|
||||||
|
});
|
||||||
|
|
||||||
it('should set "nx.name" in package.json when the user provides a name that is different than the package name', async () => {
|
it('should set "nx.name" in package.json when the user provides a name that is different than the package name', async () => {
|
||||||
await expoLibraryGenerator(appTree, {
|
await expoLibraryGenerator(appTree, {
|
||||||
...defaultSchema,
|
...defaultSchema,
|
||||||
|
|||||||
@ -295,6 +295,15 @@ function createFiles(host: Tree, options: NormalizedSchema) {
|
|||||||
function determineEntryFields(
|
function determineEntryFields(
|
||||||
options: NormalizedSchema
|
options: NormalizedSchema
|
||||||
): Pick<PackageJson, 'main' | 'types' | 'exports'> {
|
): Pick<PackageJson, 'main' | 'types' | 'exports'> {
|
||||||
|
if (
|
||||||
|
options.buildable ||
|
||||||
|
options.publishable ||
|
||||||
|
!options.isUsingTsSolutionConfig
|
||||||
|
) {
|
||||||
|
// For buildable libraries, the entries are configured by the bundler (i.e. Rollup).
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
main: options.js ? './src/index.js' : './src/index.ts',
|
main: options.js ? './src/index.js' : './src/index.ts',
|
||||||
types: options.js ? './src/index.js' : './src/index.ts',
|
types: options.js ? './src/index.js' : './src/index.ts',
|
||||||
|
|||||||
@ -17,6 +17,7 @@
|
|||||||
"noUnusedLocals": true,
|
"noUnusedLocals": true,
|
||||||
"skipLibCheck": true,
|
"skipLibCheck": true,
|
||||||
"strict": true,
|
"strict": true,
|
||||||
"target": "es2022"
|
"target": "es2022",
|
||||||
|
"customConditions": ["development"]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -208,7 +208,8 @@ describe('js init generator', () => {
|
|||||||
"noUnusedLocals": true,
|
"noUnusedLocals": true,
|
||||||
"skipLibCheck": true,
|
"skipLibCheck": true,
|
||||||
"strict": true,
|
"strict": true,
|
||||||
"target": "es2022"
|
"target": "es2022",
|
||||||
|
"customConditions": ["development"]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
"
|
"
|
||||||
|
|||||||
@ -1817,6 +1817,7 @@ describe('lib', () => {
|
|||||||
compilerOptions: {
|
compilerOptions: {
|
||||||
composite: true,
|
composite: true,
|
||||||
declaration: true,
|
declaration: true,
|
||||||
|
customConditions: ['development'],
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
writeJson(tree, 'tsconfig.json', {
|
writeJson(tree, 'tsconfig.json', {
|
||||||
@ -1954,6 +1955,7 @@ describe('lib', () => {
|
|||||||
"exports": {
|
"exports": {
|
||||||
".": {
|
".": {
|
||||||
"default": "./dist/index.js",
|
"default": "./dist/index.js",
|
||||||
|
"development": "./src/index.ts",
|
||||||
"import": "./dist/index.js",
|
"import": "./dist/index.js",
|
||||||
"types": "./dist/index.d.ts",
|
"types": "./dist/index.d.ts",
|
||||||
},
|
},
|
||||||
@ -1987,6 +1989,7 @@ describe('lib', () => {
|
|||||||
"exports": {
|
"exports": {
|
||||||
".": {
|
".": {
|
||||||
"default": "./dist/index.js",
|
"default": "./dist/index.js",
|
||||||
|
"development": "./src/index.ts",
|
||||||
"import": "./dist/index.js",
|
"import": "./dist/index.js",
|
||||||
"types": "./dist/index.d.ts",
|
"types": "./dist/index.d.ts",
|
||||||
},
|
},
|
||||||
@ -2428,5 +2431,26 @@ describe('lib', () => {
|
|||||||
expect(readJson(tree, 'my-lib/project.json').name).toBe('my-lib');
|
expect(readJson(tree, 'my-lib/project.json').name).toBe('my-lib');
|
||||||
expect(readJson(tree, 'my-lib/package.json').nx).toBeUndefined();
|
expect(readJson(tree, 'my-lib/package.json').nx).toBeUndefined();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should not set the "development" condition in exports when it does not exist in tsconfig.base.json', async () => {
|
||||||
|
updateJson(tree, 'tsconfig.base.json', (json) => {
|
||||||
|
delete json.compilerOptions.customConditions;
|
||||||
|
return json;
|
||||||
|
});
|
||||||
|
|
||||||
|
await libraryGenerator(tree, {
|
||||||
|
...defaultOptions,
|
||||||
|
directory: 'my-lib',
|
||||||
|
name: 'my-lib',
|
||||||
|
useProjectJson: true,
|
||||||
|
bundler: 'tsc',
|
||||||
|
addPlugin: true,
|
||||||
|
skipFormat: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(
|
||||||
|
readJson(tree, 'my-lib/package.json').exports['.']
|
||||||
|
).not.toHaveProperty('development');
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@ -10,6 +10,7 @@ import {
|
|||||||
names,
|
names,
|
||||||
offsetFromRoot,
|
offsetFromRoot,
|
||||||
ProjectConfiguration,
|
ProjectConfiguration,
|
||||||
|
readJson,
|
||||||
readNxJson,
|
readNxJson,
|
||||||
readProjectConfiguration,
|
readProjectConfiguration,
|
||||||
runTasksInSerial,
|
runTasksInSerial,
|
||||||
@ -631,6 +632,9 @@ function createFiles(tree: Tree, options: NormalizedLibraryGeneratorOptions) {
|
|||||||
options.isUsingTsSolutionConfig &&
|
options.isUsingTsSolutionConfig &&
|
||||||
!['none', 'rollup', 'vite'].includes(options.bundler)
|
!['none', 'rollup', 'vite'].includes(options.bundler)
|
||||||
) {
|
) {
|
||||||
|
// the file must exist in the TS solution setup
|
||||||
|
const tsconfigBase = readJson(tree, 'tsconfig.base.json');
|
||||||
|
|
||||||
return getUpdatedPackageJsonContent(updatedPackageJson, {
|
return getUpdatedPackageJsonContent(updatedPackageJson, {
|
||||||
main: join(options.projectRoot, 'src/index.ts'),
|
main: join(options.projectRoot, 'src/index.ts'),
|
||||||
outputPath: joinPathFragments(options.projectRoot, 'dist'),
|
outputPath: joinPathFragments(options.projectRoot, 'dist'),
|
||||||
@ -639,6 +643,10 @@ function createFiles(tree: Tree, options: NormalizedLibraryGeneratorOptions) {
|
|||||||
generateExportsField: true,
|
generateExportsField: true,
|
||||||
packageJsonPath,
|
packageJsonPath,
|
||||||
format: ['esm'],
|
format: ['esm'],
|
||||||
|
skipDevelopmentExports:
|
||||||
|
!tsconfigBase.compilerOptions?.customConditions?.includes(
|
||||||
|
'development'
|
||||||
|
),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -664,6 +672,8 @@ function createFiles(tree: Tree, options: NormalizedLibraryGeneratorOptions) {
|
|||||||
options.isUsingTsSolutionConfig &&
|
options.isUsingTsSolutionConfig &&
|
||||||
!['none', 'rollup', 'vite'].includes(options.bundler)
|
!['none', 'rollup', 'vite'].includes(options.bundler)
|
||||||
) {
|
) {
|
||||||
|
const tsconfigBase = readJson(tree, 'tsconfig.base.json');
|
||||||
|
|
||||||
packageJson = getUpdatedPackageJsonContent(packageJson, {
|
packageJson = getUpdatedPackageJsonContent(packageJson, {
|
||||||
main: join(options.projectRoot, 'src/index.ts'),
|
main: join(options.projectRoot, 'src/index.ts'),
|
||||||
outputPath: joinPathFragments(options.projectRoot, 'dist'),
|
outputPath: joinPathFragments(options.projectRoot, 'dist'),
|
||||||
@ -672,6 +682,10 @@ function createFiles(tree: Tree, options: NormalizedLibraryGeneratorOptions) {
|
|||||||
generateExportsField: true,
|
generateExportsField: true,
|
||||||
packageJsonPath,
|
packageJsonPath,
|
||||||
format: ['esm'],
|
format: ['esm'],
|
||||||
|
skipDevelopmentExports:
|
||||||
|
!tsconfigBase.compilerOptions?.customConditions?.includes(
|
||||||
|
'development'
|
||||||
|
),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -325,6 +325,11 @@ function updatePackageJson(
|
|||||||
version: '0.0.1',
|
version: '0.0.1',
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// the file must exist in the TS solution setup, which is the only case this
|
||||||
|
// function is called
|
||||||
|
const tsconfigBase = readJson(tree, 'tsconfig.base.json');
|
||||||
|
|
||||||
packageJson = getUpdatedPackageJsonContent(packageJson, {
|
packageJson = getUpdatedPackageJsonContent(packageJson, {
|
||||||
main,
|
main,
|
||||||
outputPath,
|
outputPath,
|
||||||
@ -333,6 +338,8 @@ function updatePackageJson(
|
|||||||
packageJsonPath,
|
packageJsonPath,
|
||||||
rootDir,
|
rootDir,
|
||||||
format,
|
format,
|
||||||
|
skipDevelopmentExports:
|
||||||
|
!tsconfigBase.compilerOptions?.customConditions?.includes('development'),
|
||||||
});
|
});
|
||||||
writeJson(tree, packageJsonPath, packageJson);
|
writeJson(tree, packageJsonPath, packageJson);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2206,6 +2206,111 @@ describe(`Plugin: ${PLUGIN_NAME}`, () => {
|
|||||||
`);
|
`);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should not create build target when the entry points point to source files', async () => {
|
||||||
|
// Sibling package.json
|
||||||
|
await applyFilesToTempFsAndContext(tempFs, context, {
|
||||||
|
'libs/my-lib/tsconfig.json': `{}`,
|
||||||
|
'libs/my-lib/tsconfig.lib.json': `{"compilerOptions": {"outDir": "dist"}}`,
|
||||||
|
'libs/my-lib/package.json': JSON.stringify({
|
||||||
|
exports: {
|
||||||
|
'.': {
|
||||||
|
default: './src/index.ts',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
expect(
|
||||||
|
await invokeCreateNodesOnMatchingFiles(context, {
|
||||||
|
// Reduce noise in build snapshots by disabling default typecheck target
|
||||||
|
typecheck: false,
|
||||||
|
build: true,
|
||||||
|
})
|
||||||
|
).toMatchInlineSnapshot(`
|
||||||
|
{
|
||||||
|
"projects": {
|
||||||
|
"libs/my-lib": {
|
||||||
|
"projectType": "library",
|
||||||
|
"targets": {},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
`);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create build target when the entry points point to dist files', async () => {
|
||||||
|
// Sibling package.json
|
||||||
|
await applyFilesToTempFsAndContext(tempFs, context, {
|
||||||
|
'libs/my-lib/tsconfig.json': `{}`,
|
||||||
|
'libs/my-lib/tsconfig.lib.json': `{"compilerOptions": {"outDir": "dist"}}`,
|
||||||
|
'libs/my-lib/package.json': JSON.stringify({
|
||||||
|
exports: {
|
||||||
|
'.': {
|
||||||
|
// should ignore the fact that the development condition points to source
|
||||||
|
development: './src/index.ts',
|
||||||
|
types: './dist/index.d.ts',
|
||||||
|
default: './dist/index.js',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
expect(
|
||||||
|
await invokeCreateNodesOnMatchingFiles(context, {
|
||||||
|
// Reduce noise in build snapshots by disabling default typecheck target
|
||||||
|
typecheck: false,
|
||||||
|
build: true,
|
||||||
|
})
|
||||||
|
).toMatchInlineSnapshot(`
|
||||||
|
{
|
||||||
|
"projects": {
|
||||||
|
"libs/my-lib": {
|
||||||
|
"projectType": "library",
|
||||||
|
"targets": {
|
||||||
|
"build": {
|
||||||
|
"cache": true,
|
||||||
|
"command": "tsc --build tsconfig.lib.json",
|
||||||
|
"dependsOn": [
|
||||||
|
"^build",
|
||||||
|
],
|
||||||
|
"inputs": [
|
||||||
|
"production",
|
||||||
|
"^production",
|
||||||
|
{
|
||||||
|
"externalDependencies": [
|
||||||
|
"typescript",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
"metadata": {
|
||||||
|
"description": "Builds the project with \`tsc\`.",
|
||||||
|
"help": {
|
||||||
|
"command": "npx tsc --build --help",
|
||||||
|
"example": {
|
||||||
|
"args": [
|
||||||
|
"--force",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"technologies": [
|
||||||
|
"typescript",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
"options": {
|
||||||
|
"cwd": "libs/my-lib",
|
||||||
|
},
|
||||||
|
"outputs": [
|
||||||
|
"{projectRoot}/dist",
|
||||||
|
],
|
||||||
|
"syncGenerators": [
|
||||||
|
"@nx/js:typescript-sync",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
`);
|
||||||
|
});
|
||||||
|
|
||||||
it('should create a node with a build target when enabled, for a project level tsconfig.lib.json build file by default', async () => {
|
it('should create a node with a build target when enabled, for a project level tsconfig.lib.json build file by default', async () => {
|
||||||
// Sibling package.json
|
// Sibling package.json
|
||||||
await applyFilesToTempFsAndContext(tempFs, context, {
|
await applyFilesToTempFsAndContext(tempFs, context, {
|
||||||
|
|||||||
@ -95,8 +95,8 @@ export function isValidPackageJsonBuildConfig(
|
|||||||
return isPathSourceFile(value);
|
return isPathSourceFile(value);
|
||||||
} else if (typeof value === 'object') {
|
} else if (typeof value === 'object') {
|
||||||
return Object.entries(value).some(([currentKey, subValue]) => {
|
return Object.entries(value).some(([currentKey, subValue]) => {
|
||||||
// Skip types field
|
// Skip types and development conditions
|
||||||
if (currentKey === 'types') {
|
if (currentKey === 'types' || currentKey === 'development') {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (typeof subValue === 'string') {
|
if (typeof subValue === 'string') {
|
||||||
|
|||||||
@ -157,6 +157,7 @@ describe('getUpdatedPackageJsonContent', () => {
|
|||||||
version: '0.0.1',
|
version: '0.0.1',
|
||||||
exports: {
|
exports: {
|
||||||
'.': {
|
'.': {
|
||||||
|
development: './src/index.ts',
|
||||||
default: './src/index.js',
|
default: './src/index.js',
|
||||||
import: './src/index.js',
|
import: './src/index.js',
|
||||||
types: './src/index.d.ts',
|
types: './src/index.d.ts',
|
||||||
@ -190,6 +191,7 @@ describe('getUpdatedPackageJsonContent', () => {
|
|||||||
type: 'commonjs',
|
type: 'commonjs',
|
||||||
exports: {
|
exports: {
|
||||||
'.': {
|
'.': {
|
||||||
|
development: './src/index.ts',
|
||||||
default: './src/index.cjs',
|
default: './src/index.cjs',
|
||||||
types: './src/index.d.ts',
|
types: './src/index.d.ts',
|
||||||
},
|
},
|
||||||
@ -228,15 +230,28 @@ describe('getUpdatedPackageJsonContent', () => {
|
|||||||
version: '0.0.1',
|
version: '0.0.1',
|
||||||
exports: {
|
exports: {
|
||||||
'.': {
|
'.': {
|
||||||
|
development: './src/index.ts',
|
||||||
default: './src/index.js',
|
default: './src/index.js',
|
||||||
types: './src/index.d.ts',
|
types: './src/index.d.ts',
|
||||||
},
|
},
|
||||||
'./foo': './src/foo.js',
|
'./foo': {
|
||||||
'./bar': './src/bar.js',
|
development: './src/foo.ts',
|
||||||
|
default: './src/foo.js',
|
||||||
|
},
|
||||||
|
'./bar': {
|
||||||
|
development: './src/bar.ts',
|
||||||
|
default: './src/bar.js',
|
||||||
|
},
|
||||||
'./package.json': './package.json',
|
'./package.json': './package.json',
|
||||||
'./migrations.json': './migrations.json',
|
'./migrations.json': './migrations.json',
|
||||||
'./feature': './feature/index.js',
|
'./feature': {
|
||||||
'./feature/index': './feature/index.js',
|
development: './feature/index.ts',
|
||||||
|
default: './feature/index.js',
|
||||||
|
},
|
||||||
|
'./feature/index': {
|
||||||
|
development: './feature/index.ts',
|
||||||
|
default: './feature/index.js',
|
||||||
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -269,15 +284,32 @@ describe('getUpdatedPackageJsonContent', () => {
|
|||||||
version: '0.0.1',
|
version: '0.0.1',
|
||||||
exports: {
|
exports: {
|
||||||
'.': {
|
'.': {
|
||||||
|
development: './src/index.ts',
|
||||||
default: './src/index.js',
|
default: './src/index.js',
|
||||||
import: './src/index.js',
|
import: './src/index.js',
|
||||||
types: './src/index.d.ts',
|
types: './src/index.d.ts',
|
||||||
},
|
},
|
||||||
'./foo': './src/foo.js',
|
'./foo': {
|
||||||
'./bar': './src/bar.js',
|
development: './src/foo.ts',
|
||||||
|
import: './src/foo.js',
|
||||||
|
default: './src/foo.js',
|
||||||
|
},
|
||||||
|
'./bar': {
|
||||||
|
development: './src/bar.ts',
|
||||||
|
import: './src/bar.js',
|
||||||
|
default: './src/bar.js',
|
||||||
|
},
|
||||||
'./package.json': './package.json',
|
'./package.json': './package.json',
|
||||||
'./feature': './feature/index.js',
|
'./feature': {
|
||||||
'./feature/index': './feature/index.js',
|
development: './feature/index.ts',
|
||||||
|
import: './feature/index.js',
|
||||||
|
default: './feature/index.js',
|
||||||
|
},
|
||||||
|
'./feature/index': {
|
||||||
|
development: './feature/index.ts',
|
||||||
|
import: './feature/index.js',
|
||||||
|
default: './feature/index.js',
|
||||||
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -310,23 +342,28 @@ describe('getUpdatedPackageJsonContent', () => {
|
|||||||
version: '0.0.1',
|
version: '0.0.1',
|
||||||
exports: {
|
exports: {
|
||||||
'.': {
|
'.': {
|
||||||
|
development: './src/index.ts',
|
||||||
import: './src/index.js',
|
import: './src/index.js',
|
||||||
default: './src/index.cjs',
|
default: './src/index.cjs',
|
||||||
types: './src/index.d.ts',
|
types: './src/index.d.ts',
|
||||||
},
|
},
|
||||||
'./foo': {
|
'./foo': {
|
||||||
|
development: './src/foo.ts',
|
||||||
import: './src/foo.js',
|
import: './src/foo.js',
|
||||||
default: './src/foo.cjs',
|
default: './src/foo.cjs',
|
||||||
},
|
},
|
||||||
'./bar': {
|
'./bar': {
|
||||||
|
development: './src/bar.ts',
|
||||||
import: './src/bar.js',
|
import: './src/bar.js',
|
||||||
default: './src/bar.cjs',
|
default: './src/bar.cjs',
|
||||||
},
|
},
|
||||||
'./feature': {
|
'./feature': {
|
||||||
|
development: './feature/index.ts',
|
||||||
import: './feature/index.js',
|
import: './feature/index.js',
|
||||||
default: './feature/index.cjs',
|
default: './feature/index.cjs',
|
||||||
},
|
},
|
||||||
'./feature/index': {
|
'./feature/index': {
|
||||||
|
development: './feature/index.ts',
|
||||||
import: './feature/index.js',
|
import: './feature/index.js',
|
||||||
default: './feature/index.cjs',
|
default: './feature/index.cjs',
|
||||||
},
|
},
|
||||||
@ -364,6 +401,7 @@ describe('getUpdatedPackageJsonContent', () => {
|
|||||||
version: '0.0.1',
|
version: '0.0.1',
|
||||||
exports: {
|
exports: {
|
||||||
'.': {
|
'.': {
|
||||||
|
development: './src/index.ts',
|
||||||
import: './src/index.js',
|
import: './src/index.js',
|
||||||
default: './src/index.cjs',
|
default: './src/index.cjs',
|
||||||
types: './src/index.d.ts',
|
types: './src/index.d.ts',
|
||||||
@ -400,6 +438,7 @@ describe('getUpdatedPackageJsonContent', () => {
|
|||||||
type: 'module',
|
type: 'module',
|
||||||
exports: {
|
exports: {
|
||||||
'.': {
|
'.': {
|
||||||
|
development: './src/index.ts',
|
||||||
default: './src/index.cjs',
|
default: './src/index.cjs',
|
||||||
types: './src/index.d.ts',
|
types: './src/index.d.ts',
|
||||||
},
|
},
|
||||||
@ -432,6 +471,7 @@ describe('getUpdatedPackageJsonContent', () => {
|
|||||||
type: 'commonjs',
|
type: 'commonjs',
|
||||||
exports: {
|
exports: {
|
||||||
'.': {
|
'.': {
|
||||||
|
development: './src/index.ts',
|
||||||
default: './src/index.js',
|
default: './src/index.js',
|
||||||
types: './src/index.d.ts',
|
types: './src/index.d.ts',
|
||||||
},
|
},
|
||||||
|
|||||||
@ -48,6 +48,7 @@ export interface UpdatePackageJsonOption {
|
|||||||
buildableProjectDepsInPackageJsonType?: 'dependencies' | 'peerDependencies';
|
buildableProjectDepsInPackageJsonType?: 'dependencies' | 'peerDependencies';
|
||||||
generateLockfile?: boolean;
|
generateLockfile?: boolean;
|
||||||
packageJsonPath?: string;
|
packageJsonPath?: string;
|
||||||
|
skipDevelopmentExports?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function updatePackageJson(
|
export function updatePackageJson(
|
||||||
@ -113,7 +114,10 @@ export function updatePackageJson(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// update package specific settings
|
// update package specific settings
|
||||||
packageJson = getUpdatedPackageJsonContent(packageJson, options);
|
packageJson = getUpdatedPackageJsonContent(packageJson, {
|
||||||
|
skipDevelopmentExports: true,
|
||||||
|
...options,
|
||||||
|
});
|
||||||
|
|
||||||
// save files
|
// save files
|
||||||
writeJsonFile(`${options.outputPath}/package.json`, packageJson);
|
writeJsonFile(`${options.outputPath}/package.json`, packageJson);
|
||||||
@ -285,6 +289,21 @@ export function getUpdatedPackageJsonContent(
|
|||||||
packageJson.exports ??=
|
packageJson.exports ??=
|
||||||
typeof packageJson.exports === 'string' ? {} : { ...packageJson.exports };
|
typeof packageJson.exports === 'string' ? {} : { ...packageJson.exports };
|
||||||
packageJson.exports['./package.json'] ??= './package.json';
|
packageJson.exports['./package.json'] ??= './package.json';
|
||||||
|
|
||||||
|
if (!options.skipDevelopmentExports && (hasCjsFormat || hasEsmFormat)) {
|
||||||
|
packageJson.exports['.'] ??= {};
|
||||||
|
const developmentExports = getDevelopmentExports(options);
|
||||||
|
for (const [exportEntry, filePath] of Object.entries(
|
||||||
|
developmentExports
|
||||||
|
)) {
|
||||||
|
if (!packageJson.exports[exportEntry]) {
|
||||||
|
packageJson.exports[exportEntry] ??= {};
|
||||||
|
packageJson.exports[exportEntry]['development'] ??= filePath;
|
||||||
|
} else if (typeof packageJson.exports[exportEntry] === 'object') {
|
||||||
|
packageJson.exports[exportEntry].development ??= filePath;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!options.skipTypings) {
|
if (!options.skipTypings) {
|
||||||
@ -364,6 +383,47 @@ export function getUpdatedPackageJsonContent(
|
|||||||
return packageJson;
|
return packageJson;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getDevelopmentExports(
|
||||||
|
options: Pick<
|
||||||
|
UpdatePackageJsonOption,
|
||||||
|
'additionalEntryPoints' | 'main' | 'projectRoot'
|
||||||
|
>
|
||||||
|
) {
|
||||||
|
const mainRelativeDir = getRelativeDirectoryToProjectRoot(
|
||||||
|
options.main,
|
||||||
|
options.projectRoot
|
||||||
|
);
|
||||||
|
const exports: Exports = {
|
||||||
|
'.': mainRelativeDir + basename(options.main),
|
||||||
|
};
|
||||||
|
|
||||||
|
if (options.additionalEntryPoints?.length) {
|
||||||
|
const jsRegex = /\.[jt]sx?$/;
|
||||||
|
|
||||||
|
for (const file of options.additionalEntryPoints) {
|
||||||
|
const { ext: fileExt, name: fileName, base: baseName } = parse(file);
|
||||||
|
if (!jsRegex.test(fileExt)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const relativeDir = getRelativeDirectoryToProjectRoot(
|
||||||
|
file,
|
||||||
|
options.projectRoot
|
||||||
|
);
|
||||||
|
const sourceFilePath = relativeDir + baseName;
|
||||||
|
const entryRelativeDir = relativeDir.replace(/^\.\/src\//, './');
|
||||||
|
const entryFilePath = entryRelativeDir + fileName;
|
||||||
|
if (fileName === 'index') {
|
||||||
|
const barrelEntry = entryRelativeDir.replace(/\/$/, '');
|
||||||
|
exports[barrelEntry] = sourceFilePath;
|
||||||
|
}
|
||||||
|
exports[entryFilePath] = sourceFilePath;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return exports;
|
||||||
|
}
|
||||||
|
|
||||||
export function getOutputDir(
|
export function getOutputDir(
|
||||||
options: Pick<
|
options: Pick<
|
||||||
UpdatePackageJsonOption,
|
UpdatePackageJsonOption,
|
||||||
|
|||||||
@ -1,6 +1,11 @@
|
|||||||
import type { Tree } from '@nx/devkit';
|
import type { Tree } from '@nx/devkit';
|
||||||
import * as devkit from '@nx/devkit';
|
import * as devkit from '@nx/devkit';
|
||||||
import { readJson, readProjectConfiguration, writeJson } from '@nx/devkit';
|
import {
|
||||||
|
readJson,
|
||||||
|
readProjectConfiguration,
|
||||||
|
updateJson,
|
||||||
|
writeJson,
|
||||||
|
} from '@nx/devkit';
|
||||||
import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing';
|
import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing';
|
||||||
import { libraryGenerator } from './library';
|
import { libraryGenerator } from './library';
|
||||||
|
|
||||||
@ -357,6 +362,7 @@ describe('lib', () => {
|
|||||||
compilerOptions: {
|
compilerOptions: {
|
||||||
composite: true,
|
composite: true,
|
||||||
declaration: true,
|
declaration: true,
|
||||||
|
customConditions: ['development'],
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
writeJson(tree, 'tsconfig.json', {
|
writeJson(tree, 'tsconfig.json', {
|
||||||
@ -498,6 +504,90 @@ describe('lib', () => {
|
|||||||
`);
|
`);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should create a correct package.json for buildable libraries', async () => {
|
||||||
|
await libraryGenerator(tree, {
|
||||||
|
directory: 'mylib',
|
||||||
|
unitTestRunner: 'jest',
|
||||||
|
useProjectJson: false,
|
||||||
|
buildable: true,
|
||||||
|
skipFormat: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(tree.read('mylib/package.json', 'utf-8')).toMatchInlineSnapshot(`
|
||||||
|
"{
|
||||||
|
"name": "@proj/mylib",
|
||||||
|
"version": "0.0.1",
|
||||||
|
"private": true,
|
||||||
|
"main": "./dist/index.js",
|
||||||
|
"module": "./dist/index.js",
|
||||||
|
"types": "./dist/index.d.ts",
|
||||||
|
"exports": {
|
||||||
|
"./package.json": "./package.json",
|
||||||
|
".": {
|
||||||
|
"development": "./src/index.ts",
|
||||||
|
"types": "./dist/index.d.ts",
|
||||||
|
"import": "./dist/index.js",
|
||||||
|
"default": "./dist/index.js"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"nx": {
|
||||||
|
"targets": {
|
||||||
|
"lint": {
|
||||||
|
"executor": "@nx/eslint:lint"
|
||||||
|
},
|
||||||
|
"test": {
|
||||||
|
"executor": "@nx/jest:jest",
|
||||||
|
"outputs": [
|
||||||
|
"{projectRoot}/test-output/jest/coverage"
|
||||||
|
],
|
||||||
|
"options": {
|
||||||
|
"jestConfig": "mylib/jest.config.ts"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"build": {
|
||||||
|
"executor": "@nx/js:tsc",
|
||||||
|
"outputs": [
|
||||||
|
"{options.outputPath}"
|
||||||
|
],
|
||||||
|
"options": {
|
||||||
|
"outputPath": "dist/mylib",
|
||||||
|
"tsConfig": "mylib/tsconfig.lib.json",
|
||||||
|
"packageJson": "mylib/package.json",
|
||||||
|
"main": "mylib/src/index.ts",
|
||||||
|
"assets": [
|
||||||
|
"mylib/*.md"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"tslib": "^2.3.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"
|
||||||
|
`);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not set the "development" condition in exports when it does not exist in tsconfig.base.json', async () => {
|
||||||
|
updateJson(tree, 'tsconfig.base.json', (json) => {
|
||||||
|
delete json.compilerOptions.customConditions;
|
||||||
|
return json;
|
||||||
|
});
|
||||||
|
|
||||||
|
await libraryGenerator(tree, {
|
||||||
|
directory: 'mylib',
|
||||||
|
unitTestRunner: 'jest',
|
||||||
|
useProjectJson: false,
|
||||||
|
buildable: true,
|
||||||
|
skipFormat: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(
|
||||||
|
readJson(tree, 'mylib/package.json').exports['.']
|
||||||
|
).not.toHaveProperty('development');
|
||||||
|
});
|
||||||
|
|
||||||
it('should set "nx.name" in package.json when the user provides a name that is different than the package name', async () => {
|
it('should set "nx.name" in package.json when the user provides a name that is different than the package name', async () => {
|
||||||
await libraryGenerator(tree, {
|
await libraryGenerator(tree, {
|
||||||
directory: 'mylib',
|
directory: 'mylib',
|
||||||
|
|||||||
@ -133,6 +133,7 @@ describe('next library', () => {
|
|||||||
compilerOptions: {
|
compilerOptions: {
|
||||||
composite: true,
|
composite: true,
|
||||||
declaration: true,
|
declaration: true,
|
||||||
|
customConditions: ['development'],
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
writeJson(tree, 'tsconfig.json', {
|
writeJson(tree, 'tsconfig.json', {
|
||||||
@ -264,6 +265,109 @@ describe('next library', () => {
|
|||||||
`);
|
`);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should create a correct package.json for buildable libraries', async () => {
|
||||||
|
await libraryGenerator(tree, {
|
||||||
|
directory: 'mylib',
|
||||||
|
linter: Linter.EsLint,
|
||||||
|
skipFormat: true,
|
||||||
|
skipTsConfig: false,
|
||||||
|
unitTestRunner: 'jest',
|
||||||
|
style: 'css',
|
||||||
|
component: false,
|
||||||
|
useProjectJson: false,
|
||||||
|
buildable: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(tree.read('mylib/package.json', 'utf-8')).toMatchInlineSnapshot(`
|
||||||
|
"{
|
||||||
|
"name": "@proj/mylib",
|
||||||
|
"version": "0.0.1",
|
||||||
|
"type": "module",
|
||||||
|
"main": "./dist/index.esm.js",
|
||||||
|
"module": "./dist/index.esm.js",
|
||||||
|
"types": "./dist/index.esm.d.ts",
|
||||||
|
"exports": {
|
||||||
|
"./package.json": "./package.json",
|
||||||
|
".": {
|
||||||
|
"development": "./src/index.ts",
|
||||||
|
"types": "./dist/index.esm.d.ts",
|
||||||
|
"import": "./dist/index.esm.js",
|
||||||
|
"default": "./dist/index.esm.js"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"nx": {
|
||||||
|
"targets": {
|
||||||
|
"lint": {
|
||||||
|
"executor": "@nx/eslint:lint"
|
||||||
|
},
|
||||||
|
"build": {
|
||||||
|
"executor": "@nx/rollup:rollup",
|
||||||
|
"outputs": [
|
||||||
|
"{options.outputPath}"
|
||||||
|
],
|
||||||
|
"options": {
|
||||||
|
"outputPath": "dist/mylib",
|
||||||
|
"tsConfig": "mylib/tsconfig.lib.json",
|
||||||
|
"project": "mylib/package.json",
|
||||||
|
"entryFile": "mylib/src/index.ts",
|
||||||
|
"external": [
|
||||||
|
"react",
|
||||||
|
"react-dom",
|
||||||
|
"react/jsx-runtime"
|
||||||
|
],
|
||||||
|
"rollupConfig": "@nx/react/plugins/bundle-rollup",
|
||||||
|
"compiler": "babel",
|
||||||
|
"assets": [
|
||||||
|
{
|
||||||
|
"glob": "mylib/README.md",
|
||||||
|
"input": ".",
|
||||||
|
"output": "."
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"test": {
|
||||||
|
"executor": "@nx/jest:jest",
|
||||||
|
"outputs": [
|
||||||
|
"{projectRoot}/test-output/jest/coverage"
|
||||||
|
],
|
||||||
|
"options": {
|
||||||
|
"jestConfig": "mylib/jest.config.ts"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"sourceRoot": "mylib/src",
|
||||||
|
"projectType": "library",
|
||||||
|
"tags": []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"
|
||||||
|
`);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not set the "development" condition in exports when it does not exist in tsconfig.base.json', async () => {
|
||||||
|
updateJson(tree, 'tsconfig.base.json', (json) => {
|
||||||
|
delete json.compilerOptions.customConditions;
|
||||||
|
return json;
|
||||||
|
});
|
||||||
|
|
||||||
|
await libraryGenerator(tree, {
|
||||||
|
directory: 'mylib',
|
||||||
|
linter: Linter.EsLint,
|
||||||
|
skipFormat: true,
|
||||||
|
skipTsConfig: false,
|
||||||
|
unitTestRunner: 'jest',
|
||||||
|
style: 'css',
|
||||||
|
component: false,
|
||||||
|
useProjectJson: false,
|
||||||
|
buildable: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(
|
||||||
|
readJson(tree, 'mylib/package.json').exports['.']
|
||||||
|
).not.toHaveProperty('development');
|
||||||
|
});
|
||||||
|
|
||||||
it('should set "nx.name" in package.json when the user provides a name that is different than the package name', async () => {
|
it('should set "nx.name" in package.json when the user provides a name that is different than the package name', async () => {
|
||||||
await libraryGenerator(tree, {
|
await libraryGenerator(tree, {
|
||||||
directory: 'mylib',
|
directory: 'mylib',
|
||||||
|
|||||||
@ -531,6 +531,7 @@ describe('lib', () => {
|
|||||||
compilerOptions: {
|
compilerOptions: {
|
||||||
composite: true,
|
composite: true,
|
||||||
declaration: true,
|
declaration: true,
|
||||||
|
customConditions: ['development'],
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
writeJson(tree, 'tsconfig.json', {
|
writeJson(tree, 'tsconfig.json', {
|
||||||
@ -654,6 +655,61 @@ describe('lib', () => {
|
|||||||
`);
|
`);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should create a correct package.json for buildable libraries', async () => {
|
||||||
|
await libraryGenerator(tree, {
|
||||||
|
directory: 'mylib',
|
||||||
|
unitTestRunner: 'jest',
|
||||||
|
addPlugin: true,
|
||||||
|
useProjectJson: false,
|
||||||
|
buildable: true,
|
||||||
|
skipFormat: true,
|
||||||
|
} as Schema);
|
||||||
|
|
||||||
|
expect(tree.read('mylib/package.json', 'utf-8')).toMatchInlineSnapshot(`
|
||||||
|
"{
|
||||||
|
"name": "@proj/mylib",
|
||||||
|
"version": "0.0.1",
|
||||||
|
"private": true,
|
||||||
|
"main": "./dist/index.js",
|
||||||
|
"module": "./dist/index.js",
|
||||||
|
"types": "./dist/index.d.ts",
|
||||||
|
"exports": {
|
||||||
|
"./package.json": "./package.json",
|
||||||
|
".": {
|
||||||
|
"development": "./src/index.ts",
|
||||||
|
"types": "./dist/index.d.ts",
|
||||||
|
"import": "./dist/index.js",
|
||||||
|
"default": "./dist/index.js"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"tslib": "^2.3.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"
|
||||||
|
`);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not set the "development" condition in exports when it does not exist in tsconfig.base.json', async () => {
|
||||||
|
updateJson(tree, 'tsconfig.base.json', (json) => {
|
||||||
|
delete json.compilerOptions.customConditions;
|
||||||
|
return json;
|
||||||
|
});
|
||||||
|
|
||||||
|
await libraryGenerator(tree, {
|
||||||
|
directory: 'mylib',
|
||||||
|
unitTestRunner: 'jest',
|
||||||
|
addPlugin: true,
|
||||||
|
useProjectJson: false,
|
||||||
|
buildable: true,
|
||||||
|
skipFormat: true,
|
||||||
|
} as Schema);
|
||||||
|
|
||||||
|
expect(
|
||||||
|
readJson(tree, 'mylib/package.json').exports['.']
|
||||||
|
).not.toHaveProperty('development');
|
||||||
|
});
|
||||||
|
|
||||||
it('should set correct options for swc', async () => {
|
it('should set correct options for swc', async () => {
|
||||||
await libraryGenerator(tree, {
|
await libraryGenerator(tree, {
|
||||||
directory: 'mylib',
|
directory: 'mylib',
|
||||||
@ -672,6 +728,7 @@ describe('lib', () => {
|
|||||||
"exports": {
|
"exports": {
|
||||||
".": {
|
".": {
|
||||||
"default": "./dist/index.js",
|
"default": "./dist/index.js",
|
||||||
|
"development": "./src/index.ts",
|
||||||
"import": "./dist/index.js",
|
"import": "./dist/index.js",
|
||||||
"types": "./dist/index.d.ts",
|
"types": "./dist/index.d.ts",
|
||||||
},
|
},
|
||||||
|
|||||||
@ -339,6 +339,7 @@ describe('NxPlugin Plugin Generator', () => {
|
|||||||
compilerOptions: {
|
compilerOptions: {
|
||||||
composite: true,
|
composite: true,
|
||||||
declaration: true,
|
declaration: true,
|
||||||
|
customConditions: ['development'],
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
writeJson(tree, 'tsconfig.json', {
|
writeJson(tree, 'tsconfig.json', {
|
||||||
@ -447,6 +448,7 @@ describe('NxPlugin Plugin Generator', () => {
|
|||||||
"exports": {
|
"exports": {
|
||||||
".": {
|
".": {
|
||||||
"default": "./dist/index.js",
|
"default": "./dist/index.js",
|
||||||
|
"development": "./src/index.ts",
|
||||||
"import": "./dist/index.js",
|
"import": "./dist/index.js",
|
||||||
"types": "./dist/index.d.ts",
|
"types": "./dist/index.d.ts",
|
||||||
},
|
},
|
||||||
@ -532,6 +534,25 @@ describe('NxPlugin Plugin Generator', () => {
|
|||||||
`);
|
`);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should not set the "development" condition in exports when it does not exist in tsconfig.base.json', async () => {
|
||||||
|
updateJson(tree, 'tsconfig.base.json', (json) => {
|
||||||
|
delete json.compilerOptions.customConditions;
|
||||||
|
return json;
|
||||||
|
});
|
||||||
|
|
||||||
|
await pluginGenerator(
|
||||||
|
tree,
|
||||||
|
getSchema({
|
||||||
|
e2eTestRunner: 'jest',
|
||||||
|
skipFormat: true,
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(
|
||||||
|
readJson(tree, 'my-plugin/package.json').exports['.']
|
||||||
|
).not.toHaveProperty('development');
|
||||||
|
});
|
||||||
|
|
||||||
it('should set "nx.name" in package.json when the user provides a name that is different than the package name and "useProjectJson" is "false"', async () => {
|
it('should set "nx.name" in package.json when the user provides a name that is different than the package name and "useProjectJson" is "false"', async () => {
|
||||||
await pluginGenerator(tree, {
|
await pluginGenerator(tree, {
|
||||||
directory: 'my-plugin',
|
directory: 'my-plugin',
|
||||||
|
|||||||
@ -459,6 +459,7 @@ describe('lib', () => {
|
|||||||
compilerOptions: {
|
compilerOptions: {
|
||||||
composite: true,
|
composite: true,
|
||||||
declaration: true,
|
declaration: true,
|
||||||
|
customConditions: ['development'],
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
writeJson(appTree, 'tsconfig.json', {
|
writeJson(appTree, 'tsconfig.json', {
|
||||||
@ -599,6 +600,58 @@ describe('lib', () => {
|
|||||||
`);
|
`);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should create a correct package.json for buildable libraries', async () => {
|
||||||
|
await libraryGenerator(appTree, {
|
||||||
|
...defaultSchema,
|
||||||
|
useProjectJson: false,
|
||||||
|
buildable: true,
|
||||||
|
skipFormat: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(appTree.read('my-lib/package.json', 'utf-8'))
|
||||||
|
.toMatchInlineSnapshot(`
|
||||||
|
"{
|
||||||
|
"name": "@proj/my-lib",
|
||||||
|
"version": "0.0.1",
|
||||||
|
"main": "./dist/index.cjs.js",
|
||||||
|
"module": "./dist/index.esm.js",
|
||||||
|
"types": "./dist/index.esm.d.ts",
|
||||||
|
"exports": {
|
||||||
|
"./package.json": "./package.json",
|
||||||
|
".": {
|
||||||
|
"development": "./src/index.ts",
|
||||||
|
"types": "./dist/index.esm.d.ts",
|
||||||
|
"import": "./dist/index.esm.js",
|
||||||
|
"default": "./dist/index.cjs.js"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"react": "~18.3.1",
|
||||||
|
"react-native": "~0.76.3"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"
|
||||||
|
`);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not set the "development" condition in exports when it does not exist in tsconfig.base.json', async () => {
|
||||||
|
updateJson(appTree, 'tsconfig.base.json', (json) => {
|
||||||
|
delete json.compilerOptions.customConditions;
|
||||||
|
return json;
|
||||||
|
});
|
||||||
|
|
||||||
|
await libraryGenerator(appTree, {
|
||||||
|
...defaultSchema,
|
||||||
|
useProjectJson: false,
|
||||||
|
buildable: true,
|
||||||
|
skipFormat: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(
|
||||||
|
readJson(appTree, 'my-lib/package.json').exports['.']
|
||||||
|
).not.toHaveProperty('development');
|
||||||
|
});
|
||||||
|
|
||||||
it('should set "nx.name" in package.json when the user provides a name that is different than the package name', async () => {
|
it('should set "nx.name" in package.json when the user provides a name that is different than the package name', async () => {
|
||||||
await libraryGenerator(appTree, {
|
await libraryGenerator(appTree, {
|
||||||
...defaultSchema,
|
...defaultSchema,
|
||||||
|
|||||||
@ -78,15 +78,15 @@ export async function reactNativeLibraryGeneratorInternal(
|
|||||||
|
|
||||||
createFiles(host, options);
|
createFiles(host, options);
|
||||||
|
|
||||||
|
if (options.isUsingTsSolutionConfig) {
|
||||||
|
await addProjectToTsSolutionWorkspace(host, options.projectRoot);
|
||||||
|
}
|
||||||
|
|
||||||
const addProjectTask = await addProject(host, options);
|
const addProjectTask = await addProject(host, options);
|
||||||
if (addProjectTask) {
|
if (addProjectTask) {
|
||||||
tasks.push(addProjectTask);
|
tasks.push(addProjectTask);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (options.isUsingTsSolutionConfig) {
|
|
||||||
await addProjectToTsSolutionWorkspace(host, options.projectRoot);
|
|
||||||
}
|
|
||||||
|
|
||||||
const lintTask = await addLinting(host, {
|
const lintTask = await addLinting(host, {
|
||||||
...options,
|
...options,
|
||||||
projectName: options.name,
|
projectName: options.name,
|
||||||
@ -296,6 +296,15 @@ function createFiles(host: Tree, options: NormalizedSchema) {
|
|||||||
function determineEntryFields(
|
function determineEntryFields(
|
||||||
options: NormalizedSchema
|
options: NormalizedSchema
|
||||||
): Pick<PackageJson, 'main' | 'types' | 'exports'> {
|
): Pick<PackageJson, 'main' | 'types' | 'exports'> {
|
||||||
|
if (
|
||||||
|
options.buildable ||
|
||||||
|
options.publishable ||
|
||||||
|
!options.isUsingTsSolutionConfig
|
||||||
|
) {
|
||||||
|
// For buildable libraries, the entries are configured by the bundler (i.e. Rollup).
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
main: options.js ? './src/index.js' : './src/index.ts',
|
main: options.js ? './src/index.js' : './src/index.ts',
|
||||||
types: options.js ? './src/index.js' : './src/index.ts',
|
types: options.js ? './src/index.js' : './src/index.ts',
|
||||||
|
|||||||
@ -939,6 +939,7 @@ module.exports = withNx(
|
|||||||
compilerOptions: {
|
compilerOptions: {
|
||||||
composite: true,
|
composite: true,
|
||||||
declaration: true,
|
declaration: true,
|
||||||
|
customConditions: ['development'],
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
writeJson(tree, 'tsconfig.json', {
|
writeJson(tree, 'tsconfig.json', {
|
||||||
@ -1246,6 +1247,7 @@ module.exports = withNx(
|
|||||||
"exports": {
|
"exports": {
|
||||||
".": {
|
".": {
|
||||||
"default": "./dist/index.esm.js",
|
"default": "./dist/index.esm.js",
|
||||||
|
"development": "./src/index.ts",
|
||||||
"import": "./dist/index.esm.js",
|
"import": "./dist/index.esm.js",
|
||||||
"types": "./dist/index.esm.d.ts",
|
"types": "./dist/index.esm.d.ts",
|
||||||
},
|
},
|
||||||
@ -1265,6 +1267,27 @@ module.exports = withNx(
|
|||||||
`);
|
`);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should not set the "development" condition in exports when it does not exist in tsconfig.base.json', async () => {
|
||||||
|
updateJson(tree, 'tsconfig.base.json', (json) => {
|
||||||
|
delete json.compilerOptions.customConditions;
|
||||||
|
return json;
|
||||||
|
});
|
||||||
|
|
||||||
|
await libraryGenerator(tree, {
|
||||||
|
...defaultSchema,
|
||||||
|
bundler: 'rollup',
|
||||||
|
directory: 'libs/mylib',
|
||||||
|
publishable: true,
|
||||||
|
importPath: '@acme/mylib',
|
||||||
|
useProjectJson: false,
|
||||||
|
skipFormat: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(
|
||||||
|
readJson(tree, 'libs/mylib/package.json').exports['.']
|
||||||
|
).not.toHaveProperty('development');
|
||||||
|
});
|
||||||
|
|
||||||
it('should add project to workspaces when using TS solution', async () => {
|
it('should add project to workspaces when using TS solution', async () => {
|
||||||
tree.write('pnpm-workspace.yaml', `packages:`);
|
tree.write('pnpm-workspace.yaml', `packages:`);
|
||||||
|
|
||||||
|
|||||||
@ -149,6 +149,7 @@ describe('Remix Library Generator', () => {
|
|||||||
compilerOptions: {
|
compilerOptions: {
|
||||||
composite: true,
|
composite: true,
|
||||||
declaration: true,
|
declaration: true,
|
||||||
|
customConditions: ['development'],
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
writeJson(tree, 'tsconfig.json', {
|
writeJson(tree, 'tsconfig.json', {
|
||||||
@ -196,6 +197,59 @@ describe('Remix Library Generator', () => {
|
|||||||
`);
|
`);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should create a correct package.json for buildable libraries', async () => {
|
||||||
|
await libraryGenerator(tree, {
|
||||||
|
directory: 'packages/foo',
|
||||||
|
style: 'css',
|
||||||
|
addPlugin: true,
|
||||||
|
useProjectJson: false,
|
||||||
|
buildable: true,
|
||||||
|
skipFormat: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(tree.read('packages/foo/package.json', 'utf-8'))
|
||||||
|
.toMatchInlineSnapshot(`
|
||||||
|
"{
|
||||||
|
"name": "@proj/foo",
|
||||||
|
"version": "0.0.1",
|
||||||
|
"type": "module",
|
||||||
|
"main": "./dist/index.esm.js",
|
||||||
|
"module": "./dist/index.esm.js",
|
||||||
|
"types": "./dist/index.esm.d.ts",
|
||||||
|
"exports": {
|
||||||
|
"./package.json": "./package.json",
|
||||||
|
".": {
|
||||||
|
"development": "./src/index.ts",
|
||||||
|
"types": "./dist/index.esm.d.ts",
|
||||||
|
"import": "./dist/index.esm.js",
|
||||||
|
"default": "./dist/index.esm.js"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"
|
||||||
|
`);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not set the "development" condition in exports when it does not exist in tsconfig.base.json', async () => {
|
||||||
|
updateJson(tree, 'tsconfig.base.json', (json) => {
|
||||||
|
delete json.compilerOptions.customConditions;
|
||||||
|
return json;
|
||||||
|
});
|
||||||
|
|
||||||
|
await libraryGenerator(tree, {
|
||||||
|
directory: 'packages/foo',
|
||||||
|
style: 'css',
|
||||||
|
addPlugin: true,
|
||||||
|
useProjectJson: false,
|
||||||
|
buildable: true,
|
||||||
|
skipFormat: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(
|
||||||
|
readJson(tree, 'packages/foo/package.json').exports['.']
|
||||||
|
).not.toHaveProperty('development');
|
||||||
|
});
|
||||||
|
|
||||||
it('should generate server entrypoint', async () => {
|
it('should generate server entrypoint', async () => {
|
||||||
await libraryGenerator(tree, {
|
await libraryGenerator(tree, {
|
||||||
directory: 'test',
|
directory: 'test',
|
||||||
|
|||||||
@ -181,6 +181,9 @@ function updatePackageJson(
|
|||||||
({ main, outputPath } = mergedTarget.options);
|
({ main, outputPath } = mergedTarget.options);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// the file must exist in the TS solution setup
|
||||||
|
const tsconfigBase = readJson(tree, 'tsconfig.base.json');
|
||||||
|
|
||||||
packageJson = getUpdatedPackageJsonContent(packageJson, {
|
packageJson = getUpdatedPackageJsonContent(packageJson, {
|
||||||
main,
|
main,
|
||||||
outputPath,
|
outputPath,
|
||||||
@ -191,6 +194,10 @@ function updatePackageJson(
|
|||||||
format: options.format ?? ['esm'],
|
format: options.format ?? ['esm'],
|
||||||
outputFileExtensionForCjs: '.cjs.js',
|
outputFileExtensionForCjs: '.cjs.js',
|
||||||
outputFileExtensionForEsm: '.esm.js',
|
outputFileExtensionForEsm: '.esm.js',
|
||||||
|
skipDevelopmentExports:
|
||||||
|
!tsconfigBase.compilerOptions?.customConditions?.includes(
|
||||||
|
'development'
|
||||||
|
),
|
||||||
});
|
});
|
||||||
|
|
||||||
// rollup has a specific declaration file generation not handled by the util above,
|
// rollup has a specific declaration file generation not handled by the util above,
|
||||||
|
|||||||
@ -331,7 +331,7 @@ describe('@nx/vite:configuration', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe('TS solution setup', () => {
|
describe('TS solution setup', () => {
|
||||||
beforeAll(async () => {
|
beforeEach(async () => {
|
||||||
tree = createTreeWithEmptyWorkspace();
|
tree = createTreeWithEmptyWorkspace();
|
||||||
updateJson(tree, '/package.json', (json) => {
|
updateJson(tree, '/package.json', (json) => {
|
||||||
json.workspaces = ['packages/*', 'apps/*'];
|
json.workspaces = ['packages/*', 'apps/*'];
|
||||||
@ -341,6 +341,7 @@ describe('@nx/vite:configuration', () => {
|
|||||||
compilerOptions: {
|
compilerOptions: {
|
||||||
composite: true,
|
composite: true,
|
||||||
declaration: true,
|
declaration: true,
|
||||||
|
customConditions: ['development'],
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
writeJson(tree, 'tsconfig.json', {
|
writeJson(tree, 'tsconfig.json', {
|
||||||
@ -371,6 +372,7 @@ describe('@nx/vite:configuration', () => {
|
|||||||
"exports": {
|
"exports": {
|
||||||
".": {
|
".": {
|
||||||
"default": "./dist/index.js",
|
"default": "./dist/index.js",
|
||||||
|
"development": "./src/index.ts",
|
||||||
"import": "./dist/index.js",
|
"import": "./dist/index.js",
|
||||||
"types": "./dist/index.d.ts",
|
"types": "./dist/index.d.ts",
|
||||||
},
|
},
|
||||||
@ -386,6 +388,31 @@ describe('@nx/vite:configuration', () => {
|
|||||||
`);
|
`);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should not set the "development" condition in exports when it does not exist in tsconfig.base.json', async () => {
|
||||||
|
updateJson(tree, 'tsconfig.base.json', (json) => {
|
||||||
|
delete json.compilerOptions.customConditions;
|
||||||
|
return json;
|
||||||
|
});
|
||||||
|
addProjectConfiguration(tree, 'my-lib', {
|
||||||
|
root: 'packages/my-lib',
|
||||||
|
});
|
||||||
|
writeJson(tree, 'packages/my-lib/tsconfig.lib.json', {});
|
||||||
|
writeJson(tree, 'packages/my-lib/tsconfig.json', {});
|
||||||
|
|
||||||
|
await viteConfigurationGenerator(tree, {
|
||||||
|
addPlugin: true,
|
||||||
|
uiFramework: 'none',
|
||||||
|
project: 'my-lib',
|
||||||
|
projectType: 'library',
|
||||||
|
newProject: true,
|
||||||
|
skipFormat: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(
|
||||||
|
readJson(tree, 'packages/my-lib/package.json').exports['.']
|
||||||
|
).not.toHaveProperty('development');
|
||||||
|
});
|
||||||
|
|
||||||
it('should create package.json without exports field for apps', async () => {
|
it('should create package.json without exports field for apps', async () => {
|
||||||
addProjectConfiguration(tree, 'my-app', {
|
addProjectConfiguration(tree, 'my-app', {
|
||||||
root: 'apps/my-app',
|
root: 'apps/my-app',
|
||||||
|
|||||||
@ -219,6 +219,10 @@ function updatePackageJson(
|
|||||||
const rootDir = join(project.root, 'src');
|
const rootDir = join(project.root, 'src');
|
||||||
const outputPath = joinPathFragments(project.root, 'dist');
|
const outputPath = joinPathFragments(project.root, 'dist');
|
||||||
|
|
||||||
|
// the file must exist in the TS solution setup, which is the only case this
|
||||||
|
// function is called
|
||||||
|
const tsconfigBase = readJson(tree, 'tsconfig.base.json');
|
||||||
|
|
||||||
packageJson = getUpdatedPackageJsonContent(packageJson, {
|
packageJson = getUpdatedPackageJsonContent(packageJson, {
|
||||||
main,
|
main,
|
||||||
outputPath,
|
outputPath,
|
||||||
@ -227,6 +231,10 @@ function updatePackageJson(
|
|||||||
generateExportsField: true,
|
generateExportsField: true,
|
||||||
packageJsonPath,
|
packageJsonPath,
|
||||||
format: ['esm'],
|
format: ['esm'],
|
||||||
|
skipDevelopmentExports:
|
||||||
|
!tsconfigBase.compilerOptions?.customConditions?.includes(
|
||||||
|
'development'
|
||||||
|
),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -4,25 +4,23 @@ import type { NormalizedSchema } from '../schema';
|
|||||||
export function determineEntryFields(
|
export function determineEntryFields(
|
||||||
options: NormalizedSchema
|
options: NormalizedSchema
|
||||||
): Pick<PackageJson, 'module' | 'types' | 'exports'> {
|
): Pick<PackageJson, 'module' | 'types' | 'exports'> {
|
||||||
if (options.bundler === 'none') {
|
if (options.bundler !== 'none' || !options.isUsingTsSolutionConfig) {
|
||||||
return {
|
// for buildable libraries, the entries are configured by the bundler
|
||||||
module: options.js ? './src/index.js' : './src/index.ts',
|
return undefined;
|
||||||
types: options.js ? './src/index.js' : './src/index.ts',
|
|
||||||
exports: {
|
|
||||||
'.': options.js
|
|
||||||
? './src/index.js'
|
|
||||||
: {
|
|
||||||
types: './src/index.ts',
|
|
||||||
import: './src/index.ts',
|
|
||||||
default: './src/index.ts',
|
|
||||||
},
|
|
||||||
'./package.json': './package.json',
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
module: './dist/index.mjs',
|
module: options.js ? './src/index.js' : './src/index.ts',
|
||||||
types: './dist/index.d.ts',
|
types: options.js ? './src/index.js' : './src/index.ts',
|
||||||
|
exports: {
|
||||||
|
'.': options.js
|
||||||
|
? './src/index.js'
|
||||||
|
: {
|
||||||
|
types: './src/index.ts',
|
||||||
|
import: './src/index.ts',
|
||||||
|
default: './src/index.ts',
|
||||||
|
},
|
||||||
|
'./package.json': './package.json',
|
||||||
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@ -521,6 +521,7 @@ module.exports = [
|
|||||||
compilerOptions: {
|
compilerOptions: {
|
||||||
composite: true,
|
composite: true,
|
||||||
declaration: true,
|
declaration: true,
|
||||||
|
customConditions: ['development'],
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
writeJson(tree, 'tsconfig.json', {
|
writeJson(tree, 'tsconfig.json', {
|
||||||
@ -585,6 +586,39 @@ module.exports = [
|
|||||||
"nx",
|
"nx",
|
||||||
]
|
]
|
||||||
`);
|
`);
|
||||||
|
expect(tree.read('my-lib/package.json', 'utf-8')).toMatchInlineSnapshot(`
|
||||||
|
"{
|
||||||
|
"name": "@proj/my-lib",
|
||||||
|
"version": "0.0.1",
|
||||||
|
"module": "./src/index.ts",
|
||||||
|
"types": "./src/index.ts",
|
||||||
|
"exports": {
|
||||||
|
".": {
|
||||||
|
"types": "./src/index.ts",
|
||||||
|
"import": "./src/index.ts",
|
||||||
|
"default": "./src/index.ts"
|
||||||
|
},
|
||||||
|
"./package.json": "./package.json"
|
||||||
|
},
|
||||||
|
"nx": {
|
||||||
|
"targets": {
|
||||||
|
"lint": {
|
||||||
|
"executor": "@nx/eslint:lint"
|
||||||
|
},
|
||||||
|
"test": {
|
||||||
|
"executor": "@nx/vite:test",
|
||||||
|
"outputs": [
|
||||||
|
"{options.reportsDirectory}"
|
||||||
|
],
|
||||||
|
"options": {
|
||||||
|
"reportsDirectory": "../coverage/my-lib"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"
|
||||||
|
`);
|
||||||
expect(readJson(tree, 'my-lib/tsconfig.json')).toMatchInlineSnapshot(`
|
expect(readJson(tree, 'my-lib/tsconfig.json')).toMatchInlineSnapshot(`
|
||||||
{
|
{
|
||||||
"extends": "../tsconfig.base.json",
|
"extends": "../tsconfig.base.json",
|
||||||
@ -690,6 +724,60 @@ module.exports = [
|
|||||||
`);
|
`);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should create a correct package.json for buildable libraries', async () => {
|
||||||
|
await libraryGenerator(tree, {
|
||||||
|
...defaultSchema,
|
||||||
|
setParserOptionsProject: true,
|
||||||
|
linter: 'eslint',
|
||||||
|
addPlugin: true,
|
||||||
|
useProjectJson: false,
|
||||||
|
bundler: 'vite',
|
||||||
|
skipFormat: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(tree.read('my-lib/package.json', 'utf-8')).toMatchInlineSnapshot(`
|
||||||
|
"{
|
||||||
|
"name": "@proj/my-lib",
|
||||||
|
"version": "0.0.1",
|
||||||
|
"type": "module",
|
||||||
|
"main": "./dist/index.js",
|
||||||
|
"module": "./dist/index.js",
|
||||||
|
"types": "./dist/index.d.ts",
|
||||||
|
"exports": {
|
||||||
|
"./package.json": "./package.json",
|
||||||
|
".": {
|
||||||
|
"development": "./src/index.ts",
|
||||||
|
"types": "./dist/index.d.ts",
|
||||||
|
"import": "./dist/index.js",
|
||||||
|
"default": "./dist/index.js"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"
|
||||||
|
`);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not set the "development" condition in exports when it does not exist in tsconfig.base.json', async () => {
|
||||||
|
updateJson(tree, 'tsconfig.base.json', (json) => {
|
||||||
|
delete json.compilerOptions.customConditions;
|
||||||
|
return json;
|
||||||
|
});
|
||||||
|
|
||||||
|
await libraryGenerator(tree, {
|
||||||
|
...defaultSchema,
|
||||||
|
setParserOptionsProject: true,
|
||||||
|
linter: 'eslint',
|
||||||
|
addPlugin: true,
|
||||||
|
useProjectJson: false,
|
||||||
|
bundler: 'vite',
|
||||||
|
skipFormat: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(
|
||||||
|
readJson(tree, 'my-lib/package.json').exports['.']
|
||||||
|
).not.toHaveProperty('development');
|
||||||
|
});
|
||||||
|
|
||||||
it('should set "nx.name" in package.json when the user provides a name that is different than the package name', async () => {
|
it('should set "nx.name" in package.json when the user provides a name that is different than the package name', async () => {
|
||||||
await libraryGenerator(tree, {
|
await libraryGenerator(tree, {
|
||||||
...defaultSchema,
|
...defaultSchema,
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user