diff --git a/docs/generated/cli/create-nx-workspace.md b/docs/generated/cli/create-nx-workspace.md index f27ab4e262..cdb36e2fee 100644 --- a/docs/generated/cli/create-nx-workspace.md +++ b/docs/generated/cli/create-nx-workspace.md @@ -113,7 +113,7 @@ Package manager to use Type: `string` -Customizes the initial content of your workspace. Default presets include: ["apps", "empty", "core", "npm", "ts", "web-components", "angular", "angular-nest", "react", "react-express", "react-native", "expo", "next", "nest", "express"]. To build your own see https://nx.dev/packages/nx-plugin#preset +Customizes the initial content of your workspace. Default presets include: ["apps", "empty", "core", "npm", "ts", "web-components", "angular", "angular-nest", "react", "react-experimental", "react-express", "react-native", "expo", "next", "nest", "express"]. To build your own see https://nx.dev/packages/nx-plugin#preset ### skipGit diff --git a/docs/generated/packages/cypress.json b/docs/generated/packages/cypress.json index 69c9b5c26d..b9cc223a5c 100644 --- a/docs/generated/packages/cypress.json +++ b/docs/generated/packages/cypress.json @@ -111,6 +111,12 @@ "type": "boolean", "default": false, "description": "Do not add dependencies to `package.json`." + }, + "rootProject": { + "description": "Create a application at the root of the workspace", + "type": "boolean", + "default": false, + "hidden": true } }, "required": ["name"], diff --git a/docs/generated/packages/nx.json b/docs/generated/packages/nx.json index d6a19bc0ac..ea7388a21b 100644 --- a/docs/generated/packages/nx.json +++ b/docs/generated/packages/nx.json @@ -10,7 +10,7 @@ "name": "create-nx-workspace", "id": "create-nx-workspace", "file": "generated/cli/create-nx-workspace", - "content": "---\ntitle: 'create-nx-workspace - CLI command'\ndescription: 'Create a new Nx workspace'\n---\n\n# create-nx-workspace\n\nCreate a new Nx workspace\n\n## Usage\n\n```bash\ncreate-nx-workspace [name] [options]\n```\n\nInstall `create-nx-workspace` globally to invoke the command directly, or use `npx create-nx-workspace`, `yarn create nx-workspace`, or `pnpx create-nx-workspace`.\n\n## Options\n\n### allPrompts\n\nType: `boolean`\n\nDefault: `false`\n\nShow all prompts\n\n### appName\n\nType: `string`\n\nThe name of the application when a preset with pregenerated app is selected\n\n### ci\n\nType: `string`\n\nChoices: [github, circleci, azure]\n\nGenerate a CI workflow file\n\n### cli\n\nType: `string`\n\nChoices: [nx, angular]\n\nCLI to power the Nx workspace\n\n### commit.email\n\nType: `string`\n\nE-mail of the committer\n\n### commit.message\n\nType: `string`\n\nDefault: `Initial commit`\n\nCommit message\n\n### commit.name\n\nType: `string`\n\nName of the committer\n\n### defaultBase\n\nType: `string`\n\nDefault: `main`\n\nDefault base to use for new projects\n\n### help\n\nType: `boolean`\n\nShow help\n\n### interactive\n\nType: `boolean`\n\nEnable interactive mode with presets\n\n### name\n\nType: `string`\n\nWorkspace name (e.g. org name)\n\n### nxCloud\n\nType: `boolean`\n\nEnable distributed caching to make your CI faster\n\n### packageManager\n\nType: `string`\n\nChoices: [npm, pnpm, yarn]\n\nDefault: `npm`\n\nPackage manager to use\n\n### preset\n\nType: `string`\n\nCustomizes the initial content of your workspace. Default presets include: [\"apps\", \"empty\", \"core\", \"npm\", \"ts\", \"web-components\", \"angular\", \"angular-nest\", \"react\", \"react-express\", \"react-native\", \"expo\", \"next\", \"nest\", \"express\"]. To build your own see https://nx.dev/packages/nx-plugin#preset\n\n### skipGit\n\nType: `boolean`\n\nDefault: `false`\n\nSkip initializing a git repository.\n\n### style\n\nType: `string`\n\nStyle option to be used when a preset with pregenerated app is selected\n\n### version\n\nType: `boolean`\n\nShow version number\n" + "content": "---\ntitle: 'create-nx-workspace - CLI command'\ndescription: 'Create a new Nx workspace'\n---\n\n# create-nx-workspace\n\nCreate a new Nx workspace\n\n## Usage\n\n```bash\ncreate-nx-workspace [name] [options]\n```\n\nInstall `create-nx-workspace` globally to invoke the command directly, or use `npx create-nx-workspace`, `yarn create nx-workspace`, or `pnpx create-nx-workspace`.\n\n## Options\n\n### allPrompts\n\nType: `boolean`\n\nDefault: `false`\n\nShow all prompts\n\n### appName\n\nType: `string`\n\nThe name of the application when a preset with pregenerated app is selected\n\n### ci\n\nType: `string`\n\nChoices: [github, circleci, azure]\n\nGenerate a CI workflow file\n\n### cli\n\nType: `string`\n\nChoices: [nx, angular]\n\nCLI to power the Nx workspace\n\n### commit.email\n\nType: `string`\n\nE-mail of the committer\n\n### commit.message\n\nType: `string`\n\nDefault: `Initial commit`\n\nCommit message\n\n### commit.name\n\nType: `string`\n\nName of the committer\n\n### defaultBase\n\nType: `string`\n\nDefault: `main`\n\nDefault base to use for new projects\n\n### help\n\nType: `boolean`\n\nShow help\n\n### interactive\n\nType: `boolean`\n\nEnable interactive mode with presets\n\n### name\n\nType: `string`\n\nWorkspace name (e.g. org name)\n\n### nxCloud\n\nType: `boolean`\n\nEnable distributed caching to make your CI faster\n\n### packageManager\n\nType: `string`\n\nChoices: [npm, pnpm, yarn]\n\nDefault: `npm`\n\nPackage manager to use\n\n### preset\n\nType: `string`\n\nCustomizes the initial content of your workspace. Default presets include: [\"apps\", \"empty\", \"core\", \"npm\", \"ts\", \"web-components\", \"angular\", \"angular-nest\", \"react\", \"react-experimental\", \"react-express\", \"react-native\", \"expo\", \"next\", \"nest\", \"express\"]. To build your own see https://nx.dev/packages/nx-plugin#preset\n\n### skipGit\n\nType: `boolean`\n\nDefault: `false`\n\nSkip initializing a git repository.\n\n### style\n\nType: `string`\n\nStyle option to be used when a preset with pregenerated app is selected\n\n### version\n\nType: `boolean`\n\nShow version number\n" }, { "name": "init", diff --git a/docs/generated/packages/react.json b/docs/generated/packages/react.json index 83b1d991b8..e113d68667 100644 --- a/docs/generated/packages/react.json +++ b/docs/generated/packages/react.json @@ -141,7 +141,7 @@ "linter": { "description": "The tool to use for running lint checks.", "type": "string", - "enum": ["eslint"], + "enum": ["eslint", "none"], "default": "eslint" }, "routing": { @@ -228,6 +228,12 @@ "description": "Do not add dependencies to `package.json`.", "type": "boolean", "default": false + }, + "rootProject": { + "description": "Create a application at the root of the workspace", + "type": "boolean", + "default": false, + "hidden": true } }, "required": [], @@ -314,7 +320,7 @@ "linter": { "description": "The tool to use for running lint checks.", "type": "string", - "enum": ["eslint"], + "enum": ["eslint", "none"], "default": "eslint" }, "unitTestRunner": { diff --git a/e2e/workspace-create/src/create-nx-workspace.test.ts b/e2e/workspace-create/src/create-nx-workspace.test.ts index 30155ef33c..6b901ae744 100644 --- a/e2e/workspace-create/src/create-nx-workspace.test.ts +++ b/e2e/workspace-create/src/create-nx-workspace.test.ts @@ -21,6 +21,20 @@ describe('create-nx-workspace', () => { afterEach(() => cleanupProject()); + it('should create a workspace with a single react app', () => { + const wsName = uniq('react'); + const appName = uniq('app'); + + runCreateWorkspace(wsName, { + preset: 'react-experimental', + appName, + style: 'css', + packageManager, + }); + + checkFilesExist('package.json'); + }); + it('should be able to create an empty workspace built for apps', () => { const wsName = uniq('apps'); runCreateWorkspace(wsName, { diff --git a/packages/create-nx-workspace/bin/create-nx-workspace.ts b/packages/create-nx-workspace/bin/create-nx-workspace.ts index 80a9f24e89..4ccb4d457a 100644 --- a/packages/create-nx-workspace/bin/create-nx-workspace.ts +++ b/packages/create-nx-workspace/bin/create-nx-workspace.ts @@ -54,6 +54,7 @@ enum Preset { Angular = 'angular', AngularWithNest = 'angular-nest', React = 'react', + ReactExperimental = 'react-experimental', ReactWithExpress = 'react-express', ReactNative = 'react-native', Expo = 'expo', @@ -674,7 +675,14 @@ async function determineStyle( }); } - if ([Preset.ReactWithExpress, Preset.React, Preset.NextJs].includes(preset)) { + if ( + [ + Preset.ReactWithExpress, + Preset.React, + Preset.ReactExperimental, + Preset.NextJs, + ].includes(preset) + ) { choices.push( { name: 'styled-components', @@ -1030,6 +1038,7 @@ function pointToTutorialAndCourse(preset: Preset) { break; case Preset.React: + case Preset.ReactExperimental: case Preset.ReactWithExpress: case Preset.NextJs: output.addVerticalSeparator(); diff --git a/packages/cypress/src/generators/cypress-project/cypress-project.ts b/packages/cypress/src/generators/cypress-project/cypress-project.ts index 86eaa3f8a1..a73d713d80 100644 --- a/packages/cypress/src/generators/cypress-project/cypress-project.ts +++ b/packages/cypress/src/generators/cypress-project/cypress-project.ts @@ -268,16 +268,23 @@ export async function cypressProjectGenerator(host: Tree, schema: Schema) { function normalizeOptions(host: Tree, options: Schema): CypressProjectSchema { const { appsDir } = getWorkspaceLayout(host); - const projectName = filePathPrefix( - options.directory ? `${options.directory}-${options.name}` : options.name - ); - const projectRoot = options.directory - ? joinPathFragments( - appsDir, - names(options.directory).fileName, - options.name - ) - : joinPathFragments(appsDir, options.name); + let projectName, projectRoot; + + if (options.rootProject) { + projectName = options.name; + projectRoot = options.name; + } else { + projectName = filePathPrefix( + options.directory ? `${options.directory}-${options.name}` : options.name + ); + projectRoot = options.directory + ? joinPathFragments( + appsDir, + names(options.directory).fileName, + options.name + ) + : joinPathFragments(appsDir, options.name); + } options.linter = options.linter || Linter.EsLint; return { diff --git a/packages/cypress/src/generators/cypress-project/schema.d.ts b/packages/cypress/src/generators/cypress-project/schema.d.ts index 512efdd931..83038d479e 100644 --- a/packages/cypress/src/generators/cypress-project/schema.d.ts +++ b/packages/cypress/src/generators/cypress-project/schema.d.ts @@ -11,4 +11,5 @@ export interface Schema { setParserOptionsProject?: boolean; standaloneConfig?: boolean; skipPackageJson?: boolean; + rootProject?: boolean; } diff --git a/packages/cypress/src/generators/cypress-project/schema.json b/packages/cypress/src/generators/cypress-project/schema.json index 18ede4e4bd..0888c92ab5 100644 --- a/packages/cypress/src/generators/cypress-project/schema.json +++ b/packages/cypress/src/generators/cypress-project/schema.json @@ -59,6 +59,12 @@ "type": "boolean", "default": false, "description": "Do not add dependencies to `package.json`." + }, + "rootProject": { + "description": "Create a application at the root of the workspace", + "type": "boolean", + "default": false, + "hidden": true } }, "required": ["name"], diff --git a/packages/devkit/src/utils/offset-from-root.spec.ts b/packages/devkit/src/utils/offset-from-root.spec.ts index 15b27b4ad4..b578723204 100644 --- a/packages/devkit/src/utils/offset-from-root.spec.ts +++ b/packages/devkit/src/utils/offset-from-root.spec.ts @@ -20,4 +20,9 @@ describe('offsetFromRoot', () => { const result = offsetFromRoot('apps/dirname/appname/'); expect(result).toBe('../../../'); }); + + it('should work for root', () => { + const result = offsetFromRoot('.'); + expect(result).toBe('./'); + }); }); diff --git a/packages/devkit/src/utils/offset-from-root.ts b/packages/devkit/src/utils/offset-from-root.ts index 3d7dfc0a12..665971434b 100644 --- a/packages/devkit/src/utils/offset-from-root.ts +++ b/packages/devkit/src/utils/offset-from-root.ts @@ -13,6 +13,8 @@ import { normalize, sep } from 'path'; * @param fullPathToDir - directory path */ export function offsetFromRoot(fullPathToDir: string): string { + if (fullPathToDir === '.') return './'; + const parts = normalize(fullPathToDir).split(sep); let offset = ''; for (let i = 0; i < parts.length; ++i) { diff --git a/packages/react/src/generators/application/application.spec.ts b/packages/react/src/generators/application/application.spec.ts index b7b70a5bf2..aad4b2a699 100644 --- a/packages/react/src/generators/application/application.spec.ts +++ b/packages/react/src/generators/application/application.spec.ts @@ -825,4 +825,23 @@ describe('app', () => { }); }); }); + + describe('--root-project', () => { + it('should create files at the root', async () => { + await applicationGenerator(appTree, { + ...schema, + rootProject: true, + }); + expect(appTree.read('/src/main.tsx')).toBeDefined(); + expect(appTree.read('/e2e/cypress.config.ts')).toBeDefined(); + expect(readJson(appTree, '/tsconfig.json').extends).toEqual( + './tsconfig.base.json' + ); + expect( + readJson(appTree, '/workspace.json').projects['my-app'].architect[ + 'build' + ].options['outputPath'] + ).toEqual('dist/my-app'); + }); + }); }); diff --git a/packages/react/src/generators/application/application.ts b/packages/react/src/generators/application/application.ts index cac103cf85..d1db68915d 100644 --- a/packages/react/src/generators/application/application.ts +++ b/packages/react/src/generators/application/application.ts @@ -23,47 +23,48 @@ import { } from '@nrwl/devkit'; import { runTasksInSerial } from '@nrwl/workspace/src/utilities/run-tasks-in-serial'; import reactInitGenerator from '../init/init'; -import { lintProjectGenerator } from '@nrwl/linter'; +import { Linter, lintProjectGenerator } from '@nrwl/linter'; import { swcCoreVersion } from '@nrwl/js/src/utils/versions'; import { swcLoaderVersion } from '@nrwl/webpack/src/utils/versions'; async function addLinting(host: Tree, options: NormalizedSchema) { const tasks: GeneratorCallback[] = []; - const lintTask = await lintProjectGenerator(host, { - linter: options.linter, - project: options.projectName, - tsConfigPaths: [ - joinPathFragments(options.appProjectRoot, 'tsconfig.app.json'), - ], - unitTestRunner: options.unitTestRunner, - eslintFilePatterns: [`${options.appProjectRoot}/**/*.{ts,tsx,js,jsx}`], - skipFormat: true, - }); - tasks.push(lintTask); + if (options.linter === Linter.EsLint) { + const lintTask = await lintProjectGenerator(host, { + linter: options.linter, + project: options.projectName, + tsConfigPaths: [ + joinPathFragments(options.appProjectRoot, 'tsconfig.app.json'), + ], + unitTestRunner: options.unitTestRunner, + eslintFilePatterns: [`${options.appProjectRoot}/**/*.{ts,tsx,js,jsx}`], + skipFormat: true, + }); + tasks.push(lintTask); - const reactEslintJson = createReactEslintJson( - options.appProjectRoot, - options.setParserOptionsProject - ); + const reactEslintJson = createReactEslintJson( + options.appProjectRoot, + options.setParserOptionsProject + ); - updateJson( - host, - joinPathFragments(options.appProjectRoot, '.eslintrc.json'), - () => reactEslintJson - ); - - const installTask = await addDependenciesToPackageJson( - host, - extraEslintDependencies.dependencies, - { - ...extraEslintDependencies.devDependencies, - ...(options.compiler === 'swc' - ? { '@swc/core': swcCoreVersion, 'swc-loader': swcLoaderVersion } - : {}), - } - ); - tasks.push(installTask); + updateJson( + host, + joinPathFragments(options.appProjectRoot, '.eslintrc.json'), + () => reactEslintJson + ); + const installTask = await addDependenciesToPackageJson( + host, + extraEslintDependencies.dependencies, + { + ...extraEslintDependencies.devDependencies, + ...(options.compiler === 'swc' + ? { '@swc/core': swcCoreVersion, 'swc-loader': swcLoaderVersion } + : {}), + } + ); + tasks.push(installTask); + } return runTasksInSerial(...tasks); } diff --git a/packages/react/src/generators/application/lib/add-cypress.ts b/packages/react/src/generators/application/lib/add-cypress.ts index bf1ebf574c..332ba3dc69 100644 --- a/packages/react/src/generators/application/lib/add-cypress.ts +++ b/packages/react/src/generators/application/lib/add-cypress.ts @@ -9,7 +9,7 @@ export async function addCypress(host: Tree, options: NormalizedSchema) { return await cypressProjectGenerator(host, { ...options, - name: `${options.name}-e2e`, + name: options.e2eProjectName, directory: options.directory, project: options.projectName, }); diff --git a/packages/react/src/generators/application/lib/add-project.ts b/packages/react/src/generators/application/lib/add-project.ts index c93658f01f..bd40852f80 100644 --- a/packages/react/src/generators/application/lib/add-project.ts +++ b/packages/react/src/generators/application/lib/add-project.ts @@ -41,7 +41,12 @@ function createBuildTarget(options: NormalizedSchema): TargetConfiguration { defaultConfiguration: 'production', options: { compiler: options.compiler ?? 'babel', - outputPath: joinPathFragments('dist', options.appProjectRoot), + outputPath: joinPathFragments( + 'dist', + options.appProjectRoot != '.' + ? options.appProjectRoot + : options.projectName + ), index: joinPathFragments(options.appProjectRoot, 'src/index.html'), baseHref: '/', main: joinPathFragments( diff --git a/packages/react/src/generators/application/lib/normalize-options.ts b/packages/react/src/generators/application/lib/normalize-options.ts index 734395ff2e..c87b551465 100644 --- a/packages/react/src/generators/application/lib/normalize-options.ts +++ b/packages/react/src/generators/application/lib/normalize-options.ts @@ -19,10 +19,14 @@ export function normalizeOptions( ): NormalizedSchema { const appDirectory = normalizeDirectory(options); const appProjectName = normalizeProjectName(options); - const e2eProjectName = `${appProjectName}-e2e`; + const e2eProjectName = options.rootProject + ? 'e2e' + : `${names(options.name).fileName}-e2e`; const { appsDir } = getWorkspaceLayout(host); - const appProjectRoot = normalizePath(`${appsDir}/${appDirectory}`); + const appProjectRoot = options.rootProject + ? '.' + : normalizePath(`${appsDir}/${appDirectory}`); const parsedTags = options.tags ? options.tags.split(',').map((s) => s.trim()) diff --git a/packages/react/src/generators/application/lib/set-defaults.ts b/packages/react/src/generators/application/lib/set-defaults.ts index bf20d8024b..435b9b1307 100644 --- a/packages/react/src/generators/application/lib/set-defaults.ts +++ b/packages/react/src/generators/application/lib/set-defaults.ts @@ -28,6 +28,7 @@ export function setDefaults(host: Tree, options: NormalizedSchema) { ...prev, application: { style: options.style, + unitTestRunner: options.unitTestRunner, linter: options.linter, ...prev.application, }, @@ -37,6 +38,7 @@ export function setDefaults(host: Tree, options: NormalizedSchema) { }, library: { style: options.style, + unitTestRunner: options.unitTestRunner, linter: options.linter, ...prev.library, }, diff --git a/packages/react/src/generators/application/schema.d.ts b/packages/react/src/generators/application/schema.d.ts index 06ee9868d9..ab5223771c 100644 --- a/packages/react/src/generators/application/schema.d.ts +++ b/packages/react/src/generators/application/schema.d.ts @@ -28,6 +28,7 @@ export interface Schema { devServerPort?: number; skipDefaultProject?: boolean; skipPackageJson?: boolean; + rootProject?: boolean; } export interface NormalizedSchema extends Schema { diff --git a/packages/react/src/generators/application/schema.json b/packages/react/src/generators/application/schema.json index 22a3546316..e34124b86b 100644 --- a/packages/react/src/generators/application/schema.json +++ b/packages/react/src/generators/application/schema.json @@ -82,7 +82,7 @@ "linter": { "description": "The tool to use for running lint checks.", "type": "string", - "enum": ["eslint"], + "enum": ["eslint", "none"], "default": "eslint" }, "routing": { @@ -169,6 +169,12 @@ "description": "Do not add dependencies to `package.json`.", "type": "boolean", "default": false + }, + "rootProject": { + "description": "Create a application at the root of the workspace", + "type": "boolean", + "default": false, + "hidden": true } }, "required": [] diff --git a/packages/react/src/generators/library/library.ts b/packages/react/src/generators/library/library.ts index dba3f37bed..07a0c77016 100644 --- a/packages/react/src/generators/library/library.ts +++ b/packages/react/src/generators/library/library.ts @@ -19,7 +19,7 @@ import { import { getImportPath } from 'nx/src/utils/path'; import { jestProjectGenerator } from '@nrwl/jest'; import { swcCoreVersion } from '@nrwl/js/src/utils/versions'; -import { lintProjectGenerator } from '@nrwl/linter'; +import { Linter, lintProjectGenerator } from '@nrwl/linter'; import { runTasksInSerial } from '@nrwl/workspace/src/utilities/run-tasks-in-serial'; import { getRelativePathToRootTsConfig, @@ -143,39 +143,43 @@ export async function libraryGenerator(host: Tree, schema: Schema) { } async function addLinting(host: Tree, options: NormalizedSchema) { - const lintTask = await lintProjectGenerator(host, { - linter: options.linter, - project: options.name, - tsConfigPaths: [ - joinPathFragments(options.projectRoot, 'tsconfig.lib.json'), - ], - unitTestRunner: options.unitTestRunner, - eslintFilePatterns: [`${options.projectRoot}/**/*.{ts,tsx,js,jsx}`], - skipFormat: true, - skipPackageJson: options.skipPackageJson, - }); + if (options.linter === Linter.EsLint) { + const lintTask = await lintProjectGenerator(host, { + linter: options.linter, + project: options.name, + tsConfigPaths: [ + joinPathFragments(options.projectRoot, 'tsconfig.lib.json'), + ], + unitTestRunner: options.unitTestRunner, + eslintFilePatterns: [`${options.projectRoot}/**/*.{ts,tsx,js,jsx}`], + skipFormat: true, + skipPackageJson: options.skipPackageJson, + }); - const reactEslintJson = createReactEslintJson( - options.projectRoot, - options.setParserOptionsProject - ); - - updateJson( - host, - joinPathFragments(options.projectRoot, '.eslintrc.json'), - () => reactEslintJson - ); - - let installTask = () => {}; - if (!options.skipPackageJson) { - installTask = await addDependenciesToPackageJson( - host, - extraEslintDependencies.dependencies, - extraEslintDependencies.devDependencies + const reactEslintJson = createReactEslintJson( + options.projectRoot, + options.setParserOptionsProject ); - } - return runTasksInSerial(lintTask, installTask); + updateJson( + host, + joinPathFragments(options.projectRoot, '.eslintrc.json'), + () => reactEslintJson + ); + + let installTask = () => {}; + if (!options.skipPackageJson) { + installTask = await addDependenciesToPackageJson( + host, + extraEslintDependencies.dependencies, + extraEslintDependencies.devDependencies + ); + } + + return runTasksInSerial(lintTask, installTask); + } else { + return () => {}; + } } function addProject(host: Tree, options: NormalizedSchema) { @@ -192,7 +196,7 @@ function addProject(host: Tree, options: NormalizedSchema) { } targets.build = { - builder: '@nrwl/web:rollup', + executor: '@nrwl/web:rollup', outputs: ['{options.outputPath}'], options: { outputPath: `dist/${libsDir}/${options.projectDirectory}`, diff --git a/packages/react/src/generators/library/schema.json b/packages/react/src/generators/library/schema.json index cf46172bea..c8c722bc3e 100644 --- a/packages/react/src/generators/library/schema.json +++ b/packages/react/src/generators/library/schema.json @@ -75,7 +75,7 @@ "linter": { "description": "The tool to use for running lint checks.", "type": "string", - "enum": ["eslint"], + "enum": ["eslint", "none"], "default": "eslint" }, "unitTestRunner": { diff --git a/packages/workspace/project.json b/packages/workspace/project.json index e2f69e4b08..33911c7d10 100644 --- a/packages/workspace/project.json +++ b/packages/workspace/project.json @@ -36,6 +36,11 @@ "glob": "**/files-npm/**", "output": "/" }, + { + "input": "packages/workspace", + "glob": "**/files-root-app/**", + "output": "/" + }, { "input": "packages/workspace", "glob": "**/files-npm/**/.gitkeep", diff --git a/packages/workspace/src/generators/new/new.ts b/packages/workspace/src/generators/new/new.ts index 3faa25bf9e..7de33577b4 100644 --- a/packages/workspace/src/generators/new/new.ts +++ b/packages/workspace/src/generators/new/new.ts @@ -194,6 +194,9 @@ function getPresetDependencies(preset: string, version?: string) { case Preset.React: return { dependencies: {}, dev: { '@nrwl/react': nxVersion } }; + case Preset.ReactExperimental: + return { dependencies: {}, dev: { '@nrwl/react': nxVersion } }; + case Preset.ReactWithExpress: return { dependencies: {}, diff --git a/packages/workspace/src/generators/preset/preset.ts b/packages/workspace/src/generators/preset/preset.ts index 82d5ac280f..0edab70466 100644 --- a/packages/workspace/src/generators/preset/preset.ts +++ b/packages/workspace/src/generators/preset/preset.ts @@ -56,6 +56,19 @@ async function createPreset(tree: Tree, options: Schema) { linter: options.linter, standaloneConfig: options.standaloneConfig, }); + } else if (options.preset === Preset.ReactExperimental) { + const { + applicationGenerator: reactApplicationGenerator, + } = require('@nrwl' + '/react'); + + await reactApplicationGenerator(tree, { + name: options.name, + style: options.style, + linter: 'none', + unitTestRunner: 'none', + standaloneConfig: options.standaloneConfig, + rootProject: true, + }); } else if (options.preset === Preset.NextJs) { const { applicationGenerator: nextApplicationGenerator } = require('@nrwl' + '/next'); diff --git a/packages/workspace/src/generators/utils/presets.ts b/packages/workspace/src/generators/utils/presets.ts index fef48bdb43..a9d0b9cc4f 100644 --- a/packages/workspace/src/generators/utils/presets.ts +++ b/packages/workspace/src/generators/utils/presets.ts @@ -8,6 +8,7 @@ export enum Preset { Angular = 'angular', AngularWithNest = 'angular-nest', React = 'react', + ReactExperimental = 'react-experimental', ReactWithExpress = 'react-express', ReactNative = 'react-native', Expo = 'expo', diff --git a/packages/workspace/src/generators/workspace/files-root-app/__dot__gitignore b/packages/workspace/src/generators/workspace/files-root-app/__dot__gitignore new file mode 100644 index 0000000000..51b9af5269 --- /dev/null +++ b/packages/workspace/src/generators/workspace/files-root-app/__dot__gitignore @@ -0,0 +1,39 @@ +# See http://help.github.com/ignore-files/ for more about ignoring files. + +# compiled output +dist +tmp +/out-tsc + +# dependencies +node_modules + +# IDEs and editors +/.idea +.project +.classpath +.c9/ +*.launch +.settings/ +*.sublime-workspace + +# IDE - VSCode +.vscode/* +!.vscode/settings.json +!.vscode/tasks.json +!.vscode/launch.json +!.vscode/extensions.json + +# misc +/.sass-cache +/connect.lock +/coverage +/libpeerconnection.log +npm-debug.log +yarn-error.log +testem.log +/typings + +# System Files +.DS_Store +Thumbs.db diff --git a/packages/workspace/src/generators/workspace/files-root-app/__dot__prettierignore b/packages/workspace/src/generators/workspace/files-root-app/__dot__prettierignore new file mode 100644 index 0000000000..d0b804da2a --- /dev/null +++ b/packages/workspace/src/generators/workspace/files-root-app/__dot__prettierignore @@ -0,0 +1,4 @@ +# Add files here to ignore them from prettier formatting + +/dist +/coverage diff --git a/packages/workspace/src/generators/workspace/files-root-app/__dot__vscode/extensions.json__tmpl__ b/packages/workspace/src/generators/workspace/files-root-app/__dot__vscode/extensions.json__tmpl__ new file mode 100644 index 0000000000..116b35fada --- /dev/null +++ b/packages/workspace/src/generators/workspace/files-root-app/__dot__vscode/extensions.json__tmpl__ @@ -0,0 +1,9 @@ +{ + "recommendations": [ + <% if(cli === 'angular') { %> + "angular.ng-template",<% } + %> + "nrwl.angular-console", + "esbenp.prettier-vscode" + ] +} diff --git a/packages/workspace/src/generators/workspace/files-root-app/package.json__tmpl__ b/packages/workspace/src/generators/workspace/files-root-app/package.json__tmpl__ new file mode 100644 index 0000000000..8f622e34de --- /dev/null +++ b/packages/workspace/src/generators/workspace/files-root-app/package.json__tmpl__ @@ -0,0 +1,17 @@ +{ + "name": "<%= formattedNames.fileName %>", + "version": "0.0.0", + "license": "MIT", + "scripts": { + }, + "private": true, + "dependencies": { + }, + "devDependencies": { + "nx": "<%= nxVersion %>", + "@nrwl/cli": "<%= nxVersion %>", + "@nrwl/workspace": "<%= nxVersion %>", + "typescript": "<%= typescriptVersion %>", + "prettier": "<%= prettierVersion %>" + } +} diff --git a/packages/workspace/src/generators/workspace/files-root-app/tsconfig.base.json b/packages/workspace/src/generators/workspace/files-root-app/tsconfig.base.json new file mode 100644 index 0000000000..11253ac5c2 --- /dev/null +++ b/packages/workspace/src/generators/workspace/files-root-app/tsconfig.base.json @@ -0,0 +1,20 @@ +{ + "compileOnSave": false, + "compilerOptions": { + "rootDir": ".", + "sourceMap": true, + "declaration": false, + "moduleResolution": "node", + "emitDecoratorMetadata": true, + "experimentalDecorators": true, + "importHelpers": true, + "target": "es2015", + "module": "esnext", + "lib": ["es2017", "dom"], + "skipLibCheck": true, + "skipDefaultLibCheck": true, + "baseUrl": ".", + "paths": {} + }, + "exclude": ["node_modules", "tmp"] +} diff --git a/packages/workspace/src/generators/workspace/workspace.ts b/packages/workspace/src/generators/workspace/workspace.ts index e19ff384a4..cb27f4e890 100644 --- a/packages/workspace/src/generators/workspace/workspace.ts +++ b/packages/workspace/src/generators/workspace/workspace.ts @@ -54,6 +54,8 @@ function createAppsAndLibsFolders(host: Tree, options: Schema) { options.preset === Preset.NPM ) { host.write(join(options.directory, 'packages/.gitkeep'), ''); + } else if (options.preset === Preset.ReactExperimental) { + // don't generate any folders } else { host.write(join(options.directory, 'apps/.gitkeep'), ''); host.write(join(options.directory, 'libs/.gitkeep'), ''); @@ -114,7 +116,9 @@ function createNxJson( function createFiles(host: Tree, options: Schema) { const formattedNames = names(options.name); const filesDirName = - options.preset === Preset.NPM || options.preset === Preset.Core + options.preset === Preset.ReactExperimental + ? './files-root-app' + : options.preset === Preset.NPM || options.preset === Preset.Core ? './files-npm' : './files'; generateFiles(host, pathJoin(__dirname, filesDirName), options.directory, {