diff --git a/packages/create-nx-workspace/bin/create-nx-workspace.ts b/packages/create-nx-workspace/bin/create-nx-workspace.ts index 35fcca90360716..833747198b21dd 100644 --- a/packages/create-nx-workspace/bin/create-nx-workspace.ts +++ b/packages/create-nx-workspace/bin/create-nx-workspace.ts @@ -224,6 +224,8 @@ async function normalizeArgsMiddleware( preset = Preset.AngularStandalone; } else if (monorepoStyle === 'node-standalone') { preset = Preset.NodeStandalone; + } else if (monorepoStyle === 'ts-standalone') { + preset = Preset.TsStandalone; } else { // when choose integrated monorepo, further prompt for preset preset = await determinePreset(argv); @@ -269,6 +271,9 @@ async function normalizeArgsMiddleware( argv.routing ?? (argv.interactive ? await determineRouting(argv) : true); } + } else if (preset === Preset.TsStandalone) { + name = await determinePackageName(preset, argv); + appName = name; } else { name = await determineRepoName(argv); appName = await determineAppName(preset as Preset, argv); @@ -402,6 +407,11 @@ async function determineMonorepoStyle(): Promise { message: 'Standalone Node app: Nx configures a framework (e.g. Express), esbuild, ESlint and Jest.', }, + { + name: 'ts-standalone', + message: + 'Standalone TS/JS package: Nx configures a TypeScript/JavaScript package suitable for publishing to npm.', + }, ], }, ]); @@ -482,6 +492,34 @@ async function determineAppName( }); } +async function determinePackageName( + preset: Preset, + parsedArgs: yargs.Arguments +): Promise { + if (parsedArgs.name) { + return Promise.resolve(parsedArgs.name); + } + + return enquirer + .prompt<{ PackageName: string }>([ + { + name: 'PackageName', + message: `Package name `, + type: 'input', + }, + ]) + .then((a) => { + if (!a.PackageName) { + output.error({ + title: 'Invalid name', + bodyLines: [`Name cannot be empty`], + }); + process.exit(1); + } + return a.PackageName; + }); +} + async function determineFramework( parsedArgs: yargs.Arguments ): Promise { @@ -671,7 +709,8 @@ async function determineStyle( preset === Preset.Express || preset === Preset.ReactNative || preset === Preset.Expo || - preset === Preset.NodeStandalone + preset === Preset.NodeStandalone || + preset === Preset.TsStandalone ) { return Promise.resolve(null); } diff --git a/packages/create-nx-workspace/src/utils/preset/preset.ts b/packages/create-nx-workspace/src/utils/preset/preset.ts index 554d3742748361..edaff5d60479d4 100644 --- a/packages/create-nx-workspace/src/utils/preset/preset.ts +++ b/packages/create-nx-workspace/src/utils/preset/preset.ts @@ -18,6 +18,7 @@ export enum Preset { React = 'react', Angular = 'angular', NodeStandalone = 'node-standalone', + TsStandalone = 'ts-standalone', } /** diff --git a/packages/js/src/generators/library/files/lib/tsconfig.json__tmpl__ b/packages/js/src/generators/library/files/lib/tsconfig.json__tmpl__ deleted file mode 100644 index 8d27bd10719eba..00000000000000 --- a/packages/js/src/generators/library/files/lib/tsconfig.json__tmpl__ +++ /dev/null @@ -1,14 +0,0 @@ -{ - "extends": "<%= rootTsConfigPath %>", - "compilerOptions": { - "module": "commonjs"<% if (js) { %>, - "allowJs": true<% } %> - }, - "files": [], - "include": [], - "references": [ - { - "path": "./tsconfig.lib.json" - } - ] -} diff --git a/packages/js/src/generators/library/library.ts b/packages/js/src/generators/library/library.ts index f846fa7ebbdd4b..7ec329862a49c9 100644 --- a/packages/js/src/generators/library/library.ts +++ b/packages/js/src/generators/library/library.ts @@ -36,6 +36,7 @@ import { } from '../../utils/versions'; import jsInitGenerator from '../init/init'; import { PackageJson } from 'nx/src/utils/package-json'; +import { tsConfigBaseOptions } from '../../utils/typescript/create-ts-config'; export async function libraryGenerator( tree: Tree, @@ -62,6 +63,7 @@ export async function projectGenerator( await jsInitGenerator(tree, { ...schema, skipFormat: true, + tsConfigName: schema.rootProject ? 'tsconfig.json' : 'tsconfig.base.json', }) ); const options = normalizeOptions(tree, schema, destinationDir); @@ -270,6 +272,9 @@ function addBabelRc(tree: Tree, options: NormalizedSchema) { function createFiles(tree: Tree, options: NormalizedSchema, filesDir: string) { const { className, name, propertyName } = names(options.name); + + createProjectTsConfigJson(tree, options); + generateFiles(tree, filesDir, options.projectRoot, { ...options, dot: '.', @@ -281,7 +286,6 @@ function createFiles(tree: Tree, options: NormalizedSchema, filesDir: string) { strict: undefined, tmpl: '', offsetFromRoot: offsetFromRoot(options.projectRoot), - rootTsConfigPath: getRelativePathToRootTsConfig(tree, options.projectRoot), buildable: options.bundler && options.bundler !== 'none', hasUnitTestRunner: options.unitTestRunner !== 'none', }); @@ -590,5 +594,30 @@ function getOutputPath(options: NormalizedSchema, destinationDir?: string) { return joinPathFragments(...parts); } +function createProjectTsConfigJson(tree: Tree, options: NormalizedSchema) { + const tsconfig = { + extends: options.rootProject + ? undefined + : getRelativePathToRootTsConfig(tree, options.projectRoot), + compilerOptions: { + ...tsConfigBaseOptions, + module: 'commonjs', + allowJs: options.js ? true : undefined, + }, + files: [], + include: [], + references: [ + { + path: './tsconfig.lib.json', + }, + ], + }; + writeJson( + tree, + joinPathFragments(options.projectRoot, 'tsconfig.json'), + tsconfig + ); +} + export default libraryGenerator; export const librarySchematic = convertNxGenerator(libraryGenerator); diff --git a/packages/workspace/src/generators/new/__snapshots__/generate-workspace-files.spec.ts.snap b/packages/workspace/src/generators/new/__snapshots__/generate-workspace-files.spec.ts.snap index 97464c3467d2a2..f31019c061d67c 100644 --- a/packages/workspace/src/generators/new/__snapshots__/generate-workspace-files.spec.ts.snap +++ b/packages/workspace/src/generators/new/__snapshots__/generate-workspace-files.spec.ts.snap @@ -372,6 +372,27 @@ Visit the [Nx Documentation](https://nx.dev) to learn more. " `; +exports[`@nx/workspace:generateWorkspaceFiles README.md should be created for TsStandalone preset 1`] = ` +"# Proj + + + +✨ **This workspace has been generated by [Nx, a Smart, fast and extensible build system.](https://nx.dev)** ✨ + +## Understand this workspace + +Run \`nx graph\` to see a diagram of the dependencies of the projects. + +## Remote caching + +Run \`npx nx connect-to-nx-cloud\` to enable [remote caching](https://nx.app) and make CI faster. + +## Further help + +Visit the [Nx Documentation](https://nx.dev) to learn more. +" +`; + exports[`@nx/workspace:generateWorkspaceFiles README.md should be created for WebComponents preset 1`] = ` "# Proj diff --git a/packages/workspace/src/generators/new/files-readme/README.md.template b/packages/workspace/src/generators/new/files-readme/README.md.template index e3e1dfd17166e4..44227e955ec2e0 100644 --- a/packages/workspace/src/generators/new/files-readme/README.md.template +++ b/packages/workspace/src/generators/new/files-readme/README.md.template @@ -3,11 +3,11 @@ ✨ **This workspace has been generated by [Nx, a Smart, fast and extensible build system.](https://nx.dev)** ✨<% if (!!appName) { %> - +<% if (includeServe) { %> ## Development server Run `nx serve <%= appName %>` for a dev server. Navigate to http://localhost:4200/. The app will automatically reload if you change any of the source files.<% } %> - +<% } %> ## Understand this workspace Run `nx graph` to see a diagram of the dependencies of the projects. diff --git a/packages/workspace/src/generators/new/generate-preset.ts b/packages/workspace/src/generators/new/generate-preset.ts index c9f03d8f8d8ec2..c1fba014748691 100644 --- a/packages/workspace/src/generators/new/generate-preset.ts +++ b/packages/workspace/src/generators/new/generate-preset.ts @@ -98,6 +98,7 @@ function getPresetDependencies({ }: NormalizedSchema) { switch (preset) { case Preset.TS: + case Preset.TsStandalone: return { dependencies: {}, dev: { '@nx/js': nxVersion } }; case Preset.AngularMonorepo: diff --git a/packages/workspace/src/generators/new/generate-workspace-files.spec.ts b/packages/workspace/src/generators/new/generate-workspace-files.spec.ts index 52eddbec50a4f1..0a0931bd303ecb 100644 --- a/packages/workspace/src/generators/new/generate-workspace-files.spec.ts +++ b/packages/workspace/src/generators/new/generate-workspace-files.spec.ts @@ -42,6 +42,7 @@ describe('@nx/workspace:generateWorkspaceFiles', () => { Preset.Express, Preset.NodeStandalone, Preset.NextJsStandalone, + Preset.TsStandalone, ].includes(Preset[preset]) ) { appName = 'app1'; diff --git a/packages/workspace/src/generators/new/generate-workspace-files.ts b/packages/workspace/src/generators/new/generate-workspace-files.ts index 3a2a319dd64e49..8cd89ed85b1c35 100644 --- a/packages/workspace/src/generators/new/generate-workspace-files.ts +++ b/packages/workspace/src/generators/new/generate-workspace-files.ts @@ -67,6 +67,7 @@ function createAppsAndLibsFolders(tree: Tree, options: NormalizedSchema) { options.preset === Preset.ReactStandalone || options.preset === Preset.NodeStandalone || options.preset === Preset.NextJsStandalone || + options.preset === Preset.TsStandalone || options.isCustomPreset ) { // don't generate any folders @@ -126,7 +127,8 @@ function createFiles(tree: Tree, options: NormalizedSchema) { options.preset === Preset.AngularStandalone || options.preset === Preset.ReactStandalone || options.preset === Preset.NodeStandalone || - options.preset === Preset.NextJsStandalone + options.preset === Preset.NextJsStandalone || + options.preset === Preset.TsStandalone ? './files-root-app' : options.preset === Preset.NPM || options.preset === Preset.Core ? './files-package-based-repo' @@ -145,11 +147,12 @@ function createFiles(tree: Tree, options: NormalizedSchema) { function createReadme( tree: Tree, - { name, appName, directory }: NormalizedSchema + { name, appName, directory, preset }: NormalizedSchema ) { const formattedNames = names(name); generateFiles(tree, join(__dirname, './files-readme'), directory, { formattedNames, + includeServe: preset !== Preset.TsStandalone, appName, name, }); @@ -189,6 +192,15 @@ function addNpmScripts(tree: Tree, options: NormalizedSchema) { return json; }); } + if (options.preset === Preset.TsStandalone) { + updateJson(tree, join(options.directory, 'package.json'), (json) => { + Object.assign(json.scripts, { + build: 'nx build', + test: 'nx test', + }); + return json; + }); + } } function addPropertyWithStableKeys(obj: any, key: string, value: string) { diff --git a/packages/workspace/src/generators/preset/preset.ts b/packages/workspace/src/generators/preset/preset.ts index f61c0e85c21525..dac39ca0ff9838 100644 --- a/packages/workspace/src/generators/preset/preset.ts +++ b/packages/workspace/src/generators/preset/preset.ts @@ -147,6 +147,17 @@ async function createPreset(tree: Tree, options: Schema) { }; updateNxJson(tree, c); return initGenerator(tree, {}); + } else if (options.preset === Preset.TsStandalone) { + const c = readNxJson(tree); + const { libraryGenerator } = require('@nx' + '/js'); + updateNxJson(tree, c); + return libraryGenerator(tree, { + name: options.name, + bundler: 'swc', + unitTestRunner: 'jest', + testEnvironment: 'node', + rootProject: true, + }); } else if (options.preset === Preset.NodeStandalone) { const { applicationGenerator: nodeApplicationGenerator } = require('@nx' + '/node'); diff --git a/packages/workspace/src/generators/utils/presets.ts b/packages/workspace/src/generators/utils/presets.ts index 2874fa5b506a56..9ed7ea035f24a6 100644 --- a/packages/workspace/src/generators/utils/presets.ts +++ b/packages/workspace/src/generators/utils/presets.ts @@ -16,4 +16,5 @@ export enum Preset { Nest = 'nest', Express = 'express', NodeStandalone = 'node-standalone', + TsStandalone = 'ts-standalone', }