fix(js): generate js libs with exports in package.json and ensure esm output when using rollup bundler (#29565)

- Ensure libs are generated with `exports` in `package.json`
- Generate `types` instead of `typings` in package.json
- Update js lib with rollup to only output esm
- Update `tsconfig.spec.json` for js libraries with rollup to set
`module: esnext` and `moduleResolution: bundler` (they use `@swc/jest`)
- Fix `@nx/js/typescript` issue with absolute paths when normalizing
inputs/outputs
- Fix `@nx/js/typescript` issue identifying buildable libs
- Fix express app generator not installing `@types/express`

<!-- Please make sure you have read the submission guidelines before
posting an PR -->
<!--
https://github.com/nrwl/nx/blob/master/CONTRIBUTING.md#-submitting-a-pr
-->

<!-- Please make sure that your commit message follows our format -->
<!-- Example: `fix(nx): must begin with lowercase` -->

<!-- If this is a particularly complex change or feature addition, you
can request a dedicated Nx release for this pull request branch. Mention
someone from the Nx team or the `@nrwl/nx-pipelines-reviewers` and they
will confirm if the PR warrants its own release for testing purposes,
and generate it for you if appropriate. -->

## Current Behavior
<!-- This is the behavior we have today -->

## Expected Behavior
<!-- This is the behavior we should expect with the changes in this PR
-->

## Related Issue(s)
<!-- Please link the issue being fixed so it gets closed when this is
merged. -->

Fixes #

---------

Co-authored-by: Jack Hsu <jack.hsu@gmail.com>
This commit is contained in:
Leosvel Pérez Espinosa 2025-01-10 14:29:09 +01:00 committed by GitHub
parent cbfc6fe97f
commit dd9b09f917
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
18 changed files with 235 additions and 86 deletions

View File

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

View File

@ -567,7 +567,7 @@ describe('Linter', () => {
name: `@proj/${mylib}`, name: `@proj/${mylib}`,
private: true, private: true,
type: 'commonjs', type: 'commonjs',
typings: './src/index.d.ts', types: './src/index.d.ts',
version: '0.0.1', version: '0.0.1',
}); });

View File

