diff --git a/docs/generated/packages/web.json b/docs/generated/packages/web.json index ec80b28f6ac9c..cc4c7e791d940 100644 --- a/docs/generated/packages/web.json +++ b/docs/generated/packages/web.json @@ -757,6 +757,16 @@ "type": "boolean", "description": "Sets `javascriptEnabled` option for less loader", "default": false + }, + "generateExportsField": { + "type": "boolean", + "description": "Generate package.json with 'exports' field. This field defines entry points in the package and is used by Node and the TypeScript compiler.", + "default": false + }, + "skipTypeField": { + "type": "boolean", + "description": "Prevents 'type' field from being added to compiled package.json file. Only use this if you are having an issue with this field.", + "default": false } }, "required": ["tsConfig", "project", "entryFile", "outputPath"], diff --git a/packages/web/src/executors/rollup/lib/update-package-json.spec.ts b/packages/web/src/executors/rollup/lib/update-package-json.spec.ts index 7ff0b6de2b33b..f79366e69dbfb 100644 --- a/packages/web/src/executors/rollup/lib/update-package-json.spec.ts +++ b/packages/web/src/executors/rollup/lib/update-package-json.spec.ts @@ -2,8 +2,6 @@ import { updatePackageJson } from './update-package-json'; import * as utils from 'nx/src/utils/fileutils'; import { PackageJson } from 'nx/src/utils/package-json'; -jest.mock('fs', () => require('memfs').fs); - describe('updatePackageJson', () => { const commonOptions = { outputPath: 'dist/index.js', @@ -23,132 +21,273 @@ describe('updatePackageJson', () => { cwd: '', }; - it('should support ESM', () => { - const spy = jest.spyOn(utils, 'writeJsonFile'); - - updatePackageJson( - { - ...commonOptions, - format: ['esm'], - }, - sharedContext, - { type: 'app', name: 'test', data: {} }, - [], - {} as unknown as PackageJson - ); - - expect(utils.writeJsonFile).toHaveBeenCalledWith(expect.anything(), { - exports: { - '.': { - types: './index.d.ts', - import: './index.js', + // TODO(jack): In Nx 15 we want this field to always generate. + describe('generateExportsField: true', () => { + it('should support ESM', () => { + const spy = jest.spyOn(utils, 'writeJsonFile'); + + updatePackageJson( + { + ...commonOptions, + generateExportsField: true, + format: ['esm'], + }, + sharedContext, + { type: 'app', name: 'test', data: {} }, + [], + {} as unknown as PackageJson + ); + + expect(utils.writeJsonFile).toHaveBeenCalledWith(expect.anything(), { + exports: { + '.': { + types: './index.d.ts', + import: './index.js', + }, }, - }, - main: './index.js', - module: './index.js', - type: 'module', - types: './index.d.ts', + main: './index.js', + module: './index.js', + type: 'module', + types: './index.d.ts', + }); + + spy.mockRestore(); }); - spy.mockRestore(); - }); + it('should support CJS', () => { + const spy = jest.spyOn(utils, 'writeJsonFile'); - it('should support CJS', () => { - const spy = jest.spyOn(utils, 'writeJsonFile'); - - updatePackageJson( - { - ...commonOptions, - format: ['cjs'], - }, - sharedContext, - { type: 'app', name: 'test', data: {} }, - [], - {} as unknown as PackageJson - ); - - expect(utils.writeJsonFile).toHaveBeenCalledWith(expect.anything(), { - exports: { - '.': { - types: './index.d.ts', - require: './index.cjs', + updatePackageJson( + { + ...commonOptions, + generateExportsField: true, + format: ['cjs'], }, - }, - main: './index.cjs', - type: 'commonjs', - types: './index.d.ts', + sharedContext, + { type: 'app', name: 'test', data: {} }, + [], + {} as unknown as PackageJson + ); + + expect(utils.writeJsonFile).toHaveBeenCalledWith(expect.anything(), { + exports: { + '.': { + types: './index.d.ts', + require: './index.cjs', + }, + }, + main: './index.cjs', + type: 'commonjs', + types: './index.d.ts', + }); + + spy.mockRestore(); }); - spy.mockRestore(); - }); + it('should support ESM + CJS', () => { + const spy = jest.spyOn(utils, 'writeJsonFile'); + + updatePackageJson( + { + ...commonOptions, + generateExportsField: true, + format: ['esm', 'cjs'], + }, + sharedContext, + { type: 'app', name: 'test', data: {} }, + [], + {} as unknown as PackageJson + ); - it('should support ESM + CJS', () => { - const spy = jest.spyOn(utils, 'writeJsonFile'); - - updatePackageJson( - { - ...commonOptions, - format: ['esm', 'cjs'], - }, - sharedContext, - { type: 'app', name: 'test', data: {} }, - [], - {} as unknown as PackageJson - ); - - expect(utils.writeJsonFile).toHaveBeenCalledWith(expect.anything(), { - exports: { - '.': { - types: './index.d.ts', - import: './index.js', - require: './index.cjs', + expect(utils.writeJsonFile).toHaveBeenCalledWith(expect.anything(), { + exports: { + '.': { + types: './index.d.ts', + import: './index.js', + require: './index.cjs', + }, }, - }, - main: './index.cjs', - module: './index.js', - type: 'module', - types: './index.d.ts', + main: './index.cjs', + module: './index.js', + type: 'module', + types: './index.d.ts', + }); + + spy.mockRestore(); }); - spy.mockRestore(); - }); + it('should support custom exports field', () => { + const spy = jest.spyOn(utils, 'writeJsonFile'); + + updatePackageJson( + { + ...commonOptions, + generateExportsField: true, + format: ['esm'], + }, + sharedContext, + { type: 'app', name: 'test', data: {} }, + [], + { + exports: { + './foo': { + import: './foo.js', + }, + }, + } as unknown as PackageJson + ); - it('should support custom exports field', () => { - const spy = jest.spyOn(utils, 'writeJsonFile'); - - updatePackageJson( - { - ...commonOptions, - format: ['esm'], - }, - sharedContext, - { type: 'app', name: 'test', data: {} }, - [], - { + expect(utils.writeJsonFile).toHaveBeenCalledWith(expect.anything(), { exports: { - foo: { + '.': { + types: './index.d.ts', + import: './index.js', + }, + './foo': { import: './foo.js', }, }, - } as unknown as PackageJson - ); - - expect(utils.writeJsonFile).toHaveBeenCalledWith(expect.anything(), { - exports: { - '.': { - types: './index.d.ts', - import: './index.js', + main: './index.js', + module: './index.js', + type: 'module', + types: './index.d.ts', + }); + + spy.mockRestore(); + }); + }); + + describe('generateExportsField: false', () => { + it('should support ESM', () => { + const spy = jest.spyOn(utils, 'writeJsonFile'); + + updatePackageJson( + { + ...commonOptions, + format: ['esm'], }, - foo: { - import: './foo.js', + sharedContext, + { type: 'app', name: 'test', data: {} }, + [], + {} as unknown as PackageJson + ); + + expect(utils.writeJsonFile).toHaveBeenCalledWith(expect.anything(), { + main: './index.js', + module: './index.js', + type: 'module', + types: './index.d.ts', + }); + + spy.mockRestore(); + }); + + it('should support CJS', () => { + const spy = jest.spyOn(utils, 'writeJsonFile'); + + updatePackageJson( + { + ...commonOptions, + format: ['cjs'], }, - }, - main: './index.js', - module: './index.js', - type: 'module', - types: './index.d.ts', + sharedContext, + { type: 'app', name: 'test', data: {} }, + [], + {} as unknown as PackageJson + ); + + expect(utils.writeJsonFile).toHaveBeenCalledWith(expect.anything(), { + main: './index.cjs', + type: 'commonjs', + types: './index.d.ts', + }); + + spy.mockRestore(); }); - spy.mockRestore(); + it('should support ESM + CJS', () => { + const spy = jest.spyOn(utils, 'writeJsonFile'); + + updatePackageJson( + { + ...commonOptions, + format: ['esm', 'cjs'], + }, + sharedContext, + { type: 'app', name: 'test', data: {} }, + [], + {} as unknown as PackageJson + ); + + expect(utils.writeJsonFile).toHaveBeenCalledWith(expect.anything(), { + main: './index.cjs', + module: './index.js', + type: 'module', + types: './index.d.ts', + }); + + spy.mockRestore(); + }); + + it('should support custom exports field', () => { + const spy = jest.spyOn(utils, 'writeJsonFile'); + + updatePackageJson( + { + ...commonOptions, + format: ['esm'], + }, + sharedContext, + { type: 'app', name: 'test', data: {} }, + [], + { + exports: { + './foo': { + import: './foo.js', + }, + }, + } as unknown as PackageJson + ); + + expect(utils.writeJsonFile).toHaveBeenCalledWith(expect.anything(), { + main: './index.js', + module: './index.js', + type: 'module', + types: './index.d.ts', + exports: { + './foo': { + import: './foo.js', + }, + }, + }); + + spy.mockRestore(); + }); + }); + + describe('skipTypeField', () => { + it('should not add "type" field in package.json', () => { + const spy = jest.spyOn(utils, 'writeJsonFile'); + + updatePackageJson( + { + ...commonOptions, + format: ['esm'], + skipTypeField: true, + }, + sharedContext, + { type: 'app', name: 'test', data: {} }, + [], + {} as unknown as PackageJson + ); + + expect(utils.writeJsonFile).toHaveBeenCalledWith(expect.anything(), { + main: './index.js', + module: './index.js', + types: './index.d.ts', + }); + + spy.mockRestore(); + }); }); }); diff --git a/packages/web/src/executors/rollup/lib/update-package-json.ts b/packages/web/src/executors/rollup/lib/update-package-json.ts index d0537ff012db9..31b4f7a9a93fa 100644 --- a/packages/web/src/executors/rollup/lib/update-package-json.ts +++ b/packages/web/src/executors/rollup/lib/update-package-json.ts @@ -47,15 +47,20 @@ export function updatePackageJson( exports['.']['require'] = './index.cjs'; } - packageJson.type = options.format.includes('esm') ? 'module' : 'commonjs'; + if (!options.skipTypeField) { + packageJson.type = options.format.includes('esm') ? 'module' : 'commonjs'; + } // Support for older TS versions < 4.5 packageJson.types = types; - packageJson.exports = { - ...packageJson.exports, - ...exports, - }; + // TODO(jack): remove this for Nx 15 + if (options.generateExportsField) { + packageJson.exports = { + ...packageJson.exports, + ...exports, + }; + } writeJsonFile(`${options.outputPath}/package.json`, packageJson); diff --git a/packages/web/src/executors/rollup/schema.d.ts b/packages/web/src/executors/rollup/schema.d.ts index 75a58d2f0c7db..528b1b5345025 100644 --- a/packages/web/src/executors/rollup/schema.d.ts +++ b/packages/web/src/executors/rollup/schema.d.ts @@ -23,4 +23,7 @@ export interface WebRollupOptions { format: string[]; compiler?: Compiler; javascriptEnabled?: boolean; + // TODO(jack): remove this for Nx 15 + skipTypeField?: boolean; + generateExportsField?: boolean; } diff --git a/packages/web/src/executors/rollup/schema.json b/packages/web/src/executors/rollup/schema.json index fd194304bbaab..ccbb6142c98b6 100644 --- a/packages/web/src/executors/rollup/schema.json +++ b/packages/web/src/executors/rollup/schema.json @@ -119,10 +119,19 @@ "type": "boolean", "description": "Sets `javascriptEnabled` option for less loader", "default": false + }, + "generateExportsField": { + "type": "boolean", + "description": "Generate package.json with 'exports' field. This field defines entry points in the package and is used by Node and the TypeScript compiler.", + "default": false + }, + "skipTypeField": { + "type": "boolean", + "description": "Prevents 'type' field from being added to compiled package.json file. Only use this if you are having an issue with this field.", + "default": false } }, "required": ["tsConfig", "project", "entryFile", "outputPath"], - "definitions": { "assetPattern": { "oneOf": [