feat(node): update CNW to support generating a node server with a framework (#14313)
This commit is contained in:
parent
5faef5d972
commit
00caf6ae5e
@ -75,6 +75,12 @@ Default: `main`
|
|||||||
|
|
||||||
Default base to use for new projects
|
Default base to use for new projects
|
||||||
|
|
||||||
|
### framework
|
||||||
|
|
||||||
|
Type: `string`
|
||||||
|
|
||||||
|
Framework option to be used when the node-server preset is selected
|
||||||
|
|
||||||
### help
|
### help
|
||||||
|
|
||||||
Type: `boolean`
|
Type: `boolean`
|
||||||
@ -113,7 +119,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-monorepo", "angular-standalone", "react-monorepo", "react-standalone", "react-native", "expo", "next", "nest", "express", "react", "angular"]. 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-monorepo", "angular-standalone", "react-monorepo", "react-standalone", "react-native", "expo", "next", "nest", "express", "react", "angular", "node-server"]. To build your own see https://nx.dev/packages/nx-plugin#preset
|
||||||
|
|
||||||
### skipGit
|
### skipGit
|
||||||
|
|
||||||
|
|||||||
@ -89,6 +89,12 @@
|
|||||||
"description": "The port which the server will be run on",
|
"description": "The port which the server will be run on",
|
||||||
"type": "number",
|
"type": "number",
|
||||||
"default": 3000
|
"default": 3000
|
||||||
|
},
|
||||||
|
"rootProject": {
|
||||||
|
"description": "Create node application at the root of the workspace",
|
||||||
|
"type": "boolean",
|
||||||
|
"default": false,
|
||||||
|
"hidden": true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"required": [],
|
"required": [],
|
||||||
|
|||||||
@ -75,6 +75,12 @@ Default: `main`
|
|||||||
|
|
||||||
Default base to use for new projects
|
Default base to use for new projects
|
||||||
|
|
||||||
|
### framework
|
||||||
|
|
||||||
|
Type: `string`
|
||||||
|
|
||||||
|
Framework option to be used when the node-server preset is selected
|
||||||
|
|
||||||
### help
|
### help
|
||||||
|
|
||||||
Type: `boolean`
|
Type: `boolean`
|
||||||
@ -113,7 +119,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-monorepo", "angular-standalone", "react-monorepo", "react-standalone", "react-native", "expo", "next", "nest", "express", "react", "angular"]. 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-monorepo", "angular-standalone", "react-monorepo", "react-standalone", "react-native", "expo", "next", "nest", "express", "react", "angular", "node-server"]. To build your own see https://nx.dev/packages/nx-plugin#preset
|
||||||
|
|
||||||
### skipGit
|
### skipGit
|
||||||
|
|
||||||
|
|||||||
@ -59,6 +59,11 @@
|
|||||||
"description": "The package manager used to install dependencies.",
|
"description": "The package manager used to install dependencies.",
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"enum": ["npm", "yarn", "pnpm"]
|
"enum": ["npm", "yarn", "pnpm"]
|
||||||
|
},
|
||||||
|
"framework": {
|
||||||
|
"description": "The framework which the application is using",
|
||||||
|
"type": "string",
|
||||||
|
"enum": ["express", "koa", "fastify", "connect"]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"additionalProperties": true,
|
"additionalProperties": true,
|
||||||
|
|||||||
@ -57,6 +57,11 @@
|
|||||||
"description": "The package manager used to install dependencies.",
|
"description": "The package manager used to install dependencies.",
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"enum": ["npm", "yarn", "pnpm"]
|
"enum": ["npm", "yarn", "pnpm"]
|
||||||
|
},
|
||||||
|
"framework": {
|
||||||
|
"description": "The framework which the application is using",
|
||||||
|
"type": "string",
|
||||||
|
"enum": ["express", "koa", "fastify", "connect"]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"presets": []
|
"presets": []
|
||||||
|
|||||||
@ -126,9 +126,9 @@ describe('Node Applications', () => {
|
|||||||
|
|
||||||
it('should be able to generate an express application', async () => {
|
it('should be able to generate an express application', async () => {
|
||||||
const nodeapp = uniq('nodeapp');
|
const nodeapp = uniq('nodeapp');
|
||||||
const originalEnvPort = process.env.port;
|
const originalEnvPort = process.env.PORT;
|
||||||
const port = 3333;
|
const port = 3333;
|
||||||
process.env.port = `${port}`;
|
process.env.PORT = `${port}`;
|
||||||
|
|
||||||
runCLI(`generate @nrwl/express:app ${nodeapp} --linter=eslint`);
|
runCLI(`generate @nrwl/express:app ${nodeapp} --linter=eslint`);
|
||||||
const lintResults = runCLI(`lint ${nodeapp}`);
|
const lintResults = runCLI(`lint ${nodeapp}`);
|
||||||
|
|||||||
@ -31,6 +31,7 @@ type Arguments = {
|
|||||||
appName: string;
|
appName: string;
|
||||||
cli: string;
|
cli: string;
|
||||||
style: string;
|
style: string;
|
||||||
|
framework: string;
|
||||||
nxCloud: boolean;
|
nxCloud: boolean;
|
||||||
allPrompts: boolean;
|
allPrompts: boolean;
|
||||||
packageManager: PackageManager;
|
packageManager: PackageManager;
|
||||||
@ -62,6 +63,7 @@ enum Preset {
|
|||||||
Express = 'express',
|
Express = 'express',
|
||||||
React = 'react',
|
React = 'react',
|
||||||
Angular = 'angular',
|
Angular = 'angular',
|
||||||
|
NodeServer = 'node-server',
|
||||||
}
|
}
|
||||||
|
|
||||||
const presetOptions: { name: Preset; message: string }[] = [
|
const presetOptions: { name: Preset; message: string }[] = [
|
||||||
@ -96,6 +98,11 @@ const presetOptions: { name: Preset; message: string }[] = [
|
|||||||
message:
|
message:
|
||||||
'react-native [a monorepo with a single React Native application]',
|
'react-native [a monorepo with a single React Native application]',
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: Preset.NodeServer,
|
||||||
|
message:
|
||||||
|
'node [a standalone repo with a single Node Server e.g. Express]',
|
||||||
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
const nxVersion = require('../package.json').version;
|
const nxVersion = require('../package.json').version;
|
||||||
@ -145,6 +152,10 @@ export const commandsObject: yargs.Argv<Arguments> = yargs
|
|||||||
describe: chalk.dim`Style option to be used when a preset with pregenerated app is selected`,
|
describe: chalk.dim`Style option to be used when a preset with pregenerated app is selected`,
|
||||||
type: 'string',
|
type: 'string',
|
||||||
})
|
})
|
||||||
|
.option('framework', {
|
||||||
|
describe: chalk.dim`Framework option to be used when the node-server preset is selected`,
|
||||||
|
type: 'string',
|
||||||
|
})
|
||||||
.option('nxCloud', {
|
.option('nxCloud', {
|
||||||
describe: chalk.dim(messages.getPromptMessage('nxCloudCreation')),
|
describe: chalk.dim(messages.getPromptMessage('nxCloudCreation')),
|
||||||
type: 'boolean',
|
type: 'boolean',
|
||||||
@ -224,6 +235,7 @@ async function main(parsedArgs: yargs.Arguments<Arguments>) {
|
|||||||
ci,
|
ci,
|
||||||
skipGit,
|
skipGit,
|
||||||
commit,
|
commit,
|
||||||
|
framework,
|
||||||
} = parsedArgs;
|
} = parsedArgs;
|
||||||
|
|
||||||
output.log({
|
output.log({
|
||||||
@ -248,6 +260,7 @@ async function main(parsedArgs: yargs.Arguments<Arguments>) {
|
|||||||
style,
|
style,
|
||||||
nxCloud,
|
nxCloud,
|
||||||
defaultBase,
|
defaultBase,
|
||||||
|
framework,
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -300,7 +313,7 @@ async function getConfiguration(
|
|||||||
argv: yargs.Arguments<Arguments>
|
argv: yargs.Arguments<Arguments>
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
try {
|
try {
|
||||||
let name, appName, style, preset;
|
let name, appName, style, preset, framework;
|
||||||
|
|
||||||
output.log({
|
output.log({
|
||||||
title:
|
title:
|
||||||
@ -343,6 +356,9 @@ async function getConfiguration(
|
|||||||
} else {
|
} else {
|
||||||
name = await determineRepoName(argv);
|
name = await determineRepoName(argv);
|
||||||
appName = await determineAppName(preset, argv);
|
appName = await determineAppName(preset, argv);
|
||||||
|
if (preset === Preset.NodeServer) {
|
||||||
|
framework = await determineFramework(preset, argv);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
style = await determineStyle(preset, argv);
|
style = await determineStyle(preset, argv);
|
||||||
}
|
}
|
||||||
@ -358,6 +374,7 @@ async function getConfiguration(
|
|||||||
preset,
|
preset,
|
||||||
appName,
|
appName,
|
||||||
style,
|
style,
|
||||||
|
framework,
|
||||||
cli,
|
cli,
|
||||||
nxCloud,
|
nxCloud,
|
||||||
packageManager,
|
packageManager,
|
||||||
@ -643,6 +660,47 @@ async function determineAppName(
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function determineFramework(
|
||||||
|
preset: Preset,
|
||||||
|
parsedArgs: yargs.Arguments<Arguments>
|
||||||
|
): Promise<string> {
|
||||||
|
if (preset !== Preset.NodeServer) {
|
||||||
|
return Promise.resolve('');
|
||||||
|
}
|
||||||
|
|
||||||
|
const frameworkChoices = ['express', 'koa', 'fastify', 'connect'];
|
||||||
|
|
||||||
|
if (!parsedArgs.framework) {
|
||||||
|
return enquirer
|
||||||
|
.prompt([
|
||||||
|
{
|
||||||
|
message: 'What framework should be used?',
|
||||||
|
type: 'select',
|
||||||
|
name: 'framework',
|
||||||
|
choices: frameworkChoices,
|
||||||
|
},
|
||||||
|
])
|
||||||
|
.then((a: { framework: string }) => a.framework);
|
||||||
|
}
|
||||||
|
|
||||||
|
const foundFramework = frameworkChoices.indexOf(parsedArgs.framework);
|
||||||
|
|
||||||
|
if (foundFramework < 0) {
|
||||||
|
output.error({
|
||||||
|
title: 'Invalid framwork',
|
||||||
|
bodyLines: [
|
||||||
|
`It must be one of the following:`,
|
||||||
|
'',
|
||||||
|
...frameworkChoices.map((choice) => choice),
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Promise.resolve(parsedArgs.framework);
|
||||||
|
}
|
||||||
|
|
||||||
function isValidCli(cli: string): cli is 'angular' | 'nx' {
|
function isValidCli(cli: string): cli is 'angular' | 'nx' {
|
||||||
return ['nx', 'angular'].indexOf(cli) !== -1;
|
return ['nx', 'angular'].indexOf(cli) !== -1;
|
||||||
}
|
}
|
||||||
@ -685,7 +743,8 @@ async function determineStyle(
|
|||||||
preset === Preset.Nest ||
|
preset === Preset.Nest ||
|
||||||
preset === Preset.Express ||
|
preset === Preset.Express ||
|
||||||
preset === Preset.ReactNative ||
|
preset === Preset.ReactNative ||
|
||||||
preset === Preset.Expo
|
preset === Preset.Expo ||
|
||||||
|
preset === Preset.NodeServer
|
||||||
) {
|
) {
|
||||||
return Promise.resolve(null);
|
return Promise.resolve(null);
|
||||||
}
|
}
|
||||||
@ -1182,6 +1241,7 @@ function pointToTutorialAndCourse(preset: Preset) {
|
|||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
case Preset.Express:
|
case Preset.Express:
|
||||||
|
case Preset.NodeServer:
|
||||||
output.addVerticalSeparator();
|
output.addVerticalSeparator();
|
||||||
output.note({
|
output.note({
|
||||||
title,
|
title,
|
||||||
|
|||||||
@ -16,11 +16,14 @@ describe('app', () => {
|
|||||||
} as Schema);
|
} as Schema);
|
||||||
|
|
||||||
const mainFile = appTree.read('apps/my-node-app/src/main.ts').toString();
|
const mainFile = appTree.read('apps/my-node-app/src/main.ts').toString();
|
||||||
expect(mainFile).toContain(`import * as express from 'express';`);
|
expect(mainFile).toContain(`import express from 'express';`);
|
||||||
|
|
||||||
const tsconfig = readJson(appTree, 'apps/my-node-app/tsconfig.json');
|
const tsconfig = readJson(appTree, 'apps/my-node-app/tsconfig.json');
|
||||||
expect(tsconfig).toMatchInlineSnapshot(`
|
expect(tsconfig).toMatchInlineSnapshot(`
|
||||||
Object {
|
Object {
|
||||||
|
"compilerOptions": Object {
|
||||||
|
"esModuleInterop": true,
|
||||||
|
},
|
||||||
"extends": "../../tsconfig.base.json",
|
"extends": "../../tsconfig.base.json",
|
||||||
"files": Array [],
|
"files": Array [],
|
||||||
"include": Array [],
|
"include": Array [],
|
||||||
@ -111,12 +114,13 @@ Object {
|
|||||||
|
|
||||||
expect(appTree.exists('apps/my-node-app/src/main.js')).toBeTruthy();
|
expect(appTree.exists('apps/my-node-app/src/main.js')).toBeTruthy();
|
||||||
expect(appTree.read('apps/my-node-app/src/main.js').toString()).toContain(
|
expect(appTree.read('apps/my-node-app/src/main.js').toString()).toContain(
|
||||||
`import * as express from 'express';`
|
`import express from 'express';`
|
||||||
);
|
);
|
||||||
|
|
||||||
const tsConfig = readJson(appTree, 'apps/my-node-app/tsconfig.json');
|
const tsConfig = readJson(appTree, 'apps/my-node-app/tsconfig.json');
|
||||||
expect(tsConfig.compilerOptions).toEqual({
|
expect(tsConfig.compilerOptions).toEqual({
|
||||||
allowJs: true,
|
allowJs: true,
|
||||||
|
esModuleInterop: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
const tsConfigApp = readJson(
|
const tsConfigApp = readJson(
|
||||||
|
|||||||
@ -37,7 +37,7 @@ function addMainFile(tree: Tree, options: NormalizedSchema) {
|
|||||||
* This is only a minimal backend to get started.
|
* This is only a minimal backend to get started.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import * as express from 'express';
|
import express from 'express';
|
||||||
import * as path from 'path';
|
import * as path from 'path';
|
||||||
|
|
||||||
const app = express();
|
const app = express();
|
||||||
@ -48,7 +48,7 @@ app.get('/api', (req, res) => {
|
|||||||
res.send({ message: 'Welcome to ${options.name}!' });
|
res.send({ message: 'Welcome to ${options.name}!' });
|
||||||
});
|
});
|
||||||
|
|
||||||
const port = process.env.port || 3333;
|
const port = process.env.PORT || 3333;
|
||||||
const server = app.listen(port, () => {
|
const server = app.listen(port, () => {
|
||||||
console.log(\`Listening at http://localhost:\${port}/api\`);
|
console.log(\`Listening at http://localhost:\${port}/api\`);
|
||||||
});
|
});
|
||||||
|
|||||||
@ -41,6 +41,7 @@ describe('app', () => {
|
|||||||
await applicationGenerator(tree, {
|
await applicationGenerator(tree, {
|
||||||
name: 'myNodeApp',
|
name: 'myNodeApp',
|
||||||
standaloneConfig: false,
|
standaloneConfig: false,
|
||||||
|
bundler: 'webpack',
|
||||||
});
|
});
|
||||||
const project = readProjectConfiguration(tree, 'my-node-app');
|
const project = readProjectConfiguration(tree, 'my-node-app');
|
||||||
expect(project.root).toEqual('my-node-app');
|
expect(project.root).toEqual('my-node-app');
|
||||||
@ -116,6 +117,9 @@ describe('app', () => {
|
|||||||
const tsconfig = readJson(tree, 'my-node-app/tsconfig.json');
|
const tsconfig = readJson(tree, 'my-node-app/tsconfig.json');
|
||||||
expect(tsconfig).toMatchInlineSnapshot(`
|
expect(tsconfig).toMatchInlineSnapshot(`
|
||||||
Object {
|
Object {
|
||||||
|
"compilerOptions": Object {
|
||||||
|
"esModuleInterop": true,
|
||||||
|
},
|
||||||
"extends": "../tsconfig.base.json",
|
"extends": "../tsconfig.base.json",
|
||||||
"files": Array [],
|
"files": Array [],
|
||||||
"include": Array [],
|
"include": Array [],
|
||||||
@ -401,6 +405,7 @@ describe('app', () => {
|
|||||||
const tsConfig = readJson(tree, 'my-node-app/tsconfig.json');
|
const tsConfig = readJson(tree, 'my-node-app/tsconfig.json');
|
||||||
expect(tsConfig.compilerOptions).toEqual({
|
expect(tsConfig.compilerOptions).toEqual({
|
||||||
allowJs: true,
|
allowJs: true,
|
||||||
|
esModuleInterop: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
const tsConfigApp = readJson(tree, 'my-node-app/tsconfig.app.json');
|
const tsConfigApp = readJson(tree, 'my-node-app/tsconfig.app.json');
|
||||||
|
|||||||
@ -27,7 +27,7 @@ import { Linter, lintProjectGenerator } from '@nrwl/linter';
|
|||||||
import { jestProjectGenerator } from '@nrwl/jest';
|
import { jestProjectGenerator } from '@nrwl/jest';
|
||||||
import { runTasksInSerial } from '@nrwl/workspace/src/utilities/run-tasks-in-serial';
|
import { runTasksInSerial } from '@nrwl/workspace/src/utilities/run-tasks-in-serial';
|
||||||
|
|
||||||
import { Schema } from './schema';
|
import { NodeJsFrameWorks, Schema } from './schema';
|
||||||
import { initGenerator } from '../init/init';
|
import { initGenerator } from '../init/init';
|
||||||
import { getRelativePathToRootTsConfig } from '@nrwl/workspace/src/utilities/typescript';
|
import { getRelativePathToRootTsConfig } from '@nrwl/workspace/src/utilities/typescript';
|
||||||
import {
|
import {
|
||||||
@ -43,6 +43,8 @@ import {
|
|||||||
} from '../../utils/versions';
|
} from '../../utils/versions';
|
||||||
import { prompt } from 'enquirer';
|
import { prompt } from 'enquirer';
|
||||||
|
|
||||||
|
import * as shared from '@nrwl/workspace/src/utils/create-ts-config';
|
||||||
|
|
||||||
export interface NormalizedSchema extends Schema {
|
export interface NormalizedSchema extends Schema {
|
||||||
appProjectRoot: string;
|
appProjectRoot: string;
|
||||||
parsedTags: string[];
|
parsedTags: string[];
|
||||||
@ -290,14 +292,27 @@ function addProjectDependencies(
|
|||||||
}
|
}
|
||||||
|
|
||||||
function updateTsConfigOptions(tree: Tree, options: NormalizedSchema) {
|
function updateTsConfigOptions(tree: Tree, options: NormalizedSchema) {
|
||||||
// updatae tsconfig.app.json to typecheck default exports https://www.typescriptlang.org/tsconfig#esModuleInterop
|
updateJson(tree, `${options.appProjectRoot}/tsconfig.json`, (json) => {
|
||||||
updateJson(tree, `${options.appProjectRoot}/tsconfig.app.json`, (json) => ({
|
if (options.rootProject) {
|
||||||
|
return {
|
||||||
|
compilerOptions: {
|
||||||
|
...shared.tsConfigBaseOptions,
|
||||||
|
...json.compilerOptions,
|
||||||
|
},
|
||||||
|
...json,
|
||||||
|
extends: undefined,
|
||||||
|
exclude: ['node_modules', 'tmp'],
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
return {
|
||||||
...json,
|
...json,
|
||||||
compilerOptions: {
|
compilerOptions: {
|
||||||
...json.compilerOptions,
|
...json.compilerOptions,
|
||||||
esModuleInterop: true,
|
esModuleInterop: true,
|
||||||
},
|
},
|
||||||
}));
|
};
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function applicationGenerator(tree: Tree, schema: Schema) {
|
export async function applicationGenerator(tree: Tree, schema: Schema) {
|
||||||
@ -313,9 +328,8 @@ export async function applicationGenerator(tree: Tree, schema: Schema) {
|
|||||||
addProjectDependencies(tree, options);
|
addProjectDependencies(tree, options);
|
||||||
addAppFiles(tree, options);
|
addAppFiles(tree, options);
|
||||||
addProject(tree, options);
|
addProject(tree, options);
|
||||||
if (options.framework && options?.bundler === 'esbuild') {
|
|
||||||
updateTsConfigOptions(tree, options);
|
updateTsConfigOptions(tree, options);
|
||||||
}
|
|
||||||
|
|
||||||
if (options.linter !== Linter.None) {
|
if (options.linter !== Linter.None) {
|
||||||
const lintTask = await addLintingToApplication(tree, {
|
const lintTask = await addLintingToApplication(tree, {
|
||||||
@ -365,7 +379,11 @@ function normalizeOptions(host: Tree, options: Schema): NormalizedSchema {
|
|||||||
|
|
||||||
const appProjectName = appDirectory.replace(new RegExp('/', 'g'), '-');
|
const appProjectName = appDirectory.replace(new RegExp('/', 'g'), '-');
|
||||||
|
|
||||||
const appProjectRoot = joinPathFragments(appsDir, appDirectory);
|
const appProjectRoot = options.rootProject
|
||||||
|
? '.'
|
||||||
|
: joinPathFragments(appsDir, appDirectory);
|
||||||
|
|
||||||
|
options.bundler = options.bundler ?? 'esbuild';
|
||||||
|
|
||||||
const parsedTags = options.tags
|
const parsedTags = options.tags
|
||||||
? options.tags.split(',').map((s) => s.trim())
|
? options.tags.split(',').map((s) => s.trim())
|
||||||
|
|||||||
@ -17,6 +17,7 @@ export interface Schema {
|
|||||||
bundler?: 'esbuild' | 'webpack';
|
bundler?: 'esbuild' | 'webpack';
|
||||||
framework?: NodeJsFrameWorks;
|
framework?: NodeJsFrameWorks;
|
||||||
port?: number;
|
port?: number;
|
||||||
|
rootProject?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export type NodeJsFrameWorks = 'express' | 'koa' | 'fastify' | 'connect';
|
export type NodeJsFrameWorks = 'express' | 'koa' | 'fastify' | 'connect';
|
||||||
|
|||||||
@ -89,6 +89,12 @@
|
|||||||
"description": "The port which the server will be run on",
|
"description": "The port which the server will be run on",
|
||||||
"type": "number",
|
"type": "number",
|
||||||
"default": 3000
|
"default": 3000
|
||||||
|
},
|
||||||
|
"rootProject": {
|
||||||
|
"description": "Create node application at the root of the workspace",
|
||||||
|
"type": "boolean",
|
||||||
|
"default": false,
|
||||||
|
"hidden": true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"required": []
|
"required": []
|
||||||
|
|||||||
@ -230,6 +230,31 @@ Visit the [Nx Documentation](https://nx.dev) to learn more.
|
|||||||
"
|
"
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
exports[`@nrwl/workspace:generateWorkspaceFiles README.md should be created for NodeServer preset 1`] = `
|
||||||
|
"# Proj
|
||||||
|
|
||||||
|
<a href=\\"https://nx.dev\\" target=\\"_blank\\" rel=\\"noreferrer\\"><img src=\\"https://raw.githubusercontent.com/nrwl/nx/master/images/nx-logo.png\\" width=\\"45\\"></a>
|
||||||
|
|
||||||
|
✨ **This workspace has been generated by [Nx, a Smart, fast and extensible build system.](https://nx.dev)** ✨
|
||||||
|
|
||||||
|
## Development server
|
||||||
|
|
||||||
|
Run \`nx serve app1\` 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.
|
||||||
|
|
||||||
|
## 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[`@nrwl/workspace:generateWorkspaceFiles README.md should be created for ReactMonorepo preset 1`] = `
|
exports[`@nrwl/workspace:generateWorkspaceFiles README.md should be created for ReactMonorepo preset 1`] = `
|
||||||
"# Proj
|
"# Proj
|
||||||
|
|
||||||
|
|||||||
@ -73,6 +73,7 @@ export function generatePreset(host: Tree, opts: NormalizedSchema) {
|
|||||||
opts.linter ? `--linter=${opts.linter}` : null,
|
opts.linter ? `--linter=${opts.linter}` : null,
|
||||||
opts.npmScope ? `--npmScope=${opts.npmScope}` : `--npmScope=${opts.name}`,
|
opts.npmScope ? `--npmScope=${opts.npmScope}` : `--npmScope=${opts.name}`,
|
||||||
opts.preset ? `--preset=${opts.preset}` : null,
|
opts.preset ? `--preset=${opts.preset}` : null,
|
||||||
|
opts.framework ? `--framework=${opts.framework}` : null,
|
||||||
opts.packageManager ? `--packageManager=${opts.packageManager}` : null,
|
opts.packageManager ? `--packageManager=${opts.packageManager}` : null,
|
||||||
parsedArgs.interactive ? '--interactive=true' : '--interactive=false',
|
parsedArgs.interactive ? '--interactive=true' : '--interactive=false',
|
||||||
].filter((e) => !!e);
|
].filter((e) => !!e);
|
||||||
@ -112,6 +113,9 @@ function getPresetDependencies(preset: string, version?: string) {
|
|||||||
case Preset.WebComponents:
|
case Preset.WebComponents:
|
||||||
return { dependencies: {}, dev: { '@nrwl/web': nxVersion } };
|
return { dependencies: {}, dev: { '@nrwl/web': nxVersion } };
|
||||||
|
|
||||||
|
case Preset.NodeServer:
|
||||||
|
return { dependencies: {}, dev: { '@nrwl/node': nxVersion } };
|
||||||
|
|
||||||
default: {
|
default: {
|
||||||
return {
|
return {
|
||||||
dev: {},
|
dev: {},
|
||||||
|
|||||||
@ -42,6 +42,7 @@ describe('@nrwl/workspace:generateWorkspaceFiles', () => {
|
|||||||
Preset.NextJs,
|
Preset.NextJs,
|
||||||
Preset.WebComponents,
|
Preset.WebComponents,
|
||||||
Preset.Express,
|
Preset.Express,
|
||||||
|
Preset.NodeServer,
|
||||||
].includes(Preset[preset])
|
].includes(Preset[preset])
|
||||||
) {
|
) {
|
||||||
appName = 'app1';
|
appName = 'app1';
|
||||||
|
|||||||
@ -76,7 +76,8 @@ function createAppsAndLibsFolders(tree: Tree, options: NormalizedSchema) {
|
|||||||
tree.write(join(options.directory, 'packages/.gitkeep'), '');
|
tree.write(join(options.directory, 'packages/.gitkeep'), '');
|
||||||
} else if (
|
} else if (
|
||||||
options.preset === Preset.AngularStandalone ||
|
options.preset === Preset.AngularStandalone ||
|
||||||
options.preset === Preset.ReactStandalone
|
options.preset === Preset.ReactStandalone ||
|
||||||
|
options.preset === Preset.NodeServer
|
||||||
) {
|
) {
|
||||||
// don't generate any folders
|
// don't generate any folders
|
||||||
} else {
|
} else {
|
||||||
@ -134,7 +135,8 @@ function createFiles(tree: Tree, options: NormalizedSchema) {
|
|||||||
const formattedNames = names(options.name);
|
const formattedNames = names(options.name);
|
||||||
const filesDirName =
|
const filesDirName =
|
||||||
options.preset === Preset.AngularStandalone ||
|
options.preset === Preset.AngularStandalone ||
|
||||||
options.preset === Preset.ReactStandalone
|
options.preset === Preset.ReactStandalone ||
|
||||||
|
options.preset === Preset.NodeServer
|
||||||
? './files-root-app'
|
? './files-root-app'
|
||||||
: options.preset === Preset.NPM || options.preset === Preset.Core
|
: options.preset === Preset.NPM || options.preset === Preset.Core
|
||||||
? './files-package-based-repo'
|
? './files-package-based-repo'
|
||||||
@ -196,7 +198,8 @@ function createYarnrcYml(tree: Tree, options: NormalizedSchema) {
|
|||||||
function addNpmScripts(tree: Tree, options: NormalizedSchema) {
|
function addNpmScripts(tree: Tree, options: NormalizedSchema) {
|
||||||
if (
|
if (
|
||||||
options.preset === Preset.AngularStandalone ||
|
options.preset === Preset.AngularStandalone ||
|
||||||
options.preset === Preset.ReactStandalone
|
options.preset === Preset.ReactStandalone ||
|
||||||
|
options.preset === Preset.NodeServer
|
||||||
) {
|
) {
|
||||||
updateJson(tree, join(options.directory, 'package.json'), (json) => {
|
updateJson(tree, join(options.directory, 'package.json'), (json) => {
|
||||||
Object.assign(json.scripts, {
|
Object.assign(json.scripts, {
|
||||||
|
|||||||
@ -24,6 +24,7 @@ interface Schema {
|
|||||||
nxCloud?: boolean;
|
nxCloud?: boolean;
|
||||||
preset: string;
|
preset: string;
|
||||||
defaultBase: string;
|
defaultBase: string;
|
||||||
|
framework?: string;
|
||||||
linter?: Linter;
|
linter?: Linter;
|
||||||
packageManager?: PackageManager;
|
packageManager?: PackageManager;
|
||||||
}
|
}
|
||||||
@ -74,6 +75,12 @@ function validateOptions(options: Schema, host: Tree) {
|
|||||||
throw new Error(`Cannot select nxCloud when skipInstall is set to true.`);
|
throw new Error(`Cannot select nxCloud when skipInstall is set to true.`);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (options.preset === Preset.NodeServer && !options.framework) {
|
||||||
|
throw new Error(
|
||||||
|
`Cannot generate ${options.preset} without selecting a framework`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
if (devkitGetWorkspacePath(host)) {
|
if (devkitGetWorkspacePath(host)) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
'Cannot generate a new workspace within an existing workspace'
|
'Cannot generate a new workspace within an existing workspace'
|
||||||
|
|||||||
@ -62,6 +62,11 @@
|
|||||||
"description": "The package manager used to install dependencies.",
|
"description": "The package manager used to install dependencies.",
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"enum": ["npm", "yarn", "pnpm"]
|
"enum": ["npm", "yarn", "pnpm"]
|
||||||
|
},
|
||||||
|
"framework": {
|
||||||
|
"description": "The framework which the application is using",
|
||||||
|
"type": "string",
|
||||||
|
"enum": ["express", "koa", "fastify", "connect"]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"additionalProperties": true
|
"additionalProperties": true
|
||||||
|
|||||||
@ -134,6 +134,16 @@ async function createPreset(tree: Tree, options: Schema) {
|
|||||||
libsDir: 'packages',
|
libsDir: 'packages',
|
||||||
};
|
};
|
||||||
updateNxJson(tree, c);
|
updateNxJson(tree, c);
|
||||||
|
} else if (options.preset === Preset.NodeServer) {
|
||||||
|
const { applicationGenerator: nodeApplicationGenerator } = require('@nrwl' +
|
||||||
|
'/node');
|
||||||
|
await nodeApplicationGenerator(tree, {
|
||||||
|
name: options.name,
|
||||||
|
linter: options.linter,
|
||||||
|
standaloneConfig: options.standaloneConfig,
|
||||||
|
framework: options.framework,
|
||||||
|
rootProject: true,
|
||||||
|
});
|
||||||
} else {
|
} else {
|
||||||
throw new Error(`Invalid preset ${options.preset}`);
|
throw new Error(`Invalid preset ${options.preset}`);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -9,5 +9,6 @@ export interface Schema {
|
|||||||
linter?: string;
|
linter?: string;
|
||||||
preset: Preset;
|
preset: Preset;
|
||||||
standaloneConfig?: boolean;
|
standaloneConfig?: boolean;
|
||||||
|
framework?: string;
|
||||||
packageManager?: PackageManager;
|
packageManager?: PackageManager;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -63,6 +63,11 @@
|
|||||||
"description": "The package manager used to install dependencies.",
|
"description": "The package manager used to install dependencies.",
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"enum": ["npm", "yarn", "pnpm"]
|
"enum": ["npm", "yarn", "pnpm"]
|
||||||
|
},
|
||||||
|
"framework": {
|
||||||
|
"description": "The framework which the application is using",
|
||||||
|
"type": "string",
|
||||||
|
"enum": ["express", "koa", "fastify", "connect"]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -14,4 +14,5 @@ export enum Preset {
|
|||||||
NextJs = 'next',
|
NextJs = 'next',
|
||||||
Nest = 'nest',
|
Nest = 'nest',
|
||||||
Express = 'express',
|
Express = 'express',
|
||||||
|
NodeServer = 'node-server',
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user