diff --git a/e2e/nx/src/affected-graph.test.ts b/e2e/nx/src/affected-graph.test.ts index badc76a74fa78..0e3171e215f91 100644 --- a/e2e/nx/src/affected-graph.test.ts +++ b/e2e/nx/src/affected-graph.test.ts @@ -31,8 +31,8 @@ describe('Nx Affected and Graph Tests', () => { const mylib = uniq('mylib'); const mylib2 = uniq('mylib2'); const mypublishablelib = uniq('mypublishablelib'); - runCLI(`generate @nx/web:app apps/${myapp}`); - runCLI(`generate @nx/web:app apps/${myapp2}`); + runCLI(`generate @nx/web:app apps/${myapp} --unitTestRunner=vitest`); + runCLI(`generate @nx/web:app apps/${myapp2} --unitTestRunner=vitest`); runCLI(`generate @nx/js:lib libs/${mylib}`); runCLI(`generate @nx/js:lib libs/${mylib2}`); runCLI( @@ -193,8 +193,12 @@ describe('Nx Affected and Graph Tests', () => { }); function generateAll() { - runCLI(`generate @nx/web:app apps/${myapp}`); - runCLI(`generate @nx/web:app apps/${myapp2}`); + runCLI( + `generate @nx/web:app apps/${myapp} --bundler=webpack --unitTestRunner=vitest` + ); + runCLI( + `generate @nx/web:app apps/${myapp2} --bundler=webpack --unitTestRunner=vitest` + ); runCLI(`generate @nx/js:lib libs/${mylib}`); runCommand(`git add . && git commit -am "add all"`); } @@ -536,8 +540,12 @@ describe('show projects --affected', () => { const mylib2 = uniq('mylib2'); const mypublishablelib = uniq('mypublishablelib'); - runCLI(`generate @nx/web:app ${myapp} --directory=apps/${myapp}`); - runCLI(`generate @nx/web:app ${myapp2} --directory=apps/${myapp2}`); + runCLI( + `generate @nx/web:app ${myapp} --directory=apps/${myapp} --unitTestRunner=vitest` + ); + runCLI( + `generate @nx/web:app ${myapp2} --directory=apps/${myapp2} --unitTestRunner=vitest` + ); runCLI(`generate @nx/js:lib ${mylib} --directory=libs/${mylib}`); runCLI(`generate @nx/js:lib ${mylib2} --directory=libs/${mylib2}`); runCLI( diff --git a/e2e/nx/src/misc.test.ts b/e2e/nx/src/misc.test.ts index 34ce9fed33fc1..418e7e25dbe73 100644 --- a/e2e/nx/src/misc.test.ts +++ b/e2e/nx/src/misc.test.ts @@ -68,9 +68,11 @@ describe('Nx Commands', () => { it('should show detailed project info', () => { const app = uniq('myapp'); - runCLI(`generate @nx/web:app apps/${app}`); + runCLI( + `generate @nx/web:app apps/${app} --bundler=webpack --unitTestRunner=vitest --linter=eslint` + ); const project: ProjectConfiguration = JSON.parse( - runCLI(`show project ${app}`) + runCLI(`show project ${app} --json`) ); expect(project.targets.build).toBeDefined(); expect(project.targets.lint).toBeDefined(); diff --git a/e2e/nx/src/run.test.ts b/e2e/nx/src/run.test.ts index e71ee43661c7a..82f22dd4deb8a 100644 --- a/e2e/nx/src/run.test.ts +++ b/e2e/nx/src/run.test.ts @@ -695,8 +695,12 @@ describe('Nx Running Tests', () => { it('should run multiple targets', () => { const myapp1 = uniq('myapp'); const myapp2 = uniq('myapp'); - runCLI(`generate @nx/web:app ${myapp1} --directory=apps/${myapp1}`); - runCLI(`generate @nx/web:app ${myapp2} --directory=apps/${myapp2}`); + runCLI( + `generate @nx/web:app ${myapp1} --directory=apps/${myapp1} --unitTestRunner=vitest` + ); + runCLI( + `generate @nx/web:app ${myapp2} --directory=apps/${myapp2} --unitTestRunner=vitest` + ); let outputs = runCLI( // Options with lists can be specified using multiple args or with a delimiter (comma or space). diff --git a/packages/nx/src/utils/package-json.ts b/packages/nx/src/utils/package-json.ts index 8efdd742e3aed..a1c78d4925a7b 100644 --- a/packages/nx/src/utils/package-json.ts +++ b/packages/nx/src/utils/package-json.ts @@ -55,6 +55,7 @@ export interface PackageJson { require?: string; import?: string; development?: string; + default?: string; } >; dependencies?: Record; diff --git a/packages/react-native/src/generators/library/library.ts b/packages/react-native/src/generators/library/library.ts index 7c4c202aebcf9..a92e719ec376a 100644 --- a/packages/react-native/src/generators/library/library.ts +++ b/packages/react-native/src/generators/library/library.ts @@ -39,6 +39,7 @@ import { updateTsconfigFiles, } from '@nx/js/src/utils/typescript/ts-solution-setup'; import { getImportPath } from '@nx/js/src/utils/get-import-path'; +import type { PackageJson } from 'nx/src/utils/package-json'; export async function reactNativeLibraryGenerator( host: Tree, @@ -162,17 +163,15 @@ async function addProject( targets: {}, }; + const packageJsonPath = joinPathFragments( + options.projectRoot, + 'package.json' + ); if (options.isUsingTsSolutionConfig) { - const sourceEntry = !options.buildable - ? options.js - ? './src/index.js' - : './src/index.ts' - : undefined; - writeJson(host, joinPathFragments(options.projectRoot, 'package.json'), { + writeJson(host, packageJsonPath, { name: getImportPath(host, options.name), version: '0.0.1', - main: sourceEntry, - types: sourceEntry, + ...determineEntryFields(options), nx: { name: options.name, sourceRoot: joinPathFragments(options.projectRoot, 'src'), @@ -198,13 +197,24 @@ async function addProject( skipFormat: true, }); + updateJson(host, packageJsonPath, (json) => { + if (json.type === 'module') { + // The @nx/rollup:configuration generator can set the type to 'module' which would + // potentially break this library. + delete json.type; + } + return json; + }); + const external = ['react/jsx-runtime', 'react-native', 'react', 'react-dom']; project.targets.build = { executor: '@nx/rollup:rollup', outputs: ['{options.outputPath}'], options: { - outputPath: `dist/${options.projectRoot}`, + outputPath: options.isUsingTsSolutionConfig + ? `${options.projectRoot}/dist` + : `dist/${options.projectRoot}`, tsConfig: `${options.projectRoot}/tsconfig.lib.json`, project: `${options.projectRoot}/package.json`, entryFile: maybeJs(options, `${options.projectRoot}/src/index.ts`), @@ -293,4 +303,27 @@ function maybeJs(options: NormalizedSchema, path: string): string { : path; } +function determineEntryFields( + options: NormalizedSchema +): Pick { + if (options.buildable) { + return {}; + } + + 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', + }, + }; +} + export default reactNativeLibraryGenerator; diff --git a/packages/react/src/generators/library/lib/determine-entry-fields.ts b/packages/react/src/generators/library/lib/determine-entry-fields.ts new file mode 100644 index 0000000000000..611d64c374293 --- /dev/null +++ b/packages/react/src/generators/library/lib/determine-entry-fields.ts @@ -0,0 +1,25 @@ +import type { PackageJson } from 'nx/src/utils/package-json'; +import type { NormalizedSchema } from '../schema'; + +export function determineEntryFields( + options: NormalizedSchema +): Pick { + if (options.bundler !== 'none') { + return {}; + } + + 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', + }, + }; +} diff --git a/packages/react/src/generators/library/library.spec.ts b/packages/react/src/generators/library/library.spec.ts index 88082ffe8e588..ab4ad38f580d8 100644 --- a/packages/react/src/generators/library/library.spec.ts +++ b/packages/react/src/generators/library/library.spec.ts @@ -1144,6 +1144,14 @@ module.exports = withNx( expect(readJson(tree, 'mylib/package.json')).toMatchInlineSnapshot(` { + "exports": { + ".": { + "default": "./src/index.ts", + "import": "./src/index.ts", + "types": "./src/index.ts", + }, + "./package.json": "./package.json", + }, "main": "./src/index.ts", "name": "@proj/mylib", "nx": { @@ -1157,6 +1165,10 @@ module.exports = withNx( `); expect(readJson(tree, 'myjslib/package.json')).toMatchInlineSnapshot(` { + "exports": { + ".": "./src/index.js", + "./package.json": "./package.json", + }, "main": "./src/index.js", "name": "@proj/myjslib", "nx": { diff --git a/packages/react/src/generators/library/library.ts b/packages/react/src/generators/library/library.ts index 2456c0cc61f2e..5ee6d3c2aaf25 100644 --- a/packages/react/src/generators/library/library.ts +++ b/packages/react/src/generators/library/library.ts @@ -35,6 +35,7 @@ import { addProjectToTsSolutionWorkspace, updateTsconfigFiles, } from '@nx/js/src/utils/typescript/ts-solution-setup'; +import { determineEntryFields } from './lib/determine-entry-fields'; export async function libraryGenerator(host: Tree, schema: Schema) { return await libraryGeneratorInternal(host, { @@ -69,17 +70,10 @@ export async function libraryGeneratorInternal(host: Tree, schema: Schema) { tasks.push(initTask); if (options.isUsingTsSolutionConfig) { - const sourceEntry = - options.bundler === 'none' - ? options.js - ? './src/index.js' - : './src/index.ts' - : undefined; writeJson(host, `${options.projectRoot}/package.json`, { name: options.importPath, version: '0.0.1', - main: sourceEntry, - types: sourceEntry, + ...determineEntryFields(options), nx: { name: options.importPath === options.name ? undefined : options.name, projectType: 'library', diff --git a/packages/remix/src/generators/library/library.impl.spec.ts b/packages/remix/src/generators/library/library.impl.spec.ts index 61e1265aa13af..bebcebbea7b60 100644 --- a/packages/remix/src/generators/library/library.impl.spec.ts +++ b/packages/remix/src/generators/library/library.impl.spec.ts @@ -167,6 +167,14 @@ describe('Remix Library Generator', () => { expect(readJson(tree, 'packages/foo/package.json')) .toMatchInlineSnapshot(` { + "exports": { + ".": { + "default": "./src/index.ts", + "import": "./src/index.ts", + "types": "./src/index.ts", + }, + "./package.json": "./package.json", + }, "main": "./src/index.ts", "name": "@proj/foo", "nx": { diff --git a/packages/rollup/src/plugins/with-nx/with-nx.ts b/packages/rollup/src/plugins/with-nx/with-nx.ts index 4a642efe7e19b..ce9a24831b60f 100644 --- a/packages/rollup/src/plugins/with-nx/with-nx.ts +++ b/packages/rollup/src/plugins/with-nx/with-nx.ts @@ -265,7 +265,7 @@ export function withNx( commonjs(), analyze(), options.generatePackageJson && generatePackageJson(options, packageJson), - ]; + ].filter(Boolean); if (Array.isArray(rollupConfig.plugins)) { finalConfig.plugins.push(...rollupConfig.plugins); } diff --git a/packages/vue/src/generators/library/lib/determine-entry-fields.ts b/packages/vue/src/generators/library/lib/determine-entry-fields.ts new file mode 100644 index 0000000000000..3aca21289f542 --- /dev/null +++ b/packages/vue/src/generators/library/lib/determine-entry-fields.ts @@ -0,0 +1,28 @@ +import type { PackageJson } from 'nx/src/utils/package-json'; +import type { NormalizedSchema } from '../schema'; + +export function determineEntryFields( + options: NormalizedSchema +): Pick { + if (options.bundler === 'none') { + return { + module: 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 { + module: './dist/index.mjs', + types: './dist/index.d.ts', + }; +} diff --git a/packages/vue/src/generators/library/library.ts b/packages/vue/src/generators/library/library.ts index 9555def605df9..de3386677ee99 100644 --- a/packages/vue/src/generators/library/library.ts +++ b/packages/vue/src/generators/library/library.ts @@ -4,12 +4,10 @@ import { GeneratorCallback, installPackagesTask, joinPathFragments, - readNxJson, runTasksInSerial, toJS, Tree, updateJson, - updateNxJson, writeJson, } from '@nx/devkit'; import { addTsConfigPath, initGenerator as jsInitGenerator } from '@nx/js'; @@ -30,6 +28,7 @@ import { addProjectToTsSolutionWorkspace, updateTsconfigFiles, } from '@nx/js/src/utils/typescript/ts-solution-setup'; +import { determineEntryFields } from './lib/determine-entry-fields'; export function libraryGenerator(tree: Tree, schema: Schema) { return libraryGeneratorInternal(tree, { addPlugin: false, ...schema }); @@ -48,28 +47,15 @@ export async function libraryGeneratorInternal(tree: Tree, schema: Schema) { } if (options.isUsingTsSolutionConfig) { - const moduleFile = - options.bundler === 'none' - ? options.js - ? './src/index.js' - : './src/index.ts' - : './dist/index.mjs'; - const typesFile = - options.bundler === 'none' - ? options.js - ? './src/index.js' - : './src/index.ts' - : './dist/index.d.ts'; writeJson(tree, joinPathFragments(options.projectRoot, 'package.json'), { name: getImportPath(tree, options.name), version: '0.0.1', private: true, - module: moduleFile, - types: typesFile, + ...determineEntryFields(options), files: options.publishable ? ['dist', '!**/*.tsbuildinfo'] : undefined, nx: { name: options.name, - projectType: 'application', + projectType: 'library', sourceRoot: `${options.projectRoot}/src`, tags: options.parsedTags?.length ? options.parsedTags : undefined, },