259 lines
7.6 KiB
TypeScript
259 lines
7.6 KiB
TypeScript
import {
|
|
extendReactEslintJson,
|
|
extraEslintDependencies,
|
|
} from '../../utils/lint';
|
|
import { NormalizedSchema, Schema } from './schema';
|
|
import { createApplicationFiles } from './lib/create-application-files';
|
|
import { updateSpecConfig } from './lib/update-jest-config';
|
|
import { normalizeOptions } from './lib/normalize-options';
|
|
import { addProject, maybeJs } from './lib/add-project';
|
|
import { addCypress } from './lib/add-cypress';
|
|
import { addJest } from './lib/add-jest';
|
|
import { addRouting } from './lib/add-routing';
|
|
import { setDefaults } from './lib/set-defaults';
|
|
import { addStyledModuleDependencies } from '../../rules/add-styled-dependencies';
|
|
import {
|
|
addDependenciesToPackageJson,
|
|
convertNxGenerator,
|
|
ensurePackage,
|
|
formatFiles,
|
|
GeneratorCallback,
|
|
joinPathFragments,
|
|
logger,
|
|
runTasksInSerial,
|
|
stripIndents,
|
|
Tree,
|
|
updateJson,
|
|
} from '@nx/devkit';
|
|
|
|
import reactInitGenerator from '../init/init';
|
|
import { Linter, lintProjectGenerator } from '@nx/linter';
|
|
import { mapLintPattern } from '@nx/linter/src/generators/lint-project/lint-project';
|
|
import {
|
|
babelLoaderVersion,
|
|
nxRspackVersion,
|
|
nxVersion,
|
|
} from '../../utils/versions';
|
|
import { installCommonDependencies } from './lib/install-common-dependencies';
|
|
import { extractTsConfigBase } from '../../utils/create-ts-config';
|
|
import { addSwcDependencies } from '@nx/js/src/utils/swc/add-swc-dependencies';
|
|
import * as chalk from 'chalk';
|
|
import { showPossibleWarnings } from './lib/show-possible-warnings';
|
|
|
|
async function addLinting(host: Tree, options: NormalizedSchema) {
|
|
const tasks: GeneratorCallback[] = [];
|
|
if (options.linter === Linter.EsLint) {
|
|
const lintTask = await lintProjectGenerator(host, {
|
|
linter: options.linter,
|
|
project: options.projectName,
|
|
tsConfigPaths: [
|
|
joinPathFragments(options.appProjectRoot, 'tsconfig.app.json'),
|
|
],
|
|
unitTestRunner: options.unitTestRunner,
|
|
eslintFilePatterns: [
|
|
mapLintPattern(
|
|
options.appProjectRoot,
|
|
'{ts,tsx,js,jsx}',
|
|
options.rootProject
|
|
),
|
|
],
|
|
skipFormat: true,
|
|
rootProject: options.rootProject,
|
|
skipPackageJson: options.skipPackageJson,
|
|
});
|
|
tasks.push(lintTask);
|
|
|
|
updateJson(
|
|
host,
|
|
joinPathFragments(options.appProjectRoot, '.eslintrc.json'),
|
|
extendReactEslintJson
|
|
);
|
|
|
|
if (!options.skipPackageJson) {
|
|
const installTask = await addDependenciesToPackageJson(
|
|
host,
|
|
extraEslintDependencies.dependencies,
|
|
extraEslintDependencies.devDependencies
|
|
);
|
|
const addSwcTask = addSwcDependencies(host);
|
|
tasks.push(installTask, addSwcTask);
|
|
}
|
|
}
|
|
return runTasksInSerial(...tasks);
|
|
}
|
|
|
|
export async function applicationGenerator(
|
|
host: Tree,
|
|
schema: Schema
|
|
): Promise<GeneratorCallback> {
|
|
const tasks = [];
|
|
|
|
const options = normalizeOptions(host, schema);
|
|
showPossibleWarnings(host, options);
|
|
|
|
const initTask = await reactInitGenerator(host, {
|
|
...options,
|
|
skipFormat: true,
|
|
skipHelperLibs: options.bundler === 'vite',
|
|
});
|
|
|
|
tasks.push(initTask);
|
|
|
|
if (!options.rootProject) {
|
|
extractTsConfigBase(host);
|
|
}
|
|
|
|
createApplicationFiles(host, options);
|
|
addProject(host, options);
|
|
|
|
if (options.bundler === 'vite') {
|
|
const { viteConfigurationGenerator } = ensurePackage<
|
|
typeof import('@nx/vite')
|
|
>('@nx/vite', nxVersion);
|
|
// We recommend users use `import.meta.env.MODE` and other variables in their code to differentiate between production and development.
|
|
// See: https://vitejs.dev/guide/env-and-mode.html
|
|
if (
|
|
host.exists(joinPathFragments(options.appProjectRoot, 'src/environments'))
|
|
) {
|
|
host.delete(
|
|
joinPathFragments(options.appProjectRoot, 'src/environments')
|
|
);
|
|
}
|
|
|
|
const viteTask = await viteConfigurationGenerator(host, {
|
|
uiFramework: 'react',
|
|
project: options.projectName,
|
|
newProject: true,
|
|
includeVitest: options.unitTestRunner === 'vitest',
|
|
inSourceTests: options.inSourceTests,
|
|
compiler: options.compiler,
|
|
skipFormat: true,
|
|
});
|
|
tasks.push(viteTask);
|
|
} else if (options.bundler === 'webpack') {
|
|
const { webpackInitGenerator } = ensurePackage<
|
|
typeof import('@nx/webpack')
|
|
>('@nx/webpack', nxVersion);
|
|
const webpackInitTask = await webpackInitGenerator(host, {
|
|
uiFramework: 'react',
|
|
skipFormat: true,
|
|
});
|
|
tasks.push(webpackInitTask);
|
|
} else if (options.bundler === 'rspack') {
|
|
const { configurationGenerator } = ensurePackage(
|
|
'@nx/rspack',
|
|
nxRspackVersion
|
|
);
|
|
const rspackTask = await configurationGenerator(host, {
|
|
project: options.projectName,
|
|
main: joinPathFragments(
|
|
options.appProjectRoot,
|
|
maybeJs(options, `src/main.tsx`)
|
|
),
|
|
tsConfig: joinPathFragments(options.appProjectRoot, 'tsconfig.app.json'),
|
|
target: 'web',
|
|
newProject: true,
|
|
uiFramework: 'react',
|
|
});
|
|
tasks.push(rspackTask);
|
|
}
|
|
|
|
if (options.bundler !== 'vite' && options.unitTestRunner === 'vitest') {
|
|
const { vitestGenerator } = ensurePackage<typeof import('@nx/vite')>(
|
|
'@nx/vite',
|
|
nxVersion
|
|
);
|
|
|
|
const vitestTask = await vitestGenerator(host, {
|
|
uiFramework: 'react',
|
|
coverageProvider: 'c8',
|
|
project: options.projectName,
|
|
inSourceTests: options.inSourceTests,
|
|
skipFormat: true,
|
|
});
|
|
tasks.push(vitestTask);
|
|
}
|
|
|
|
if (
|
|
(options.bundler === 'vite' || options.unitTestRunner === 'vitest') &&
|
|
options.inSourceTests
|
|
) {
|
|
host.delete(
|
|
joinPathFragments(
|
|
options.appProjectRoot,
|
|
`src/app/${options.fileName}.spec.tsx`
|
|
)
|
|
);
|
|
}
|
|
|
|
const lintTask = await addLinting(host, options);
|
|
tasks.push(lintTask);
|
|
|
|
const cypressTask = await addCypress(host, options);
|
|
tasks.push(cypressTask);
|
|
|
|
if (options.unitTestRunner === 'jest') {
|
|
const jestTask = await addJest(host, options);
|
|
tasks.push(jestTask);
|
|
}
|
|
|
|
// Handle tsconfig.spec.json for jest or vitest
|
|
updateSpecConfig(host, options);
|
|
const stylePreprocessorTask = installCommonDependencies(host, options);
|
|
tasks.push(stylePreprocessorTask);
|
|
const styledTask = addStyledModuleDependencies(host, options);
|
|
tasks.push(styledTask);
|
|
const routingTask = addRouting(host, options);
|
|
tasks.push(routingTask);
|
|
setDefaults(host, options);
|
|
|
|
if (options.bundler === 'rspack' && options.style === 'styled-jsx') {
|
|
logger.warn(
|
|
`${chalk.bold('styled-jsx')} is not supported by ${chalk.bold(
|
|
'Rspack'
|
|
)}. We've added ${chalk.bold(
|
|
'babel-loader'
|
|
)} to your project, but using babel will slow down your build.`
|
|
);
|
|
|
|
tasks.push(
|
|
addDependenciesToPackageJson(
|
|
host,
|
|
{},
|
|
{ 'babel-loader': babelLoaderVersion }
|
|
)
|
|
);
|
|
|
|
host.write(
|
|
joinPathFragments(options.appProjectRoot, 'rspack.config.js'),
|
|
stripIndents`
|
|
const { composePlugins, withNx, withWeb } = require('@nx/rspack');
|
|
module.exports = composePlugins(withNx(), withWeb(), (config) => {
|
|
config.module.rules.push({
|
|
test: /\\.[jt]sx$/i,
|
|
use: [
|
|
{
|
|
loader: 'babel-loader',
|
|
options: {
|
|
presets: ['@babel/preset-typescript'],
|
|
plugins: ['styled-jsx/babel'],
|
|
},
|
|
},
|
|
],
|
|
});
|
|
return config;
|
|
});
|
|
`
|
|
);
|
|
}
|
|
|
|
if (!options.skipFormat) {
|
|
await formatFiles(host);
|
|
}
|
|
|
|
return runTasksInSerial(...tasks);
|
|
}
|
|
|
|
export default applicationGenerator;
|
|
export const applicationSchematic = convertNxGenerator(applicationGenerator);
|