279 lines
7.3 KiB
TypeScript
279 lines
7.3 KiB
TypeScript
import {
|
|
addProjectConfiguration,
|
|
convertNxGenerator,
|
|
formatFiles,
|
|
generateFiles,
|
|
GeneratorCallback,
|
|
getWorkspaceLayout,
|
|
joinPathFragments,
|
|
logger,
|
|
names,
|
|
offsetFromRoot,
|
|
ProjectConfiguration,
|
|
readProjectConfiguration,
|
|
readWorkspaceConfiguration,
|
|
TargetConfiguration,
|
|
toJS,
|
|
Tree,
|
|
updateProjectConfiguration,
|
|
updateTsConfigsToJs,
|
|
updateWorkspaceConfiguration,
|
|
} from '@nrwl/devkit';
|
|
|
|
import { join } from 'path';
|
|
|
|
import { Linter, lintProjectGenerator } from '@nrwl/linter';
|
|
import { jestProjectGenerator } from '@nrwl/jest';
|
|
import { runTasksInSerial } from '@nrwl/workspace/src/utilities/run-tasks-in-serial';
|
|
|
|
import { Schema } from './schema';
|
|
import { initGenerator } from '../init/init';
|
|
import { getRelativePathToRootTsConfig } from '@nrwl/workspace/src/utilities/typescript';
|
|
|
|
export interface NormalizedSchema extends Schema {
|
|
appProjectRoot: string;
|
|
parsedTags: string[];
|
|
}
|
|
|
|
function getBuildConfig(
|
|
project: ProjectConfiguration,
|
|
options: NormalizedSchema
|
|
): TargetConfiguration {
|
|
return {
|
|
executor: '@nrwl/webpack:webpack',
|
|
outputs: ['{options.outputPath}'],
|
|
options: {
|
|
target: 'node',
|
|
compiler: 'tsc',
|
|
outputPath: joinPathFragments('dist', options.appProjectRoot),
|
|
main: joinPathFragments(
|
|
project.sourceRoot,
|
|
'main' + (options.js ? '.js' : '.ts')
|
|
),
|
|
tsConfig: joinPathFragments(options.appProjectRoot, 'tsconfig.app.json'),
|
|
assets: [joinPathFragments(project.sourceRoot, 'assets')],
|
|
},
|
|
configurations: {
|
|
production: {
|
|
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 getServeConfig(options: NormalizedSchema): TargetConfiguration {
|
|
return {
|
|
executor: '@nrwl/js:node',
|
|
options: {
|
|
buildTarget: `${options.name}:build`,
|
|
},
|
|
configurations: {
|
|
production: {
|
|
buildTarget: `${options.name}:build:production`,
|
|
},
|
|
},
|
|
};
|
|
}
|
|
|
|
function addProject(tree: Tree, options: NormalizedSchema) {
|
|
const project: ProjectConfiguration = {
|
|
root: options.appProjectRoot,
|
|
sourceRoot: joinPathFragments(options.appProjectRoot, 'src'),
|
|
projectType: 'application',
|
|
targets: {},
|
|
tags: options.parsedTags,
|
|
};
|
|
project.targets.build = getBuildConfig(project, options);
|
|
project.targets.serve = getServeConfig(options);
|
|
|
|
addProjectConfiguration(
|
|
tree,
|
|
options.name,
|
|
project,
|
|
options.standaloneConfig
|
|
);
|
|
|
|
const workspace = readWorkspaceConfiguration(tree);
|
|
|
|
if (!workspace.defaultProject) {
|
|
workspace.defaultProject = options.name;
|
|
updateWorkspaceConfiguration(tree, workspace);
|
|
}
|
|
}
|
|
|
|
function addAppFiles(tree: Tree, options: NormalizedSchema) {
|
|
generateFiles(tree, join(__dirname, './files/app'), options.appProjectRoot, {
|
|
tmpl: '',
|
|
name: options.name,
|
|
root: options.appProjectRoot,
|
|
offset: offsetFromRoot(options.appProjectRoot),
|
|
rootTsConfigPath: getRelativePathToRootTsConfig(
|
|
tree,
|
|
options.appProjectRoot
|
|
),
|
|
});
|
|
if (options.js) {
|
|
toJS(tree);
|
|
}
|
|
if (options.pascalCaseFiles) {
|
|
logger.warn('NOTE: --pascalCaseFiles is a noop');
|
|
}
|
|
}
|
|
|
|
function addProxy(tree: Tree, options: NormalizedSchema) {
|
|
const projectConfig = readProjectConfiguration(tree, options.frontendProject);
|
|
if (projectConfig.targets && projectConfig.targets.serve) {
|
|
const pathToProxyFile = `${projectConfig.root}/proxy.conf.json`;
|
|
projectConfig.targets.serve.options = {
|
|
...projectConfig.targets.serve.options,
|
|
proxyConfig: pathToProxyFile,
|
|
};
|
|
|
|
if (!tree.exists(pathToProxyFile)) {
|
|
tree.write(
|
|
pathToProxyFile,
|
|
JSON.stringify(
|
|
{
|
|
'/api': {
|
|
target: 'http://localhost:3333',
|
|
secure: false,
|
|
},
|
|
},
|
|
null,
|
|
2
|
|
)
|
|
);
|
|
} else {
|
|
//add new entry to existing config
|
|
const proxyFileContent = tree.read(pathToProxyFile).toString();
|
|
|
|
const proxyModified = {
|
|
...JSON.parse(proxyFileContent),
|
|
[`/${options.name}-api`]: {
|
|
target: 'http://localhost:3333',
|
|
secure: false,
|
|
},
|
|
};
|
|
|
|
tree.write(pathToProxyFile, JSON.stringify(proxyModified, null, 2));
|
|
}
|
|
|
|
updateProjectConfiguration(tree, options.frontendProject, projectConfig);
|
|
}
|
|
}
|
|
|
|
export async function addLintingToApplication(
|
|
tree: Tree,
|
|
options: NormalizedSchema
|
|
): Promise<GeneratorCallback> {
|
|
const lintTask = await lintProjectGenerator(tree, {
|
|
linter: options.linter,
|
|
project: options.name,
|
|
tsConfigPaths: [
|
|
joinPathFragments(options.appProjectRoot, 'tsconfig.app.json'),
|
|
],
|
|
eslintFilePatterns: [
|
|
`${options.appProjectRoot}/**/*.${options.js ? 'js' : 'ts'}`,
|
|
],
|
|
unitTestRunner: options.unitTestRunner,
|
|
skipFormat: true,
|
|
setParserOptionsProject: options.setParserOptionsProject,
|
|
});
|
|
|
|
return lintTask;
|
|
}
|
|
|
|
export async function applicationGenerator(tree: Tree, schema: Schema) {
|
|
const options = normalizeOptions(tree, schema);
|
|
|
|
const tasks: GeneratorCallback[] = [];
|
|
const initTask = await initGenerator(tree, {
|
|
...options,
|
|
skipFormat: true,
|
|
});
|
|
tasks.push(initTask);
|
|
|
|
addAppFiles(tree, options);
|
|
addProject(tree, options);
|
|
|
|
if (options.linter !== Linter.None) {
|
|
const lintTask = await addLintingToApplication(tree, {
|
|
...options,
|
|
skipFormat: true,
|
|
});
|
|
tasks.push(lintTask);
|
|
}
|
|
|
|
if (options.unitTestRunner === 'jest') {
|
|
const jestTask = await jestProjectGenerator(tree, {
|
|
...options,
|
|
project: options.name,
|
|
setupFile: 'none',
|
|
skipSerializers: true,
|
|
supportTsx: options.js,
|
|
babelJest: options.babelJest,
|
|
testEnvironment: 'node',
|
|
skipFormat: true,
|
|
});
|
|
tasks.push(jestTask);
|
|
}
|
|
if (options.js) {
|
|
updateTsConfigsToJs(tree, { projectRoot: options.appProjectRoot });
|
|
}
|
|
|
|
if (options.frontendProject) {
|
|
addProxy(tree, options);
|
|
}
|
|
|
|
if (!options.skipFormat) {
|
|
await formatFiles(tree);
|
|
}
|
|
|
|
return runTasksInSerial(...tasks);
|
|
}
|
|
|
|
function normalizeOptions(host: Tree, options: Schema): NormalizedSchema {
|
|
const { appsDir } = getWorkspaceLayout(host);
|
|
|
|
const appDirectory = options.directory
|
|
? `${names(options.directory).fileName}/${names(options.name).fileName}`
|
|
: names(options.name).fileName;
|
|
|
|
const appProjectName = appDirectory.replace(new RegExp('/', 'g'), '-');
|
|
|
|
const appProjectRoot = joinPathFragments(appsDir, appDirectory);
|
|
|
|
const parsedTags = options.tags
|
|
? options.tags.split(',').map((s) => s.trim())
|
|
: [];
|
|
|
|
return {
|
|
...options,
|
|
name: names(appProjectName).fileName,
|
|
frontendProject: options.frontendProject
|
|
? names(options.frontendProject).fileName
|
|
: undefined,
|
|
appProjectRoot,
|
|
parsedTags,
|
|
linter: options.linter ?? Linter.EsLint,
|
|
unitTestRunner: options.unitTestRunner ?? 'jest',
|
|
};
|
|
}
|
|
|
|
export default applicationGenerator;
|
|
export const applicationSchematic = convertNxGenerator(applicationGenerator);
|