@ -116,9 +116,11 @@ packages:
expect(() => runCLI(`lint ${nodeapp}`)).not.toThrow(); expect(() => runCLI(`lint ${nodeapp}`)).not.toThrow();
expect(() => runCLI(`test ${nodeapp}`)).not.toThrow(); expect(() => runCLI(`test ${nodeapp}`)).not.toThrow();
expect(() => runCLI(`build ${nodeapp}`)).not.toThrow(); expect(() => runCLI(`build ${nodeapp}`)).not.toThrow();
expect(() => runCLI(`typecheck ${nodeapp}`)).not.toThrow();
expect(() => runCLI(`lint ${nodelib}`)).not.toThrow(); expect(() => runCLI(`lint ${nodelib}`)).not.toThrow();
expect(() => runCLI(`test ${nodelib}`)).not.toThrow(); expect(() => runCLI(`test ${nodelib}`)).not.toThrow();
expect(() => runCLI(`build ${nodelib}`)).not.toThrow(); expect(() => runCLI(`build ${nodelib}`)).not.toThrow();
expect(() => runCLI(`typecheck ${nodelib}`)).not.toThrow();
const p = await runCommandUntil( const p = await runCommandUntil(
`serve ${nodeapp}`, `serve ${nodeapp}`,

View File

@ -82,6 +82,7 @@ export async function applicationGeneratorInternal(tree: Tree, schema: Schema) {
const applicationTask = await nodeApplicationGenerator(tree, { const applicationTask = await nodeApplicationGenerator(tree, {
...options, ...options,
bundler: 'webpack', bundler: 'webpack',
framework: 'express',
skipFormat: true, skipFormat: true,
}); });
tasks.push(applicationTask); tasks.push(applicationTask);

View File

@ -62,7 +62,8 @@ export function createFiles(
? `${rootOffset}tsconfig.base.json` ? `${rootOffset}tsconfig.base.json`
: './tsconfig.json', : './tsconfig.json',
outDir: isTsSolutionSetup ? `./out-tsc/jest` : `${rootOffset}dist/out-tsc`, outDir: isTsSolutionSetup ? `./out-tsc/jest` : `${rootOffset}dist/out-tsc`,
module: !isTsSolutionSetup ? 'commonjs' : undefined, module:
!isTsSolutionSetup || transformer === 'ts-jest' ? 'commonjs' : undefined,
}); });
if (options.setupFile === 'none') { if (options.setupFile === 'none') {

View File

@ -1653,6 +1653,14 @@ describe('lib', () => {
expect(readJson(tree, 'my-ts-lib/package.json')).toMatchInlineSnapshot(` expect(readJson(tree, 'my-ts-lib/package.json')).toMatchInlineSnapshot(`
{ {
"dependencies": {}, "dependencies": {},
"exports": {
".": {
"default": "./src/index.ts",
"import": "./src/index.ts",
"types": "./src/index.ts",
},
"./package.json": "./package.json",
},
"main": "./src/index.ts", "main": "./src/index.ts",
"name": "@proj/my-ts-lib", "name": "@proj/my-ts-lib",
"private": true, "private": true,
@ -1663,6 +1671,10 @@ describe('lib', () => {
expect(readJson(tree, 'my-js-lib/package.json')).toMatchInlineSnapshot(` expect(readJson(tree, 'my-js-lib/package.json')).toMatchInlineSnapshot(`
{ {
"dependencies": {}, "dependencies": {},
"exports": {
".": "./src/index.js",
"./package.json": "./package.json",
},
"main": "./src/index.js", "main": "./src/index.js",
"name": "@proj/my-js-lib", "name": "@proj/my-js-lib",
"private": true, "private": true,
@ -1686,11 +1698,20 @@ describe('lib', () => {
"dependencies": { "dependencies": {
"tslib": "^2.3.0", "tslib": "^2.3.0",
}, },
"exports": {
".": {
"default": "./dist/index.js",
"import": "./dist/index.js",
"types": "./dist/index.d.ts",
},
"./package.json": "./package.json",
},
"main": "./dist/index.js", "main": "./dist/index.js",
"module": "./dist/index.js",
"name": "@proj/my-ts-lib", "name": "@proj/my-ts-lib",
"private": true, "private": true,
"type": "module", "type": "module",
"typings": "./dist/index.d.ts", "types": "./dist/index.d.ts",
"version": "0.0.1", "version": "0.0.1",
} }
`); `);
@ -1710,11 +1731,20 @@ describe('lib', () => {
"dependencies": { "dependencies": {
"@swc/helpers": "~0.5.11", "@swc/helpers": "~0.5.11",
}, },
"exports": {
".": {
"default": "./dist/index.js",
"import": "./dist/index.js",
"types": "./dist/index.d.ts",
},
"./package.json": "./package.json",
},
"main": "./dist/index.js", "main": "./dist/index.js",
"module": "./dist/index.js",
"name": "@proj/my-ts-lib", "name": "@proj/my-ts-lib",
"private": true, "private": true,
"type": "module", "type": "module",
"typings": "./dist/index.d.ts", "types": "./dist/index.d.ts",
"version": "0.0.1", "version": "0.0.1",
} }
`); `);

View File

@ -1,12 +1,12 @@
import { import {
addDependenciesToPackageJson, addDependenciesToPackageJson,
installPackagesTask,
addProjectConfiguration, addProjectConfiguration,
ensurePackage, ensurePackage,
formatFiles, formatFiles,
generateFiles, generateFiles,
GeneratorCallback, GeneratorCallback,
getPackageManagerCommand, getPackageManagerCommand,
installPackagesTask,
joinPathFragments, joinPathFragments,
names, names,
offsetFromRoot, offsetFromRoot,
@ -35,6 +35,7 @@ import { type PackageJson } from 'nx/src/utils/package-json';
import { join } from 'path'; import { join } from 'path';
import type { CompilerOptions } from 'typescript'; import type { CompilerOptions } from 'typescript';
import { normalizeLinterOption } from '../../utils/generator-prompts'; import { normalizeLinterOption } from '../../utils/generator-prompts';
import { getUpdatedPackageJsonContent } from '../../utils/package-json/update-package-json';
import { import {
getProjectPackageManagerWorkspaceState, getProjectPackageManagerWorkspaceState,
getProjectPackageManagerWorkspaceStateWarningTask, getProjectPackageManagerWorkspaceStateWarningTask,
@ -43,6 +44,7 @@ import { addSwcConfig } from '../../utils/swc/add-swc-config';
import { getSwcDependencies } from '../../utils/swc/add-swc-dependencies'; import { getSwcDependencies } from '../../utils/swc/add-swc-dependencies';
import { getNeededCompilerOptionOverrides } from '../../utils/typescript/configuration'; import { getNeededCompilerOptionOverrides } from '../../utils/typescript/configuration';
import { tsConfigBaseOptions } from '../../utils/typescript/create-ts-config'; import { tsConfigBaseOptions } from '../../utils/typescript/create-ts-config';
import { ensureTypescript } from '../../utils/typescript/ensure-typescript';
import { ensureProjectIsIncludedInPluginRegistrations } from '../../utils/typescript/plugin'; import { ensureProjectIsIncludedInPluginRegistrations } from '../../utils/typescript/plugin';
import { import {
addTsConfigPath, addTsConfigPath,
@ -68,7 +70,6 @@ import type {
LibraryGeneratorSchema, LibraryGeneratorSchema,
NormalizedLibraryGeneratorOptions, NormalizedLibraryGeneratorOptions,
} from './schema'; } from './schema';
import { ensureTypescript } from '../../utils/typescript/ensure-typescript';
const defaultOutputDirectory = 'dist'; const defaultOutputDirectory = 'dist';
@ -118,7 +119,7 @@ export async function libraryGeneratorInternal(
await configurationGenerator(tree, { await configurationGenerator(tree, {
project: options.name, project: options.name,
compiler: 'swc', compiler: 'swc',
format: ['cjs', 'esm'], format: options.isUsingTsSolutionConfig ? ['esm'] : ['cjs', 'esm'],
}); });
} }
@ -206,6 +207,12 @@ export async function libraryGeneratorInternal(
// add project reference to the runtime tsconfig.lib.json file // add project reference to the runtime tsconfig.lib.json file
json.references ??= []; json.references ??= [];
json.references.push({ path: './tsconfig.lib.json' }); json.references.push({ path: './tsconfig.lib.json' });
if (options.isUsingTsSolutionConfig && options.bundler === 'rollup') {
json.compilerOptions.module = 'esnext';
json.compilerOptions.moduleResolution = 'bundler';
}
return json; return json;
} }
); );
@ -503,8 +510,7 @@ function createFiles(tree: Tree, options: NormalizedLibraryGeneratorOptions) {
let fileNameImport = options.fileName; let fileNameImport = options.fileName;
if ( if (
options.bundler === 'vite' || options.bundler === 'vite' ||
(options.isUsingTsSolutionConfig && (options.isUsingTsSolutionConfig && options.bundler !== 'none')
['esbuild', 'swc', 'tsc'].includes(options.bundler))
) { ) {
const tsConfig = readTsConfigFromTree( const tsConfig = readTsConfigFromTree(
tree, tree,
@ -606,7 +612,8 @@ function createFiles(tree: Tree, options: NormalizedLibraryGeneratorOptions) {
// https://docs.npmjs.com/cli/v10/configuring-npm/package-json#files // https://docs.npmjs.com/cli/v10/configuring-npm/package-json#files
json.files = ['dist', '!**/*.tsbuildinfo']; json.files = ['dist', '!**/*.tsbuildinfo'];
} }
return {
const updatedPackageJson = {
...json, ...json,
dependencies: { dependencies: {
...json.dependencies, ...json.dependencies,
@ -614,9 +621,26 @@ function createFiles(tree: Tree, options: NormalizedLibraryGeneratorOptions) {
}, },
...determineEntryFields(options), ...determineEntryFields(options),
}; };
if (
options.isUsingTsSolutionConfig &&
!['none', 'rollup', 'vite'].includes(options.bundler)
) {
return getUpdatedPackageJsonContent(updatedPackageJson, {
main: join(options.projectRoot, 'src/index.ts'),
outputPath: joinPathFragments(options.projectRoot, 'dist'),
projectRoot: options.projectRoot,
rootDir: join(options.projectRoot, 'src'),
generateExportsField: true,
packageJsonPath,
format: ['esm'],
});
}
return updatedPackageJson;
}); });
} else { } else {
const packageJson: PackageJson = { let packageJson: PackageJson = {
name: options.importPath, name: options.importPath,
version: '0.0.1', version: '0.0.1',
dependencies: determineDependencies(options), dependencies: determineDependencies(options),
@ -630,6 +654,22 @@ function createFiles(tree: Tree, options: NormalizedLibraryGeneratorOptions) {
// https://docs.npmjs.com/cli/v10/configuring-npm/package-json#files // https://docs.npmjs.com/cli/v10/configuring-npm/package-json#files
packageJson.files = ['dist', '!**/*.tsbuildinfo']; packageJson.files = ['dist', '!**/*.tsbuildinfo'];
} }
if (
options.isUsingTsSolutionConfig &&
!['none', 'rollup', 'vite'].includes(options.bundler)
) {
packageJson = getUpdatedPackageJsonContent(packageJson, {
main: join(options.projectRoot, 'src/index.ts'),
outputPath: joinPathFragments(options.projectRoot, 'dist'),
projectRoot: options.projectRoot,
rootDir: join(options.projectRoot, 'src'),
generateExportsField: true,
packageJsonPath,
format: ['esm'],
});
}
writeJson<PackageJson>(tree, packageJsonPath, packageJson); writeJson<PackageJson>(tree, packageJsonPath, packageJson);
} }
@ -1094,74 +1134,84 @@ function determineEntryFields(
): Record<string, EntryField> { ): Record<string, EntryField> {
switch (options.bundler) { switch (options.bundler) {
case 'tsc': case 'tsc':
return {
type: options.isUsingTsSolutionConfig ? 'module' : 'commonjs',
main: options.isUsingTsSolutionConfig
? './dist/index.js'
: './src/index.js',
typings: options.isUsingTsSolutionConfig
? './dist/index.d.ts'
: './src/index.d.ts',
};
case 'swc': case 'swc':
return { if (options.isUsingTsSolutionConfig) {
type: options.isUsingTsSolutionConfig ? 'module' : 'commonjs', return {
main: options.isUsingTsSolutionConfig type: 'module',
? './dist/index.js' main: './dist/index.js',
: './src/index.js', types: './dist/index.d.ts',
typings: options.isUsingTsSolutionConfig };
? './dist/index.d.ts' } else {
: './src/index.d.ts', return {
}; type: 'commonjs',
main: './src/index.js',
types: './src/index.d.ts',
};
}
case 'rollup': case 'rollup':
return { if (options.isUsingTsSolutionConfig) {
// Since we're publishing both formats, skip the type field. // the rollup configuration generator already handles this
// Bundlers or Node will determine the entry point to use. return {};
main: options.isUsingTsSolutionConfig } else {
? './dist/index.cjs' return {
: './index.cjs', // Since we're publishing both formats, skip the type field.
module: options.isUsingTsSolutionConfig // Bundlers or Node will determine the entry point to use.
? './dist/index.js' main: './index.cjs',
: './index.js', module: './index.js',
}; };
}
case 'vite': case 'vite':
return { if (options.isUsingTsSolutionConfig) {
type: 'module', // the vite configuration generator already handle this
main: options.isUsingTsSolutionConfig return {};
? './dist/index.js' } else {
: './index.js', return {
typings: options.isUsingTsSolutionConfig type: 'module',
? './dist/index.d.ts' main: './index.js',
: './index.d.ts', types: './index.d.ts',
}; };
}
case 'esbuild': case 'esbuild':
return { if (options.isUsingTsSolutionConfig) {
type: options.isUsingTsSolutionConfig ? 'module' : 'commonjs', return {
main: options.isUsingTsSolutionConfig type: 'module',
? './dist/index.js' main: './dist/index.js',
: './index.cjs', types: './dist/index.d.ts',
typings: options.isUsingTsSolutionConfig };
? './dist/index.d.ts' } else {
: './index.d.ts', return {
}; type: 'commonjs',
default: { main: './index.cjs',
types: './index.d.ts',
};
}
case 'none': {
if (options.isUsingTsSolutionConfig) {
return {
main: options.js ? './src/index.js' : './src/index.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',
},
};
}
return { return {
// Safest option is to not set a type field. // Safest option is to not set a type field.
// Allow the user to decide which module format their library is using // Allow the user to decide which module format their library is using
type: undefined, type: undefined,
// For non-buildable libraries, point to source so we can still use them in apps via bundlers like Vite.
main: options.isUsingTsSolutionConfig
? options.js
? './src/index.js'
: './src/index.ts'
: undefined,
types: options.isUsingTsSolutionConfig
? options.js
? './src/index.js'
: './src/index.ts'
: undefined,
}; };
} }
default: {
return {};
}
} }
} }

View File

@ -144,7 +144,7 @@ export async function setupBuildGenerator(
tsConfig: tsConfigFile, tsConfig: tsConfigFile,
project: options.project, project: options.project,
compiler: 'tsc', compiler: 'tsc',
format: ['cjs', 'esm'], format: isTsSolutionSetup ? ['esm'] : ['cjs', 'esm'],
addPlugin, addPlugin,
skipFormat: true, skipFormat: true,
skipValidation: true, skipValidation: true,

View File

@ -1919,7 +1919,18 @@ describe(`Plugin: ${PLUGIN_NAME}`, () => {
'libs/my-lib/tsconfig.json': `{}`, 'libs/my-lib/tsconfig.json': `{}`,
'libs/my-lib/tsconfig.lib.json': `{"compilerOptions": {"outDir": "dist"}}`, 'libs/my-lib/tsconfig.lib.json': `{"compilerOptions": {"outDir": "dist"}}`,
'libs/my-lib/tsconfig.build.json': `{}`, 'libs/my-lib/tsconfig.build.json': `{}`,
'libs/my-lib/package.json': `{"main": "dist/index.js"}`, 'libs/my-lib/package.json': JSON.stringify({
main: 'dist/index.js',
types: 'dist/index.d.ts',
exports: {
'.': {
types: './dist/index.d.ts',
import: './dist/index.js',
default: './dist/index.js',
},
'./package.json': './package.json',
},
}),
}); });
expect( expect(
await invokeCreateNodesOnMatchingFiles(context, { await invokeCreateNodesOnMatchingFiles(context, {

View File

@ -633,18 +633,17 @@ function getOutputs(
* @returns `true` if the package has a valid build configuration; otherwise, `false`. * @returns `true` if the package has a valid build configuration; otherwise, `false`.
*/ */
function isValidPackageJsonBuildConfig( function isValidPackageJsonBuildConfig(
tsConfig, tsConfig: ParsedCommandLine,
workspaceRoot: string, workspaceRoot: string,
projectRoot: string projectRoot: string
): boolean { ): boolean {
if (!existsSync(joinPathFragments(projectRoot, 'package.json'))) { const packageJsonPath = join(workspaceRoot, projectRoot, 'package.json');
if (!existsSync(packageJsonPath)) {
// If the package.json file does not exist. // If the package.json file does not exist.
// Assume it's valid because it would be using `project.json` instead. // Assume it's valid because it would be using `project.json` instead.
return true; return true;
} }
const packageJson = readJsonFile( const packageJson = readJsonFile(packageJsonPath);
joinPathFragments(projectRoot, 'package.json')
);
const outDir = tsConfig.options.outFile const outDir = tsConfig.options.outFile
? dirname(tsConfig.options.outFile) ? dirname(tsConfig.options.outFile)
@ -691,10 +690,9 @@ function isValidPackageJsonBuildConfig(
if (exports) { if (exports) {
if (typeof exports === 'string') { if (typeof exports === 'string') {
return !isPathSourceFile(exports); return !isPathSourceFile(exports);
} else if (typeof exports === 'object' && '.' in exports) { }
if (containsInvalidPath(exports['.'])) { if (typeof exports === 'object' && '.' in exports) {
return false; return !containsInvalidPath(exports['.']);
}
} }
// Check other exports if `.` is not defined or valid. // Check other exports if `.` is not defined or valid.
@ -723,9 +721,16 @@ function pathToInputOrOutput(
workspaceRoot: string, workspaceRoot: string,
projectRoot: string projectRoot: string
): string { ): string {
const pathRelativeToProjectRoot = normalizePath(relative(projectRoot, path)); const fullProjectRoot = resolve(workspaceRoot, projectRoot);
const fullPath = resolve(workspaceRoot, path);
const pathRelativeToProjectRoot = normalizePath(
relative(fullProjectRoot, fullPath)
);
if (pathRelativeToProjectRoot.startsWith('..')) { if (pathRelativeToProjectRoot.startsWith('..')) {
return joinPathFragments('{workspaceRoot}', relative(workspaceRoot, path)); return joinPathFragments(
'{workspaceRoot}',
relative(workspaceRoot, fullPath)
);
} }
return joinPathFragments('{projectRoot}', pathRelativeToProjectRoot); return joinPathFragments('{projectRoot}', pathRelativeToProjectRoot);

View File

@ -157,6 +157,7 @@ describe('getUpdatedPackageJsonContent', () => {
version: '0.0.1', version: '0.0.1',
exports: { exports: {
'.': { '.': {
default: './src/index.js',
import: './src/index.js', import: './src/index.js',
types: './src/index.d.ts', types: './src/index.d.ts',
}, },
@ -268,6 +269,7 @@ describe('getUpdatedPackageJsonContent', () => {
version: '0.0.1', version: '0.0.1',
exports: { exports: {
'.': { '.': {
default: './src/index.js',
import: './src/index.js', import: './src/index.js',
types: './src/index.d.ts', types: './src/index.d.ts',
}, },

View File

@ -326,6 +326,9 @@ export function getUpdatedPackageJsonContent(
: filePath; : filePath;
} else if (typeof packageJson.exports[exportEntry] === 'object') { } else if (typeof packageJson.exports[exportEntry] === 'object') {
packageJson.exports[exportEntry].import ??= filePath; packageJson.exports[exportEntry].import ??= filePath;
if (!hasCjsFormat) {
packageJson.exports[exportEntry].default ??= filePath;
}
} }
} }
} }

View File

@ -8,9 +8,9 @@ import {
updateJson, updateJson,
workspaceRoot, workspaceRoot,
} from '@nx/devkit'; } from '@nx/devkit';
import { basename, dirname, join } from 'node:path/posix';
import { FsTree } from 'nx/src/generators/tree'; import { FsTree } from 'nx/src/generators/tree';
import { isUsingPackageManagerWorkspaces } from '../package-manager-workspaces'; import { isUsingPackageManagerWorkspaces } from '../package-manager-workspaces';
import { basename, dirname, join, relative } from 'node:path/posix';
export function isUsingTypeScriptPlugin(tree: Tree): boolean { export function isUsingTypeScriptPlugin(tree: Tree): boolean {
const nxJson = readNxJson(tree); const nxJson = readNxJson(tree);

View File

@ -433,6 +433,8 @@ describe('lib', () => {
expect(readJson(tree, 'mylib/tsconfig.spec.json')).toMatchInlineSnapshot(` expect(readJson(tree, 'mylib/tsconfig.spec.json')).toMatchInlineSnapshot(`
{ {
"compilerOptions": { "compilerOptions": {
"module": "commonjs",
"moduleResolution": "node10",
"outDir": "./out-tsc/jest", "outDir": "./out-tsc/jest",
"types": [ "types": [
"jest", "jest",

View File

@ -556,6 +556,14 @@ describe('lib', () => {
expect(readJson(tree, 'mylib/package.json')).toMatchInlineSnapshot(` expect(readJson(tree, 'mylib/package.json')).toMatchInlineSnapshot(`
{ {
"dependencies": {}, "dependencies": {},
"exports": {
".": {
"default": "./src/index.ts",
"import": "./src/index.ts",
"types": "./src/index.ts",
},
"./package.json": "./package.json",
},
"main": "./src/index.ts", "main": "./src/index.ts",
"name": "@proj/mylib", "name": "@proj/mylib",
"nx": { "nx": {
@ -612,6 +620,8 @@ describe('lib', () => {
expect(readJson(tree, 'mylib/tsconfig.spec.json')).toMatchInlineSnapshot(` expect(readJson(tree, 'mylib/tsconfig.spec.json')).toMatchInlineSnapshot(`
{ {
"compilerOptions": { "compilerOptions": {
"module": "commonjs",
"moduleResolution": "node10",
"outDir": "./out-tsc/jest", "outDir": "./out-tsc/jest",
"types": [ "types": [
"jest", "jest",
@ -648,7 +658,16 @@ describe('lib', () => {
"dependencies": { "dependencies": {
"tslib": "^2.3.0", "tslib": "^2.3.0",
}, },
"exports": {
".": {
"default": "./dist/index.js",
"import": "./dist/index.js",
"types": "./dist/index.d.ts",
},
"./package.json": "./package.json",
},
"main": "./dist/index.js", "main": "./dist/index.js",
"module": "./dist/index.js",
"name": "@proj/mylib", "name": "@proj/mylib",
"nx": { "nx": {
"name": "mylib", "name": "mylib",
@ -671,8 +690,7 @@ describe('lib', () => {
}, },
}, },
"private": true, "private": true,
"type": "module", "types": "./dist/index.d.ts",
"typings": "./dist/index.d.ts",
"version": "0.0.1", "version": "0.0.1",
} }
`); `);

View File

@ -7,6 +7,7 @@ import {
joinPathFragments, joinPathFragments,
names, names,
offsetFromRoot, offsetFromRoot,
readJson,
readNxJson, readNxJson,
readProjectConfiguration, readProjectConfiguration,
runTasksInSerial, runTasksInSerial,
@ -84,6 +85,8 @@ export async function libraryGeneratorInternal(tree: Tree, schema: Schema) {
}) })
); );
updatePackageJson(tree, options);
tasks.push( tasks.push(
await initGenerator(tree, { await initGenerator(tree, {
...options, ...options,
@ -234,3 +237,22 @@ function ensureDependencies(tree: Tree): GeneratorCallback {
{ '@types/node': typesNodeVersion } { '@types/node': typesNodeVersion }
); );
} }
function updatePackageJson(tree: Tree, options: NormalizedSchema) {
const packageJson = readJson(
tree,
joinPathFragments(options.projectRoot, 'package.json')
);
if (packageJson.type === 'module') {
// The @nx/js:lib generator can set the type to 'module' which would
// potentially break consumers of the library.
delete packageJson.type;
}
writeJson(
tree,
joinPathFragments(options.projectRoot, 'package.json'),
packageJson
);
}

View File

@ -1226,6 +1226,7 @@ module.exports = withNx(
{ {
"exports": { "exports": {
".": { ".": {
"default": "./dist/index.esm.js",
"import": "./dist/index.esm.js", "import": "./dist/index.esm.js",
"types": "./dist/index.esm.d.ts", "types": "./dist/index.esm.d.ts",
}, },

View File

@ -370,6 +370,7 @@ describe('@nx/vite:configuration', () => {
{ {
"exports": { "exports": {
".": { ".": {
"default": "./dist/index.js",
"import": "./dist/index.js", "import": "./dist/index.js",
"types": "./dist/index.d.ts", "types": "./dist/index.d.ts",
}, },