feat(react): add a preset to generate a workspace with a single app at the root
This commit is contained in:
parent
fc8de9a4d3
commit
c4ebef2803
@ -113,7 +113,7 @@ Package manager to use
|
|||||||
|
|
||||||
Type: `string`
|
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
|
### skipGit
|
||||||
|
|
||||||
|
|||||||
@ -111,6 +111,12 @@
|
|||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
"default": false,
|
"default": false,
|
||||||
"description": "Do not add dependencies to `package.json`."
|
"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"],
|
"required": ["name"],
|
||||||
|
|||||||
@ -10,7 +10,7 @@
|
|||||||
"name": "create-nx-workspace",
|
"name": "create-nx-workspace",
|
||||||
"id": "create-nx-workspace",
|
"id": "create-nx-workspace",
|
||||||
"file": "generated/cli/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",
|
"name": "init",
|
||||||
|
|||||||
@ -141,7 +141,7 @@
|
|||||||
"linter": {
|
"linter": {
|
||||||
"description": "The tool to use for running lint checks.",
|
"description": "The tool to use for running lint checks.",
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"enum": ["eslint"],
|
"enum": ["eslint", "none"],
|
||||||
"default": "eslint"
|
"default": "eslint"
|
||||||
},
|
},
|
||||||
"routing": {
|
"routing": {
|
||||||
@ -228,6 +228,12 @@
|
|||||||
"description": "Do not add dependencies to `package.json`.",
|
"description": "Do not add dependencies to `package.json`.",
|
||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
"default": false
|
"default": false
|
||||||
|
},
|
||||||
|
"rootProject": {
|
||||||
|
"description": "Create a application at the root of the workspace",
|
||||||
|
"type": "boolean",
|
||||||
|
"default": false,
|
||||||
|
"hidden": true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"required": [],
|
"required": [],
|
||||||
@ -314,7 +320,7 @@
|
|||||||
"linter": {
|
"linter": {
|
||||||
"description": "The tool to use for running lint checks.",
|
"description": "The tool to use for running lint checks.",
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"enum": ["eslint"],
|
"enum": ["eslint", "none"],
|
||||||
"default": "eslint"
|
"default": "eslint"
|
||||||
},
|
},
|
||||||
"unitTestRunner": {
|
"unitTestRunner": {
|
||||||
|
|||||||
@ -21,6 +21,20 @@ describe('create-nx-workspace', () => {
|
|||||||
|
|
||||||
afterEach(() => cleanupProject());
|
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', () => {
|
it('should be able to create an empty workspace built for apps', () => {
|
||||||
const wsName = uniq('apps');
|
const wsName = uniq('apps');
|
||||||
runCreateWorkspace(wsName, {
|
runCreateWorkspace(wsName, {
|
||||||
|
|||||||
@ -54,6 +54,7 @@ enum Preset {
|
|||||||
Angular = 'angular',
|
Angular = 'angular',
|
||||||
AngularWithNest = 'angular-nest',
|
AngularWithNest = 'angular-nest',
|
||||||
React = 'react',
|
React = 'react',
|
||||||
|
ReactExperimental = 'react-experimental',
|
||||||
ReactWithExpress = 'react-express',
|
ReactWithExpress = 'react-express',
|
||||||
ReactNative = 'react-native',
|
ReactNative = 'react-native',
|
||||||
Expo = 'expo',
|
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(
|
choices.push(
|
||||||
{
|
{
|
||||||
name: 'styled-components',
|
name: 'styled-components',
|
||||||
@ -1030,6 +1038,7 @@ function pointToTutorialAndCourse(preset: Preset) {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case Preset.React:
|
case Preset.React:
|
||||||
|
case Preset.ReactExperimental:
|
||||||
case Preset.ReactWithExpress:
|
case Preset.ReactWithExpress:
|
||||||
case Preset.NextJs:
|
case Preset.NextJs:
|
||||||
output.addVerticalSeparator();
|
output.addVerticalSeparator();
|
||||||
|
|||||||
@ -268,16 +268,23 @@ export async function cypressProjectGenerator(host: Tree, schema: Schema) {
|
|||||||
|
|
||||||
function normalizeOptions(host: Tree, options: Schema): CypressProjectSchema {
|
function normalizeOptions(host: Tree, options: Schema): CypressProjectSchema {
|
||||||
const { appsDir } = getWorkspaceLayout(host);
|
const { appsDir } = getWorkspaceLayout(host);
|
||||||
const projectName = filePathPrefix(
|
let projectName, projectRoot;
|
||||||
options.directory ? `${options.directory}-${options.name}` : options.name
|
|
||||||
);
|
if (options.rootProject) {
|
||||||
const projectRoot = options.directory
|
projectName = options.name;
|
||||||
? joinPathFragments(
|
projectRoot = options.name;
|
||||||
appsDir,
|
} else {
|
||||||
names(options.directory).fileName,
|
projectName = filePathPrefix(
|
||||||
options.name
|
options.directory ? `${options.directory}-${options.name}` : options.name
|
||||||
)
|
);
|
||||||
: joinPathFragments(appsDir, options.name);
|
projectRoot = options.directory
|
||||||
|
? joinPathFragments(
|
||||||
|
appsDir,
|
||||||
|
names(options.directory).fileName,
|
||||||
|
options.name
|
||||||
|
)
|
||||||
|
: joinPathFragments(appsDir, options.name);
|
||||||
|
}
|
||||||
|
|
||||||
options.linter = options.linter || Linter.EsLint;
|
options.linter = options.linter || Linter.EsLint;
|
||||||
return {
|
return {
|
||||||
|
|||||||
@ -11,4 +11,5 @@ export interface Schema {
|
|||||||
setParserOptionsProject?: boolean;
|
setParserOptionsProject?: boolean;
|
||||||
standaloneConfig?: boolean;
|
standaloneConfig?: boolean;
|
||||||
skipPackageJson?: boolean;
|
skipPackageJson?: boolean;
|
||||||
|
rootProject?: boolean;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -59,6 +59,12 @@
|
|||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
"default": false,
|
"default": false,
|
||||||
"description": "Do not add dependencies to `package.json`."
|
"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"],
|
"required": ["name"],
|
||||||
|
|||||||
@ -20,4 +20,9 @@ describe('offsetFromRoot', () => {
|
|||||||
const result = offsetFromRoot('apps/dirname/appname/');
|
const result = offsetFromRoot('apps/dirname/appname/');
|
||||||
expect(result).toBe('../../../');
|
expect(result).toBe('../../../');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should work for root', () => {
|
||||||
|
const result = offsetFromRoot('.');
|
||||||
|
expect(result).toBe('./');
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@ -13,6 +13,8 @@ import { normalize, sep } from 'path';
|
|||||||
* @param fullPathToDir - directory path
|
* @param fullPathToDir - directory path
|
||||||
*/
|
*/
|
||||||
export function offsetFromRoot(fullPathToDir: string): string {
|
export function offsetFromRoot(fullPathToDir: string): string {
|
||||||
|
if (fullPathToDir === '.') return './';
|
||||||
|
|
||||||
const parts = normalize(fullPathToDir).split(sep);
|
const parts = normalize(fullPathToDir).split(sep);
|
||||||
let offset = '';
|
let offset = '';
|
||||||
for (let i = 0; i < parts.length; ++i) {
|
for (let i = 0; i < parts.length; ++i) {
|
||||||
|
|||||||
@ -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');
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@ -23,47 +23,48 @@ import {
|
|||||||
} from '@nrwl/devkit';
|
} from '@nrwl/devkit';
|
||||||
import { runTasksInSerial } from '@nrwl/workspace/src/utilities/run-tasks-in-serial';
|
import { runTasksInSerial } from '@nrwl/workspace/src/utilities/run-tasks-in-serial';
|
||||||
import reactInitGenerator from '../init/init';
|
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 { swcCoreVersion } from '@nrwl/js/src/utils/versions';
|
||||||
import { swcLoaderVersion } from '@nrwl/webpack/src/utils/versions';
|
import { swcLoaderVersion } from '@nrwl/webpack/src/utils/versions';
|
||||||
|
|
||||||
async function addLinting(host: Tree, options: NormalizedSchema) {
|
async function addLinting(host: Tree, options: NormalizedSchema) {
|
||||||
const tasks: GeneratorCallback[] = [];
|
const tasks: GeneratorCallback[] = [];
|
||||||
const lintTask = await lintProjectGenerator(host, {
|
if (options.linter === Linter.EsLint) {
|
||||||
linter: options.linter,
|
const lintTask = await lintProjectGenerator(host, {
|
||||||
project: options.projectName,
|
linter: options.linter,
|
||||||
tsConfigPaths: [
|
project: options.projectName,
|
||||||
joinPathFragments(options.appProjectRoot, 'tsconfig.app.json'),
|
tsConfigPaths: [
|
||||||
],
|
joinPathFragments(options.appProjectRoot, 'tsconfig.app.json'),
|
||||||
unitTestRunner: options.unitTestRunner,
|
],
|
||||||
eslintFilePatterns: [`${options.appProjectRoot}/**/*.{ts,tsx,js,jsx}`],
|
unitTestRunner: options.unitTestRunner,
|
||||||
skipFormat: true,
|
eslintFilePatterns: [`${options.appProjectRoot}/**/*.{ts,tsx,js,jsx}`],
|
||||||
});
|
skipFormat: true,
|
||||||
tasks.push(lintTask);
|
});
|
||||||
|
tasks.push(lintTask);
|
||||||
|
|
||||||
const reactEslintJson = createReactEslintJson(
|
const reactEslintJson = createReactEslintJson(
|
||||||
options.appProjectRoot,
|
options.appProjectRoot,
|
||||||
options.setParserOptionsProject
|
options.setParserOptionsProject
|
||||||
);
|
);
|
||||||
|
|
||||||
updateJson(
|
updateJson(
|
||||||
host,
|
host,
|
||||||
joinPathFragments(options.appProjectRoot, '.eslintrc.json'),
|
joinPathFragments(options.appProjectRoot, '.eslintrc.json'),
|
||||||
() => reactEslintJson
|
() => reactEslintJson
|
||||||
);
|
);
|
||||||
|
|
||||||
const installTask = await addDependenciesToPackageJson(
|
|
||||||
host,
|
|
||||||
extraEslintDependencies.dependencies,
|
|
||||||
{
|
|
||||||
...extraEslintDependencies.devDependencies,
|
|
||||||
...(options.compiler === 'swc'
|
|
||||||
? { '@swc/core': swcCoreVersion, 'swc-loader': swcLoaderVersion }
|
|
||||||
: {}),
|
|
||||||
}
|
|
||||||
);
|
|
||||||
tasks.push(installTask);
|
|
||||||
|
|
||||||
|
const installTask = await addDependenciesToPackageJson(
|
||||||
|
host,
|
||||||
|
extraEslintDependencies.dependencies,
|
||||||
|
{
|
||||||
|
...extraEslintDependencies.devDependencies,
|
||||||
|
...(options.compiler === 'swc'
|
||||||
|
? { '@swc/core': swcCoreVersion, 'swc-loader': swcLoaderVersion }
|
||||||
|
: {}),
|
||||||
|
}
|
||||||
|
);
|
||||||
|
tasks.push(installTask);
|
||||||
|
}
|
||||||
return runTasksInSerial(...tasks);
|
return runTasksInSerial(...tasks);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -9,7 +9,7 @@ export async function addCypress(host: Tree, options: NormalizedSchema) {
|
|||||||
|
|
||||||
return await cypressProjectGenerator(host, {
|
return await cypressProjectGenerator(host, {
|
||||||
...options,
|
...options,
|
||||||
name: `${options.name}-e2e`,
|
name: options.e2eProjectName,
|
||||||
directory: options.directory,
|
directory: options.directory,
|
||||||
project: options.projectName,
|
project: options.projectName,
|
||||||
});
|
});
|
||||||
|
|||||||
@ -41,7 +41,12 @@ function createBuildTarget(options: NormalizedSchema): TargetConfiguration {
|
|||||||
defaultConfiguration: 'production',
|
defaultConfiguration: 'production',
|
||||||
options: {
|
options: {
|
||||||
compiler: options.compiler ?? 'babel',
|
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'),
|
index: joinPathFragments(options.appProjectRoot, 'src/index.html'),
|
||||||
baseHref: '/',
|
baseHref: '/',
|
||||||
main: joinPathFragments(
|
main: joinPathFragments(
|
||||||
|
|||||||
@ -19,10 +19,14 @@ export function normalizeOptions(
|
|||||||
): NormalizedSchema {
|
): NormalizedSchema {
|
||||||
const appDirectory = normalizeDirectory(options);
|
const appDirectory = normalizeDirectory(options);
|
||||||
const appProjectName = normalizeProjectName(options);
|
const appProjectName = normalizeProjectName(options);
|
||||||
const e2eProjectName = `${appProjectName}-e2e`;
|
const e2eProjectName = options.rootProject
|
||||||
|
? 'e2e'
|
||||||
|
: `${names(options.name).fileName}-e2e`;
|
||||||
|
|
||||||
const { appsDir } = getWorkspaceLayout(host);
|
const { appsDir } = getWorkspaceLayout(host);
|
||||||
const appProjectRoot = normalizePath(`${appsDir}/${appDirectory}`);
|
const appProjectRoot = options.rootProject
|
||||||
|
? '.'
|
||||||
|
: normalizePath(`${appsDir}/${appDirectory}`);
|
||||||
|
|
||||||
const parsedTags = options.tags
|
const parsedTags = options.tags
|
||||||
? options.tags.split(',').map((s) => s.trim())
|
? options.tags.split(',').map((s) => s.trim())
|
||||||
|
|||||||
@ -28,6 +28,7 @@ export function setDefaults(host: Tree, options: NormalizedSchema) {
|
|||||||
...prev,
|
...prev,
|
||||||
application: {
|
application: {
|
||||||
style: options.style,
|
style: options.style,
|
||||||
|
unitTestRunner: options.unitTestRunner,
|
||||||
linter: options.linter,
|
linter: options.linter,
|
||||||
...prev.application,
|
...prev.application,
|
||||||
},
|
},
|
||||||
@ -37,6 +38,7 @@ export function setDefaults(host: Tree, options: NormalizedSchema) {
|
|||||||
},
|
},
|
||||||
library: {
|
library: {
|
||||||
style: options.style,
|
style: options.style,
|
||||||
|
unitTestRunner: options.unitTestRunner,
|
||||||
linter: options.linter,
|
linter: options.linter,
|
||||||
...prev.library,
|
...prev.library,
|
||||||
},
|
},
|
||||||
|
|||||||
@ -28,6 +28,7 @@ export interface Schema {
|
|||||||
devServerPort?: number;
|
devServerPort?: number;
|
||||||
skipDefaultProject?: boolean;
|
skipDefaultProject?: boolean;
|
||||||
skipPackageJson?: boolean;
|
skipPackageJson?: boolean;
|
||||||
|
rootProject?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface NormalizedSchema extends Schema {
|
export interface NormalizedSchema extends Schema {
|
||||||
|
|||||||
@ -82,7 +82,7 @@
|
|||||||
"linter": {
|
"linter": {
|
||||||
"description": "The tool to use for running lint checks.",
|
"description": "The tool to use for running lint checks.",
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"enum": ["eslint"],
|
"enum": ["eslint", "none"],
|
||||||
"default": "eslint"
|
"default": "eslint"
|
||||||
},
|
},
|
||||||
"routing": {
|
"routing": {
|
||||||
@ -169,6 +169,12 @@
|
|||||||
"description": "Do not add dependencies to `package.json`.",
|
"description": "Do not add dependencies to `package.json`.",
|
||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
"default": false
|
"default": false
|
||||||
|
},
|
||||||
|
"rootProject": {
|
||||||
|
"description": "Create a application at the root of the workspace",
|
||||||
|
"type": "boolean",
|
||||||
|
"default": false,
|
||||||
|
"hidden": true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"required": []
|
"required": []
|
||||||
|
|||||||
@ -19,7 +19,7 @@ import {
|
|||||||
import { getImportPath } from 'nx/src/utils/path';
|
import { getImportPath } from 'nx/src/utils/path';
|
||||||
import { jestProjectGenerator } from '@nrwl/jest';
|
import { jestProjectGenerator } from '@nrwl/jest';
|
||||||
import { swcCoreVersion } from '@nrwl/js/src/utils/versions';
|
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 { runTasksInSerial } from '@nrwl/workspace/src/utilities/run-tasks-in-serial';
|
||||||
import {
|
import {
|
||||||
getRelativePathToRootTsConfig,
|
getRelativePathToRootTsConfig,
|
||||||
@ -143,39 +143,43 @@ export async function libraryGenerator(host: Tree, schema: Schema) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function addLinting(host: Tree, options: NormalizedSchema) {
|
async function addLinting(host: Tree, options: NormalizedSchema) {
|
||||||
const lintTask = await lintProjectGenerator(host, {
|
if (options.linter === Linter.EsLint) {
|
||||||
linter: options.linter,
|
const lintTask = await lintProjectGenerator(host, {
|
||||||
project: options.name,
|
linter: options.linter,
|
||||||
tsConfigPaths: [
|
project: options.name,
|
||||||
joinPathFragments(options.projectRoot, 'tsconfig.lib.json'),
|
tsConfigPaths: [
|
||||||
],
|
joinPathFragments(options.projectRoot, 'tsconfig.lib.json'),
|
||||||
unitTestRunner: options.unitTestRunner,
|
],
|
||||||
eslintFilePatterns: [`${options.projectRoot}/**/*.{ts,tsx,js,jsx}`],
|
unitTestRunner: options.unitTestRunner,
|
||||||
skipFormat: true,
|
eslintFilePatterns: [`${options.projectRoot}/**/*.{ts,tsx,js,jsx}`],
|
||||||
skipPackageJson: options.skipPackageJson,
|
skipFormat: true,
|
||||||
});
|
skipPackageJson: options.skipPackageJson,
|
||||||
|
});
|
||||||
|
|
||||||
const reactEslintJson = createReactEslintJson(
|
const reactEslintJson = createReactEslintJson(
|
||||||
options.projectRoot,
|
options.projectRoot,
|
||||||
options.setParserOptionsProject
|
options.setParserOptionsProject
|
||||||
);
|
|
||||||
|
|
||||||
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);
|
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) {
|
function addProject(host: Tree, options: NormalizedSchema) {
|
||||||
@ -192,7 +196,7 @@ function addProject(host: Tree, options: NormalizedSchema) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
targets.build = {
|
targets.build = {
|
||||||
builder: '@nrwl/web:rollup',
|
executor: '@nrwl/web:rollup',
|
||||||
outputs: ['{options.outputPath}'],
|
outputs: ['{options.outputPath}'],
|
||||||
options: {
|
options: {
|
||||||
outputPath: `dist/${libsDir}/${options.projectDirectory}`,
|
outputPath: `dist/${libsDir}/${options.projectDirectory}`,
|
||||||
|
|||||||
@ -75,7 +75,7 @@
|
|||||||
"linter": {
|
"linter": {
|
||||||
"description": "The tool to use for running lint checks.",
|
"description": "The tool to use for running lint checks.",
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"enum": ["eslint"],
|
"enum": ["eslint", "none"],
|
||||||
"default": "eslint"
|
"default": "eslint"
|
||||||
},
|
},
|
||||||
"unitTestRunner": {
|
"unitTestRunner": {
|
||||||
|
|||||||
@ -36,6 +36,11 @@
|
|||||||
"glob": "**/files-npm/**",
|
"glob": "**/files-npm/**",
|
||||||
"output": "/"
|
"output": "/"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"input": "packages/workspace",
|
||||||
|
"glob": "**/files-root-app/**",
|
||||||
|
"output": "/"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"input": "packages/workspace",
|
"input": "packages/workspace",
|
||||||
"glob": "**/files-npm/**/.gitkeep",
|
"glob": "**/files-npm/**/.gitkeep",
|
||||||
|
|||||||
@ -194,6 +194,9 @@ function getPresetDependencies(preset: string, version?: string) {
|
|||||||
case Preset.React:
|
case Preset.React:
|
||||||
return { dependencies: {}, dev: { '@nrwl/react': nxVersion } };
|
return { dependencies: {}, dev: { '@nrwl/react': nxVersion } };
|
||||||
|
|
||||||
|
case Preset.ReactExperimental:
|
||||||
|
return { dependencies: {}, dev: { '@nrwl/react': nxVersion } };
|
||||||
|
|
||||||
case Preset.ReactWithExpress:
|
case Preset.ReactWithExpress:
|
||||||
return {
|
return {
|
||||||
dependencies: {},
|
dependencies: {},
|
||||||
|
|||||||
@ -56,6 +56,19 @@ async function createPreset(tree: Tree, options: Schema) {
|
|||||||
linter: options.linter,
|
linter: options.linter,
|
||||||
standaloneConfig: options.standaloneConfig,
|
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) {
|
} else if (options.preset === Preset.NextJs) {
|
||||||
const { applicationGenerator: nextApplicationGenerator } = require('@nrwl' +
|
const { applicationGenerator: nextApplicationGenerator } = require('@nrwl' +
|
||||||
'/next');
|
'/next');
|
||||||
|
|||||||
@ -8,6 +8,7 @@ export enum Preset {
|
|||||||
Angular = 'angular',
|
Angular = 'angular',
|
||||||
AngularWithNest = 'angular-nest',
|
AngularWithNest = 'angular-nest',
|
||||||
React = 'react',
|
React = 'react',
|
||||||
|
ReactExperimental = 'react-experimental',
|
||||||
ReactWithExpress = 'react-express',
|
ReactWithExpress = 'react-express',
|
||||||
ReactNative = 'react-native',
|
ReactNative = 'react-native',
|
||||||
Expo = 'expo',
|
Expo = 'expo',
|
||||||
|
|||||||
@ -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
|
||||||
@ -0,0 +1,4 @@
|
|||||||
|
# Add files here to ignore them from prettier formatting
|
||||||
|
|
||||||
|
/dist
|
||||||
|
/coverage
|
||||||
@ -0,0 +1,9 @@
|
|||||||
|
{
|
||||||
|
"recommendations": [
|
||||||
|
<% if(cli === 'angular') { %>
|
||||||
|
"angular.ng-template",<% }
|
||||||
|
%>
|
||||||
|
"nrwl.angular-console",
|
||||||
|
"esbenp.prettier-vscode"
|
||||||
|
]
|
||||||
|
}
|
||||||
@ -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 %>"
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -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"]
|
||||||
|
}
|
||||||
@ -54,6 +54,8 @@ function createAppsAndLibsFolders(host: Tree, options: Schema) {
|
|||||||
options.preset === Preset.NPM
|
options.preset === Preset.NPM
|
||||||
) {
|
) {
|
||||||
host.write(join(options.directory, 'packages/.gitkeep'), '');
|
host.write(join(options.directory, 'packages/.gitkeep'), '');
|
||||||
|
} else if (options.preset === Preset.ReactExperimental) {
|
||||||
|
// don't generate any folders
|
||||||
} else {
|
} else {
|
||||||
host.write(join(options.directory, 'apps/.gitkeep'), '');
|
host.write(join(options.directory, 'apps/.gitkeep'), '');
|
||||||
host.write(join(options.directory, 'libs/.gitkeep'), '');
|
host.write(join(options.directory, 'libs/.gitkeep'), '');
|
||||||
@ -114,7 +116,9 @@ function createNxJson(
|
|||||||
function createFiles(host: Tree, options: Schema) {
|
function createFiles(host: Tree, options: Schema) {
|
||||||
const formattedNames = names(options.name);
|
const formattedNames = names(options.name);
|
||||||
const filesDirName =
|
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-npm'
|
||||||
: './files';
|
: './files';
|
||||||
generateFiles(host, pathJoin(__dirname, filesDirName), options.directory, {
|
generateFiles(host, pathJoin(__dirname, filesDirName), options.directory, {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user