Skip to content

Commit

Permalink
feat(angular): add a preset to generate a workspace with a single app…
Browse files Browse the repository at this point in the history
… at the root
  • Loading branch information
leosvelperez authored and vsavkin committed Nov 21, 2022
1 parent bc2f249 commit 70e43cd
Show file tree
Hide file tree
Showing 20 changed files with 103 additions and 45 deletions.
2 changes: 1 addition & 1 deletion docs/generated/cli/create-nx-workspace.md
Original file line number Diff line number Diff line change
Expand Up @@ -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", "react", "react-experimental", "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-experimental", "react", "react-experimental", "react-native", "expo", "next", "nest", "express"]. To build your own see https://nx.dev/packages/nx-plugin#preset

### skipGit

Expand Down
6 changes: 6 additions & 0 deletions docs/generated/packages/angular.json
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,12 @@
"description": "Generate an application that is setup to use standalone components.",
"type": "boolean",
"default": false
},
"rootProject": {
"description": "Create an application at the root of the workspace.",
"type": "boolean",
"default": false,
"hidden": true
}
},
"additionalProperties": false,
Expand Down
2 changes: 1 addition & 1 deletion docs/generated/packages/nx.json
Original file line number Diff line number Diff line change
Expand Up @@ -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\", \"react\", \"react-experimental\", \"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-experimental\", \"react\", \"react-experimental\", \"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",
Expand Down
22 changes: 17 additions & 5 deletions e2e/workspace-create/src/create-nx-workspace.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,8 @@ import {
expectNoTsJestInJestConfig,
getSelectedPackageManager,
packageManagerLockFile,
readJson,
runCLI,
runCreateWorkspace,
uniq,
updateFile,
updateJson,
} from '@nrwl/e2e/utils';
import { existsSync, mkdirSync } from 'fs-extra';

