feat(node): support nodejs frameworks (#14199)
This commit is contained in:
parent
3db0bf8a18
commit
a631af7b62
@ -73,6 +73,22 @@
|
|||||||
"standaloneConfig": {
|
"standaloneConfig": {
|
||||||
"description": "Split the project configuration into `<projectRoot>/project.json` rather than including it inside `workspace.json`.",
|
"description": "Split the project configuration into `<projectRoot>/project.json` rather than including it inside `workspace.json`.",
|
||||||
"type": "boolean"
|
"type": "boolean"
|
||||||
|
},
|
||||||
|
"bundler": {
|
||||||
|
"description": "Bundler which is used to package the application",
|
||||||
|
"type": "string",
|
||||||
|
"enum": ["esbuild", "webpack"],
|
||||||
|
"default": "esbuild"
|
||||||
|
},
|
||||||
|
"framework": {
|
||||||
|
"description": "Generate the node application using a framework",
|
||||||
|
"type": "string",
|
||||||
|
"enum": ["express", "koa", "fastify", "connect"]
|
||||||
|
},
|
||||||
|
"port": {
|
||||||
|
"description": "The port which the server will be run on",
|
||||||
|
"type": "number",
|
||||||
|
"default": 3000
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"required": [],
|
"required": [],
|
||||||
|
|||||||
@ -38,6 +38,7 @@
|
|||||||
"@nrwl/webpack": "file:../webpack",
|
"@nrwl/webpack": "file:../webpack",
|
||||||
"@nrwl/workspace": "file:../workspace",
|
"@nrwl/workspace": "file:../workspace",
|
||||||
"chalk": "4.1.0",
|
"chalk": "4.1.0",
|
||||||
|
"enquirer": "~2.3.6",
|
||||||
"tslib": "^2.3.0"
|
"tslib": "^2.3.0"
|
||||||
},
|
},
|
||||||
"publishConfig": {
|
"publishConfig": {
|
||||||
|
|||||||
@ -59,12 +59,6 @@ describe('app', () => {
|
|||||||
optimization: true,
|
optimization: true,
|
||||||
extractLicenses: true,
|
extractLicenses: true,
|
||||||
inspect: false,
|
inspect: false,
|
||||||
fileReplacements: [
|
|
||||||
{
|
|
||||||
replace: 'apps/my-node-app/src/environments/environment.ts',
|
|
||||||
with: 'apps/my-node-app/src/environments/environment.prod.ts',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -434,12 +428,6 @@ describe('app', () => {
|
|||||||
const buildTarget = project.architect.build;
|
const buildTarget = project.architect.build;
|
||||||
|
|
||||||
expect(buildTarget.options.main).toEqual('apps/my-node-app/src/main.js');
|
expect(buildTarget.options.main).toEqual('apps/my-node-app/src/main.js');
|
||||||
expect(buildTarget.configurations.production.fileReplacements).toEqual([
|
|
||||||
{
|
|
||||||
replace: 'apps/my-node-app/src/environments/environment.js',
|
|
||||||
with: 'apps/my-node-app/src/environments/environment.prod.js',
|
|
||||||
},
|
|
||||||
]);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should generate js files for nested libs as well', async () => {
|
it('should generate js files for nested libs as well', async () => {
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
import {
|
import {
|
||||||
|
addDependenciesToPackageJson,
|
||||||
addProjectConfiguration,
|
addProjectConfiguration,
|
||||||
convertNxGenerator,
|
convertNxGenerator,
|
||||||
extractLayoutDirectory,
|
extractLayoutDirectory,
|
||||||
@ -15,6 +16,7 @@ import {
|
|||||||
TargetConfiguration,
|
TargetConfiguration,
|
||||||
toJS,
|
toJS,
|
||||||
Tree,
|
Tree,
|
||||||
|
updateJson,
|
||||||
updateProjectConfiguration,
|
updateProjectConfiguration,
|
||||||
updateTsConfigsToJs,
|
updateTsConfigsToJs,
|
||||||
} from '@nrwl/devkit';
|
} from '@nrwl/devkit';
|
||||||
@ -28,18 +30,30 @@ import { runTasksInSerial } from '@nrwl/workspace/src/utilities/run-tasks-in-ser
|
|||||||
import { Schema } from './schema';
|
import { 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 {
|
||||||
|
connectTypingsVersion,
|
||||||
|
connectVersion,
|
||||||
|
esbuildVersion,
|
||||||
|
expressTypingsVersion,
|
||||||
|
expressVersion,
|
||||||
|
fastifyVersion,
|
||||||
|
koaTypingsVersion,
|
||||||
|
koaVersion,
|
||||||
|
nxVersion,
|
||||||
|
} from '../../utils/versions';
|
||||||
|
import { prompt } from 'enquirer';
|
||||||
|
|
||||||
export interface NormalizedSchema extends Schema {
|
export interface NormalizedSchema extends Schema {
|
||||||
appProjectRoot: string;
|
appProjectRoot: string;
|
||||||
parsedTags: string[];
|
parsedTags: string[];
|
||||||
}
|
}
|
||||||
|
|
||||||
function getBuildConfig(
|
function getWebpackBuildConfig(
|
||||||
project: ProjectConfiguration,
|
project: ProjectConfiguration,
|
||||||
options: NormalizedSchema
|
options: NormalizedSchema
|
||||||
): TargetConfiguration {
|
): TargetConfiguration {
|
||||||
return {
|
return {
|
||||||
executor: '@nrwl/webpack:webpack',
|
executor: `@nrwl/webpack:webpack`,
|
||||||
outputs: ['{options.outputPath}'],
|
outputs: ['{options.outputPath}'],
|
||||||
options: {
|
options: {
|
||||||
target: 'node',
|
target: 'node',
|
||||||
@ -57,23 +71,31 @@ function getBuildConfig(
|
|||||||
optimization: true,
|
optimization: true,
|
||||||
extractLicenses: true,
|
extractLicenses: true,
|
||||||
inspect: false,
|
inspect: false,
|
||||||
fileReplacements: [
|
|
||||||
{
|
|
||||||
replace: joinPathFragments(
|
|
||||||
project.sourceRoot,
|
|
||||||
'environments/environment' + (options.js ? '.js' : '.ts')
|
|
||||||
),
|
|
||||||
with: joinPathFragments(
|
|
||||||
project.sourceRoot,
|
|
||||||
'environments/environment.prod' + (options.js ? '.js' : '.ts')
|
|
||||||
),
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getEsBuildConfig(
|
||||||
|
project: ProjectConfiguration,
|
||||||
|
options: NormalizedSchema
|
||||||
|
): TargetConfiguration {
|
||||||
|
return {
|
||||||
|
executor: '@nrwl/esbuild:esbuild',
|
||||||
|
outputs: ['{options.outputPath}'],
|
||||||
|
options: {
|
||||||
|
outputPath: joinPathFragments('dist', options.appProjectRoot),
|
||||||
|
format: ['cjs'],
|
||||||
|
main: joinPathFragments(
|
||||||
|
project.sourceRoot,
|
||||||
|
'main' + (options.js ? '.js' : '.ts')
|
||||||
|
),
|
||||||
|
tsConfig: joinPathFragments(options.appProjectRoot, 'tsconfig.app.json'),
|
||||||
|
assets: [joinPathFragments(project.sourceRoot, 'assets')],
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
function getServeConfig(options: NormalizedSchema): TargetConfiguration {
|
function getServeConfig(options: NormalizedSchema): TargetConfiguration {
|
||||||
return {
|
return {
|
||||||
executor: '@nrwl/js:node',
|
executor: '@nrwl/js:node',
|
||||||
@ -96,7 +118,10 @@ function addProject(tree: Tree, options: NormalizedSchema) {
|
|||||||
targets: {},
|
targets: {},
|
||||||
tags: options.parsedTags,
|
tags: options.parsedTags,
|
||||||
};
|
};
|
||||||
project.targets.build = getBuildConfig(project, options);
|
project.targets.build =
|
||||||
|
options.bundler === 'esbuild'
|
||||||
|
? getEsBuildConfig(project, options)
|
||||||
|
: getWebpackBuildConfig(project, options);
|
||||||
project.targets.serve = getServeConfig(options);
|
project.targets.serve = getServeConfig(options);
|
||||||
|
|
||||||
addProjectConfiguration(
|
addProjectConfiguration(
|
||||||
@ -108,16 +133,41 @@ function addProject(tree: Tree, options: NormalizedSchema) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function addAppFiles(tree: Tree, options: NormalizedSchema) {
|
function addAppFiles(tree: Tree, options: NormalizedSchema) {
|
||||||
generateFiles(tree, join(__dirname, './files/app'), options.appProjectRoot, {
|
generateFiles(
|
||||||
tmpl: '',
|
tree,
|
||||||
name: options.name,
|
join(__dirname, './files/common'),
|
||||||
root: options.appProjectRoot,
|
options.appProjectRoot,
|
||||||
offset: offsetFromRoot(options.appProjectRoot),
|
{
|
||||||
rootTsConfigPath: getRelativePathToRootTsConfig(
|
...options,
|
||||||
|
tmpl: '',
|
||||||
|
name: options.name,
|
||||||
|
root: options.appProjectRoot,
|
||||||
|
offset: offsetFromRoot(options.appProjectRoot),
|
||||||
|
rootTsConfigPath: getRelativePathToRootTsConfig(
|
||||||
|
tree,
|
||||||
|
options.appProjectRoot
|
||||||
|
),
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
if (options.framework) {
|
||||||
|
generateFiles(
|
||||||
tree,
|
tree,
|
||||||
options.appProjectRoot
|
join(__dirname, `./files/${options.framework}`),
|
||||||
),
|
options.appProjectRoot,
|
||||||
});
|
{
|
||||||
|
...options,
|
||||||
|
tmpl: '',
|
||||||
|
name: options.name,
|
||||||
|
root: options.appProjectRoot,
|
||||||
|
offset: offsetFromRoot(options.appProjectRoot),
|
||||||
|
rootTsConfigPath: getRelativePathToRootTsConfig(
|
||||||
|
tree,
|
||||||
|
options.appProjectRoot
|
||||||
|
),
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
if (options.js) {
|
if (options.js) {
|
||||||
toJS(tree);
|
toJS(tree);
|
||||||
}
|
}
|
||||||
@ -189,7 +239,73 @@ export async function addLintingToApplication(
|
|||||||
return lintTask;
|
return lintTask;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function addProjectDependencies(
|
||||||
|
tree: Tree,
|
||||||
|
options: NormalizedSchema
|
||||||
|
): GeneratorCallback {
|
||||||
|
const bundlers = {
|
||||||
|
webpack: {
|
||||||
|
'@nrwl/webpack': nxVersion,
|
||||||
|
},
|
||||||
|
esbuild: {
|
||||||
|
'@nrwl/esbuild': nxVersion,
|
||||||
|
esbuild: esbuildVersion,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const frameworkDependencies = {
|
||||||
|
express: {
|
||||||
|
express: expressVersion,
|
||||||
|
'@types/express': expressTypingsVersion,
|
||||||
|
},
|
||||||
|
koa: {
|
||||||
|
koa: koaVersion,
|
||||||
|
'@types/koa': koaTypingsVersion,
|
||||||
|
},
|
||||||
|
fastify: {
|
||||||
|
fastify: fastifyVersion,
|
||||||
|
},
|
||||||
|
connect: {
|
||||||
|
connect: connectVersion,
|
||||||
|
'@types/connect': connectTypingsVersion,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
return addDependenciesToPackageJson(
|
||||||
|
tree,
|
||||||
|
{},
|
||||||
|
{
|
||||||
|
...frameworkDependencies[options.framework],
|
||||||
|
...bundlers[options.bundler],
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
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.app.json`, (json) => ({
|
||||||
|
...json,
|
||||||
|
compilerOptions: {
|
||||||
|
...json.compilerOptions,
|
||||||
|
esModuleInterop: true,
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
export async function applicationGenerator(tree: Tree, schema: Schema) {
|
export async function applicationGenerator(tree: Tree, schema: Schema) {
|
||||||
|
// Prompt for bundler webpack / esbuild
|
||||||
|
if (schema.framework) {
|
||||||
|
schema.bundler = (
|
||||||
|
await prompt<{ bundler: 'esbuild' | 'webpack' }>([
|
||||||
|
{
|
||||||
|
message: 'What bundler would you like to use?',
|
||||||
|
type: 'select',
|
||||||
|
name: 'bundler',
|
||||||
|
choices: ['esbuild', 'webpack'],
|
||||||
|
},
|
||||||
|
])
|
||||||
|
).bundler;
|
||||||
|
}
|
||||||
|
|
||||||
const options = normalizeOptions(tree, schema);
|
const options = normalizeOptions(tree, schema);
|
||||||
|
|
||||||
const tasks: GeneratorCallback[] = [];
|
const tasks: GeneratorCallback[] = [];
|
||||||
@ -199,8 +315,12 @@ export async function applicationGenerator(tree: Tree, schema: Schema) {
|
|||||||
});
|
});
|
||||||
tasks.push(initTask);
|
tasks.push(initTask);
|
||||||
|
|
||||||
|
addProjectDependencies(tree, options);
|
||||||
addAppFiles(tree, options);
|
addAppFiles(tree, options);
|
||||||
addProject(tree, options);
|
addProject(tree, options);
|
||||||
|
if (options.framework && options?.bundler === 'esbuild') {
|
||||||
|
updateTsConfigOptions(tree, options);
|
||||||
|
}
|
||||||
|
|
||||||
if (options.linter !== Linter.None) {
|
if (options.linter !== Linter.None) {
|
||||||
const lintTask = await addLintingToApplication(tree, {
|
const lintTask = await addLintingToApplication(tree, {
|
||||||
@ -251,6 +371,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 = joinPathFragments(appsDir, appDirectory);
|
||||||
|
if (options.framework) {
|
||||||
|
options.bundler = options.bundler ?? 'esbuild';
|
||||||
|
} else {
|
||||||
|
options.bundler = 'webpack';
|
||||||
|
}
|
||||||
|
|
||||||
const parsedTags = options.tags
|
const parsedTags = options.tags
|
||||||
? options.tags.split(',').map((s) => s.trim())
|
? options.tags.split(',').map((s) => s.trim())
|
||||||
@ -266,6 +391,7 @@ function normalizeOptions(host: Tree, options: Schema): NormalizedSchema {
|
|||||||
parsedTags,
|
parsedTags,
|
||||||
linter: options.linter ?? Linter.EsLint,
|
linter: options.linter ?? Linter.EsLint,
|
||||||
unitTestRunner: options.unitTestRunner ?? 'jest',
|
unitTestRunner: options.unitTestRunner ?? 'jest',
|
||||||
|
port: options.port ?? 3000,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,3 +0,0 @@
|
|||||||
export const environment = {
|
|
||||||
production: true
|
|
||||||
};
|
|
||||||
@ -1,3 +0,0 @@
|
|||||||
export const environment = {
|
|
||||||
production: false
|
|
||||||
};
|
|
||||||
@ -1 +0,0 @@
|
|||||||
console.log('Hello World!');
|
|
||||||
@ -0,0 +1 @@
|
|||||||
|
console.log('Hello World');
|
||||||
@ -0,0 +1,11 @@
|
|||||||
|
import express from 'express';
|
||||||
|
const app = express();
|
||||||
|
|
||||||
|
|
||||||
|
app.get('/', (req, res) => {
|
||||||
|
res.send('Hello from Nrwl 🐳 API');
|
||||||
|
});
|
||||||
|
|
||||||
|
app.listen(<%= port %>, () => {
|
||||||
|
// Server is running
|
||||||
|
});
|
||||||
@ -14,4 +14,9 @@ export interface Schema {
|
|||||||
pascalCaseFiles?: boolean;
|
pascalCaseFiles?: boolean;
|
||||||
setParserOptionsProject?: boolean;
|
setParserOptionsProject?: boolean;
|
||||||
standaloneConfig?: boolean;
|
standaloneConfig?: boolean;
|
||||||
|
bundler?: 'esbuild' | 'webpack';
|
||||||
|
framework?: NodeJsFrameWorks;
|
||||||
|
port?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type NodeJsFrameWorks = 'express' | 'koa' | 'fastify' | 'connect';
|
||||||
|
|||||||
@ -73,6 +73,22 @@
|
|||||||
"standaloneConfig": {
|
"standaloneConfig": {
|
||||||
"description": "Split the project configuration into `<projectRoot>/project.json` rather than including it inside `workspace.json`.",
|
"description": "Split the project configuration into `<projectRoot>/project.json` rather than including it inside `workspace.json`.",
|
||||||
"type": "boolean"
|
"type": "boolean"
|
||||||
|
},
|
||||||
|
"bundler": {
|
||||||
|
"description": "Bundler which is used to package the application",
|
||||||
|
"type": "string",
|
||||||
|
"enum": ["esbuild", "webpack"],
|
||||||
|
"default": "esbuild"
|
||||||
|
},
|
||||||
|
"framework": {
|
||||||
|
"description": "Generate the node application using a framework",
|
||||||
|
"type": "string",
|
||||||
|
"enum": ["express", "koa", "fastify", "connect"]
|
||||||
|
},
|
||||||
|
"port": {
|
||||||
|
"description": "The port which the server will be run on",
|
||||||
|
"type": "number",
|
||||||
|
"default": 3000
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"required": []
|
"required": []
|
||||||
|
|||||||
@ -3,3 +3,16 @@ export const nxVersion = require('../../package.json').version;
|
|||||||
export const tslibVersion = '^2.3.0';
|
export const tslibVersion = '^2.3.0';
|
||||||
|
|
||||||
export const typesNodeVersion = '18.7.1';
|
export const typesNodeVersion = '18.7.1';
|
||||||
|
|
||||||
|
export const esbuildVersion = '^0.15.7';
|
||||||
|
|
||||||
|
export const expressVersion = '^4.18.1';
|
||||||
|
export const expressTypingsVersion = '4.17.13';
|
||||||
|
|
||||||
|
export const koaVersion = '2.14.1';
|
||||||
|
export const koaTypingsVersion = '2.13.5';
|
||||||
|
|
||||||
|
export const fastifyVersion = '4.11.0';
|
||||||
|
|
||||||
|
export const connectVersion = '3.7.0';
|
||||||
|
export const connectTypingsVersion = '3.4.35';
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user