feat(node): support nodejs frameworks (#14199)
This commit is contained in:
parent
3db0bf8a18
commit
a631af7b62
@ -73,6 +73,22 @@
|
||||
"standaloneConfig": {
|
||||
"description": "Split the project configuration into `<projectRoot>/project.json` rather than including it inside `workspace.json`.",
|
||||
"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": [],
|
||||
|
||||
@ -38,6 +38,7 @@
|
||||
"@nrwl/webpack": "file:../webpack",
|
||||
"@nrwl/workspace": "file:../workspace",
|
||||
"chalk": "4.1.0",
|
||||
"enquirer": "~2.3.6",
|
||||
"tslib": "^2.3.0"
|
||||
},
|
||||
"publishConfig": {
|
||||
|
||||
@ -59,12 +59,6 @@ describe('app', () => {
|
||||
optimization: true,
|
||||
extractLicenses: true,
|
||||
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;
|
||||
|
||||
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 () => {
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
import {
|
||||
addDependenciesToPackageJson,
|
||||
addProjectConfiguration,
|
||||
convertNxGenerator,
|
||||
extractLayoutDirectory,
|
||||
@ -15,6 +16,7 @@ import {
|
||||
TargetConfiguration,
|
||||
toJS,
|
||||
Tree,
|
||||
updateJson,
|
||||
updateProjectConfiguration,
|
||||
updateTsConfigsToJs,
|
||||
} from '@nrwl/devkit';
|
||||
@ -28,18 +30,30 @@ import { runTasksInSerial } from '@nrwl/workspace/src/utilities/run-tasks-in-ser
|
||||
import { Schema } from './schema';
|
||||
import { initGenerator } from '../init/init';
|
||||
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 {
|
||||
appProjectRoot: string;
|
||||
parsedTags: string[];
|
||||
}
|
||||
|
||||
function getBuildConfig(
|
||||
function getWebpackBuildConfig(
|
||||
project: ProjectConfiguration,
|
||||
options: NormalizedSchema
|
||||
): TargetConfiguration {
|
||||
return {
|
||||
executor: '@nrwl/webpack:webpack',
|
||||
executor: `@nrwl/webpack:webpack`,
|
||||
outputs: ['{options.outputPath}'],
|
||||
options: {
|
||||
target: 'node',
|
||||
@ -57,19 +71,27 @@ function getBuildConfig(
|
||||
optimization: true,
|
||||
extractLicenses: true,
|
||||
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')],
|
||||
},
|
||||
};
|
||||
}
|
||||
@ -96,7 +118,10 @@ function addProject(tree: Tree, options: NormalizedSchema) {
|
||||
targets: {},
|
||||
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);
|
||||
|
||||
addProjectConfiguration(
|
||||
@ -108,7 +133,12 @@ function addProject(tree: Tree, options: NormalizedSchema) {
|
||||
}
|
||||
|
||||
function addAppFiles(tree: Tree, options: NormalizedSchema) {
|
||||
generateFiles(tree, join(__dirname, './files/app'), options.appProjectRoot, {
|
||||
generateFiles(
|
||||
tree,
|
||||
join(__dirname, './files/common'),
|
||||
options.appProjectRoot,
|
||||
{
|
||||
...options,
|
||||
tmpl: '',
|
||||
name: options.name,
|
||||
root: options.appProjectRoot,
|
||||
@ -117,7 +147,27 @@ function addAppFiles(tree: Tree, options: NormalizedSchema) {
|
||||
tree,
|
||||
options.appProjectRoot
|
||||
),
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
if (options.framework) {
|
||||
generateFiles(
|
||||
tree,
|
||||
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) {
|
||||
toJS(tree);
|
||||
}
|
||||
@ -189,7 +239,73 @@ export async function addLintingToApplication(
|
||||
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) {
|
||||
// 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 tasks: GeneratorCallback[] = [];
|
||||
@ -199,8 +315,12 @@ export async function applicationGenerator(tree: Tree, schema: Schema) {
|
||||
});
|
||||
tasks.push(initTask);
|
||||
|
||||
addProjectDependencies(tree, options);
|
||||
addAppFiles(tree, options);
|
||||
addProject(tree, options);
|
||||
if (options.framework && options?.bundler === 'esbuild') {
|
||||
updateTsConfigOptions(tree, options);
|
||||
}
|
||||
|
||||
if (options.linter !== Linter.None) {
|
||||
const lintTask = await addLintingToApplication(tree, {
|
||||
@ -251,6 +371,11 @@ function normalizeOptions(host: Tree, options: Schema): NormalizedSchema {
|
||||
const appProjectName = appDirectory.replace(new RegExp('/', 'g'), '-');
|
||||
|
||||
const appProjectRoot = joinPathFragments(appsDir, appDirectory);
|
||||
if (options.framework) {
|
||||
options.bundler = options.bundler ?? 'esbuild';
|
||||
} else {
|
||||
options.bundler = 'webpack';
|
||||
}
|
||||
|
||||
const parsedTags = options.tags
|
||||
? options.tags.split(',').map((s) => s.trim())
|
||||
@ -266,6 +391,7 @@ function normalizeOptions(host: Tree, options: Schema): NormalizedSchema {
|
||||
parsedTags,
|
||||
linter: options.linter ?? Linter.EsLint,
|
||||
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;
|
||||
setParserOptionsProject?: boolean;
|
||||
standaloneConfig?: boolean;
|
||||
bundler?: 'esbuild' | 'webpack';
|
||||
framework?: NodeJsFrameWorks;
|
||||
port?: number;
|
||||
}
|
||||
|
||||
export type NodeJsFrameWorks = 'express' | 'koa' | 'fastify' | 'connect';
|
||||
|
||||
@ -73,6 +73,22 @@
|
||||
"standaloneConfig": {
|
||||
"description": "Split the project configuration into `<projectRoot>/project.json` rather than including it inside `workspace.json`.",
|
||||
"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": []
|
||||
|
||||
@ -3,3 +3,16 @@ export const nxVersion = require('../../package.json').version;
|
||||
export const tslibVersion = '^2.3.0';
|
||||
|
||||
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