Expand All @@ -21,7 +17,22 @@ describe('create-nx-workspace', () => {

afterEach(() => cleanupProject());

it('should create a workspace with a single react app', () => {
it('should create a workspace with a single angular app at the root', () => {
const wsName = uniq('angular');
const appName = uniq('app');

runCreateWorkspace(wsName, {
preset: 'angular-experimental',
appName,
style: 'css',
packageManager,
});

checkFilesExist('package.json');
checkFilesExist('project.json');
});

it('should create a workspace with a single react app at the root', () => {
const wsName = uniq('react');
const appName = uniq('app');

Expand All @@ -33,6 +44,7 @@ describe('create-nx-workspace', () => {
});

checkFilesExist('package.json');
checkFilesExist('project.json');
});

it('should be able to create an empty workspace built for apps', () => {
Expand Down
18 changes: 18 additions & 0 deletions packages/angular/src/generators/application/application.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1056,6 +1056,24 @@ describe('app', () => {
"
`);
});

describe('--root-project', () => {
it('should create files at the root', async () => {
await generateApp(appTree, 'my-app', {
rootProject: true,
});

expect(appTree.exists('src/main.ts')).toBe(true);
expect(appTree.exists('src/app/app.module.ts')).toBe(true);
expect(appTree.exists('src/app/app.component.ts')).toBe(true);
expect(appTree.exists('e2e/cypress.config.ts')).toBe(true);
expect(readJson(appTree, 'tsconfig.json').extends).toEqual(
'./tsconfig.base.json'
);
const project = readProjectConfiguration(appTree, 'my-app');
expect(project.targets.build.options['outputPath']).toBe('dist/my-app');
});
});
});

async function generateApp(
Expand Down
1 change: 1 addition & 0 deletions packages/angular/src/generators/application/lib/add-e2e.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ export async function addE2e(tree: Tree, options: NormalizedSchema) {
skipFormat: options.skipFormat,
standaloneConfig: options.standaloneConfig,
skipPackageJson: options.skipPackageJson,
rootProject: options.rootProject,
});
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,5 @@
import {
getWorkspaceLayout,
joinPathFragments,
moveFilesToNewDirectory,
Tree,
} from '@nrwl/devkit';
import type { Tree } from '@nrwl/devkit';
import { joinPathFragments, moveFilesToNewDirectory } from '@nrwl/devkit';
import { wrapAngularDevkitSchematic } from '@nrwl/devkit/ngcli-adapter';
import type { NormalizedSchema } from './normalized-schema';

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,18 +20,19 @@ export function normalizeOptions(
host: Tree,
options: Partial<Schema>
): NormalizedSchema {
const { appsDir, npmScope, standaloneAsDefault } = getWorkspaceLayout(host);

const appDirectory = normalizeDirectory(options.name, options.directory);

let e2eProjectName = `${names(options.name).fileName}-e2e`;
const appProjectName = normalizeProjectName(options.name, options.directory);
if (options.e2eTestRunner !== 'cypress') {
e2eProjectName = `${appProjectName}-e2e`;
}
const e2eProjectName = options.rootProject
? 'e2e'
: `${names(options.name).fileName}-e2e`;

const appProjectRoot = joinPathFragments(appsDir, appDirectory);
const e2eProjectRoot = joinPathFragments(appsDir, `${appDirectory}-e2e`);
const { appsDir, npmScope, standaloneAsDefault } = getWorkspaceLayout(host);
const appProjectRoot = options.rootProject
? '.'
: joinPathFragments(appsDir, appDirectory);
const e2eProjectRoot = options.rootProject
? 'e2e'
: joinPathFragments(appsDir, `${appDirectory}-e2e`);

const parsedTags = options.tags
? options.tags.split(',').map((s) => s.trim())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import type { Tree } from '@nrwl/devkit';
import {
addProjectConfiguration,
getProjects,
joinPathFragments,
offsetFromRoot,
readProjectConfiguration,
removeProjectConfiguration,
Expand Down Expand Up @@ -73,6 +74,13 @@ function updateAppAndE2EProjectConfigurations(
executor,
outputs: ['{options.outputPath}'],
...rest,
options: {
...rest.options,
outputPath: joinPathFragments(
'dist',
!options.rootProject ? options.appProjectRoot : options.name
),
},
};

if (project.generators) {
Expand Down
1 change: 1 addition & 0 deletions packages/angular/src/generators/application/schema.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,4 +26,5 @@ export interface Schema {
skipPackageJson?: boolean;
skipDefaultProject?: boolean;
standalone?: boolean;
rootProject?: boolean;
}
6 changes: 6 additions & 0 deletions packages/angular/src/generators/application/schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,12 @@
"description": "Generate an application that is setup to use standalone components.",
"type": "boolean",
"default": false
},
"rootProject": {
"description": "Create an application at the root of the workspace.",
"type": "boolean",
"default": false,
"hidden": true
}
},
"additionalProperties": false,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import {
getWorkspaceLayout,
joinPathFragments,
offsetFromRoot,
Tree,
Expand All @@ -18,8 +17,7 @@ export function updateNgPackage(
const dest = joinPathFragments(
offsetFromRoot(options.projectRoot),
'dist',
getWorkspaceLayout(host).libsDir,
options.projectDirectory
options.projectRoot
);

updateJson(host, `${options.projectRoot}/ng-package.json`, (json) => {
Expand Down
14 changes: 3 additions & 11 deletions packages/angular/src/generators/library/lib/update-tsconfig.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,5 @@
import {
getWorkspaceLayout,
joinPathFragments,
Tree,
updateJson,
} from '@nrwl/devkit';
import type { Tree } from '@nrwl/devkit';
import { joinPathFragments, updateJson } from '@nrwl/devkit';
import { getRootTsConfigPathInTree } from '@nrwl/workspace/src/utilities/typescript';
import { NormalizedSchema } from './normalized-schema';

Expand All @@ -23,11 +19,7 @@ function updateRootConfig(
}

c.paths[options.importPath] = [
joinPathFragments(
getWorkspaceLayout(host).libsDir,
options.projectDirectory,
'/src/index.ts'
),
joinPathFragments(options.projectRoot, '/src/index.ts'),
];

return json;
Expand Down
4 changes: 3 additions & 1 deletion packages/create-nx-workspace/bin/create-nx-workspace.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ enum Preset {
TS = 'ts',
WebComponents = 'web-components',
Angular = 'angular',
AngularExperimental = 'angular-experimental',
React = 'react',
ReactExperimental = 'react-experimental',
ReactNative = 'react-native',
Expand Down Expand Up @@ -655,7 +656,7 @@ async function determineStyle(
},
];

if (![Preset.Angular].includes(preset)) {
if (![Preset.Angular, Preset.AngularExperimental].includes(preset)) {
choices.push({
name: 'styl',
message: 'Stylus(.styl) [ http://stylus-lang.com ]',
Expand Down Expand Up @@ -1029,6 +1030,7 @@ function pointToTutorialAndCourse(preset: Preset) {
});
break;
case Preset.Angular:
case Preset.AngularExperimental:
output.addVerticalSeparator();
output.note({
title,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
{
"recommendations": [
<% if(cliCommand === 'ng') { %>
"angular.ng-template",<% }
%>
"recommendations": [<% if(cliCommand === 'ng') { %>
"angular.ng-template",<% } %>
"nrwl.angular-console",
"esbenp.prettier-vscode"
]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,10 @@
"dependencies": {
},
"devDependencies": {
"nx": "<%= nxVersion %>",
"@nrwl/cli": "<%= nxVersion %>",
"@nrwl/workspace": "<%= nxVersion %>",
"typescript": "<%= typescriptVersion %>",
"prettier": "<%= prettierVersion %>"
"nx": "<%= nxVersion %>",
"prettier": "<%= prettierVersion %>",
"typescript": "<%= typescriptVersion %>"
}
}
1 change: 1 addition & 0 deletions packages/workspace/src/generators/new/generate-preset.ts
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@ function getPresetDependencies(preset: string, version?: string) {
return { dependencies: {}, dev: { '@nrwl/js': nxVersion } };

case Preset.Angular:
case Preset.AngularExperimental:
return { dependencies: { '@nrwl/angular': nxVersion }, dev: {} };

case Preset.Express:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,10 @@ function createAppsAndLibsFolders(host: Tree, options: NormalizedSchema) {
options.preset === Preset.NPM
) {
host.write(join(options.directory, 'packages/.gitkeep'), '');
} else if (options.preset === Preset.ReactExperimental) {
} else if (
options.preset === Preset.AngularExperimental ||
options.preset === Preset.ReactExperimental
) {
// don't generate any folders
} else {
host.write(join(options.directory, 'apps/.gitkeep'), '');
Expand Down Expand Up @@ -139,6 +142,7 @@ function createNxJson(
function createFiles(host: Tree, options: NormalizedSchema) {
const formattedNames = names(options.name);
const filesDirName =
options.preset === Preset.AngularExperimental ||
options.preset === Preset.ReactExperimental
? './files-root-app'
: options.preset === Preset.NPM || options.preset === Preset.Core
Expand Down
13 changes: 13 additions & 0 deletions packages/workspace/src/generators/preset/preset.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,19 @@ async function createPreset(tree: Tree, options: Schema) {
linter: options.linter,
standaloneConfig: options.standaloneConfig,
});
} else if (options.preset === Preset.AngularExperimental) {
const {
applicationGenerator: angularApplicationGenerator,
} = require('@nrwl' + '/angular/generators');

await angularApplicationGenerator(tree, {
name: options.name,
style: options.style,
linter: 'none',
unitTestRunner: 'none',
standaloneConfig: options.standaloneConfig,
rootProject: true,
});
} else if (options.preset === Preset.React) {
const {
applicationGenerator: reactApplicationGenerator,
Expand Down
1 change: 1 addition & 0 deletions packages/workspace/src/generators/utils/presets.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ export enum Preset {
TS = 'ts',
WebComponents = 'web-components',
Angular = 'angular',
AngularExperimental = 'angular-experimental',
React = 'react',
ReactExperimental = 'react-experimental',
ReactNative = 'react-native',
Expand Down

1 comment on commit 70e43cd

@vercel
Copy link

@vercel vercel bot commented on 70e43cd Nov 21, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Successfully deployed to the following URLs:

nx-dev – ./

nx-five.vercel.app
nx-dev-nrwl.vercel.app
nx.dev
nx-dev-git-master-nrwl.vercel.app

Please sign in to comment.