feat(web): add support for TS solution setup for @nx/web (#29583)
This PR adds the new TS setup support to `@nx/web:app` generator. Previously it errored out since it was not handled. ## Current Behavior Cannot generate webapp in new setup/ ## Expected Behavior <!-- This is the behavior we should expect with the changes in this PR --> Can generate webapp in new setup ## Related Issue(s) <!-- Please link the issue being fixed so it gets closed when this is merged. --> Fixes #
This commit is contained in:
parent
d08ad7504f
commit
42d9e8bcb3
@ -51,8 +51,8 @@
|
|||||||
"bundler": {
|
"bundler": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"description": "The bundler to use.",
|
"description": "The bundler to use.",
|
||||||
"enum": ["webpack", "none", "vite"],
|
"enum": ["vite", "webpack", "none"],
|
||||||
"default": "webpack",
|
"default": "vite",
|
||||||
"x-prompt": "Which bundler do you want to use?",
|
"x-prompt": "Which bundler do you want to use?",
|
||||||
"x-priority": "important"
|
"x-priority": "important"
|
||||||
},
|
},
|
||||||
@ -60,7 +60,8 @@
|
|||||||
"description": "The tool to use for running lint checks.",
|
"description": "The tool to use for running lint checks.",
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"enum": ["eslint", "none"],
|
"enum": ["eslint", "none"],
|
||||||
"default": "eslint"
|
"default": "none",
|
||||||
|
"x-prompt": "Which linter would you like to use?"
|
||||||
},
|
},
|
||||||
"skipFormat": {
|
"skipFormat": {
|
||||||
"description": "Skip formatting files",
|
"description": "Skip formatting files",
|
||||||
@ -71,8 +72,9 @@
|
|||||||
"unitTestRunner": {
|
"unitTestRunner": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"enum": ["vitest", "jest", "none"],
|
"enum": ["vitest", "jest", "none"],
|
||||||
"default": "vitest",
|
"default": "none",
|
||||||
"description": "Test runner to use for unit tests. Default value is 'jest' when using 'webpack' or 'none' as the bundler and 'vitest' when using 'vite' as the bundler"
|
"description": "Test runner to use for unit tests. Default value is 'jest' when using 'webpack' or 'none' as the bundler and 'vitest' when using 'vite' as the bundler",
|
||||||
|
"x-prompt": "What unit test runner should be used?"
|
||||||
},
|
},
|
||||||
"inSourceTests": {
|
"inSourceTests": {
|
||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
@ -99,12 +101,6 @@
|
|||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
"description": "Creates an application with strict mode and strict type checking.",
|
"description": "Creates an application with strict mode and strict type checking.",
|
||||||
"default": true
|
"default": true
|
||||||
},
|
|
||||||
"standaloneConfig": {
|
|
||||||
"description": "Split the project configuration into `<projectRoot>/project.json` rather than including it inside workspace.json",
|
|
||||||
"type": "boolean",
|
|
||||||
"default": true,
|
|
||||||
"x-deprecated": "Nx only supports standaloneConfig"
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"required": ["directory"],
|
"required": ["directory"],
|
||||||
|
|||||||
@ -22,7 +22,9 @@ describe('file-server', () => {
|
|||||||
const appName = uniq('app');
|
const appName = uniq('app');
|
||||||
const port = 4301;
|
const port = 4301;
|
||||||
|
|
||||||
runCLI(`generate @nx/web:app apps/${appName} --no-interactive`);
|
runCLI(
|
||||||
|
`generate @nx/web:app apps/${appName} --no-interactive --bundler=webpack`
|
||||||
|
);
|
||||||
updateJson(join('apps', appName, 'project.json'), (config) => {
|
updateJson(join('apps', appName, 'project.json'), (config) => {
|
||||||
config.targets['serve'] = {
|
config.targets['serve'] = {
|
||||||
executor: '@nx/web:file-server',
|
executor: '@nx/web:file-server',
|
||||||
@ -52,7 +54,9 @@ describe('file-server', () => {
|
|||||||
const appName = uniq('app');
|
const appName = uniq('app');
|
||||||
const port = 4301;
|
const port = 4301;
|
||||||
|
|
||||||
runCLI(`generate @nx/web:app apps/${appName} --no-interactive`);
|
runCLI(
|
||||||
|
`generate @nx/web:app apps/${appName} --no-interactive --bundler=webpack`
|
||||||
|
);
|
||||||
// Used to copy index.html rather than the normal webpack build.
|
// Used to copy index.html rather than the normal webpack build.
|
||||||
updateFile(
|
updateFile(
|
||||||
`apps/${appName}/copy-index.js`,
|
`apps/${appName}/copy-index.js`,
|
||||||
|
|||||||
@ -19,7 +19,7 @@ describe('Web Components Applications with bundler set as vite', () => {
|
|||||||
it('should be able to generate a web app', async () => {
|
it('should be able to generate a web app', async () => {
|
||||||
const appName = uniq('app');
|
const appName = uniq('app');
|
||||||
runCLI(
|
runCLI(
|
||||||
`generate @nx/web:app apps/${appName} --bundler=vite --no-interactive`
|
`generate @nx/web:app apps/${appName} --bundler=vite --no-interactive --linter=eslint --unitTestRunner=vitest`
|
||||||
);
|
);
|
||||||
|
|
||||||
const lintResults = runCLI(`lint ${appName}`);
|
const lintResults = runCLI(`lint ${appName}`);
|
||||||
@ -50,10 +50,10 @@ describe('Web Components Applications with bundler set as vite', () => {
|
|||||||
const libName = uniq('lib');
|
const libName = uniq('lib');
|
||||||
|
|
||||||
runCLI(
|
runCLI(
|
||||||
`generate @nx/web:app apps/${appName} --bundler=vite --no-interactive`
|
`generate @nx/web:app apps/${appName} --bundler=vite --no-interactive --linter=eslint --unitTestRunner=vitest`
|
||||||
);
|
);
|
||||||
runCLI(
|
runCLI(
|
||||||
`generate @nx/react:lib libs/${libName} --bundler=vite --no-interactive --unitTestRunner=vitest`
|
`generate @nx/react:lib libs/${libName} --bundler=vite --no-interactive --unitTestRunner=vitest --linter=eslint`
|
||||||
);
|
);
|
||||||
|
|
||||||
createFile(`dist/apps/${appName}/_should_remove.txt`);
|
createFile(`dist/apps/${appName}/_should_remove.txt`);
|
||||||
|
|||||||
@ -26,7 +26,7 @@ describe('Web Components Applications', () => {
|
|||||||
it('should be able to generate a web app', async () => {
|
it('should be able to generate a web app', async () => {
|
||||||
const appName = uniq('app');
|
const appName = uniq('app');
|
||||||
runCLI(
|
runCLI(
|
||||||
`generate @nx/web:app apps/${appName} --bundler=webpack --no-interactive`
|
`generate @nx/web:app apps/${appName} --bundler=webpack --no-interactive --unitTestRunner=vitest --linter=eslint`
|
||||||
);
|
);
|
||||||
|
|
||||||
const lintResults = runCLI(`lint ${appName}`);
|
const lintResults = runCLI(`lint ${appName}`);
|
||||||
@ -110,7 +110,7 @@ describe('Web Components Applications', () => {
|
|||||||
it('should emit decorator metadata when --compiler=babel and it is enabled in tsconfig', async () => {
|
it('should emit decorator metadata when --compiler=babel and it is enabled in tsconfig', async () => {
|
||||||
const appName = uniq('app');
|
const appName = uniq('app');
|
||||||
runCLI(
|
runCLI(
|
||||||
`generate @nx/web:app apps/${appName} --bundler=webpack --compiler=babel --no-interactive`
|
`generate @nx/web:app apps/${appName} --bundler=webpack --compiler=babel --no-interactive --unitTestRunner=vitest --linter=eslint`
|
||||||
);
|
);
|
||||||
|
|
||||||
updateFile(`apps/${appName}/src/app/app.element.ts`, (content) => {
|
updateFile(`apps/${appName}/src/app/app.element.ts`, (content) => {
|
||||||
@ -175,7 +175,7 @@ describe('Web Components Applications', () => {
|
|||||||
it('should emit decorator metadata when using --compiler=swc', async () => {
|
it('should emit decorator metadata when using --compiler=swc', async () => {
|
||||||
const appName = uniq('app');
|
const appName = uniq('app');
|
||||||
runCLI(
|
runCLI(
|
||||||
`generate @nx/web:app apps/${appName} --bundler=webpack --compiler=swc --no-interactive`
|
`generate @nx/web:app apps/${appName} --bundler=webpack --compiler=swc --no-interactive --unitTestRunner=vitest --linter=eslint`
|
||||||
);
|
);
|
||||||
|
|
||||||
updateFile(`apps/${appName}/src/app/app.element.ts`, (content) => {
|
updateFile(`apps/${appName}/src/app/app.element.ts`, (content) => {
|
||||||
@ -223,7 +223,7 @@ describe('Web Components Applications', () => {
|
|||||||
const appName = uniq('app1');
|
const appName = uniq('app1');
|
||||||
|
|
||||||
runCLI(
|
runCLI(
|
||||||
`generate @nx/web:app ${appName} --bundler=webpack --no-interactive`
|
`generate @nx/web:app ${appName} --bundler=webpack --no-interactive --unitTestRunner=vitest --linter=eslint`
|
||||||
);
|
);
|
||||||
|
|
||||||
// check files are generated without the layout directory ("apps/") and
|
// check files are generated without the layout directory ("apps/") and
|
||||||
@ -285,7 +285,7 @@ describe('CLI - Environment Variables', () => {
|
|||||||
`;
|
`;
|
||||||
|
|
||||||
runCLI(
|
runCLI(
|
||||||
`generate @nx/web:app apps/${appName} --bundler=webpack --no-interactive --compiler=babel`
|
`generate @nx/web:app apps/${appName} --bundler=webpack --no-interactive --compiler=babel --unitTestRunner=vitest --linter=eslint`
|
||||||
);
|
);
|
||||||
|
|
||||||
const content = readFile(main);
|
const content = readFile(main);
|
||||||
@ -310,7 +310,7 @@ describe('CLI - Environment Variables', () => {
|
|||||||
const newCode2 = `const envVars = [process.env.NODE_ENV, process.env.NX_PUBLIC_WS_BASE, process.env.NX_PUBLIC_WS_ENV_LOCAL, process.env.NX_PUBLIC_WS_LOCAL_ENV, process.env.NX_PUBLIC_APP_BASE, process.env.NX_PUBLIC_APP_ENV_LOCAL, process.env.NX_PUBLIC_APP_LOCAL_ENV, process.env.NX_PUBLIC_SHARED_ENV];`;
|
const newCode2 = `const envVars = [process.env.NODE_ENV, process.env.NX_PUBLIC_WS_BASE, process.env.NX_PUBLIC_WS_ENV_LOCAL, process.env.NX_PUBLIC_WS_LOCAL_ENV, process.env.NX_PUBLIC_APP_BASE, process.env.NX_PUBLIC_APP_ENV_LOCAL, process.env.NX_PUBLIC_APP_LOCAL_ENV, process.env.NX_PUBLIC_SHARED_ENV];`;
|
||||||
|
|
||||||
runCLI(
|
runCLI(
|
||||||
`generate @nx/web:app apps/${appName2} --bundler=webpack --no-interactive --compiler=babel`
|
`generate @nx/web:app apps/${appName2} --bundler=webpack --no-interactive --compiler=babel --unitTestRunner=vitest --linter=eslint`
|
||||||
);
|
);
|
||||||
|
|
||||||
const content2 = readFile(main2);
|
const content2 = readFile(main2);
|
||||||
@ -351,7 +351,7 @@ describe('index.html interpolation', () => {
|
|||||||
const appName = uniq('app');
|
const appName = uniq('app');
|
||||||
|
|
||||||
runCLI(
|
runCLI(
|
||||||
`generate @nx/web:app apps/${appName} --bundler=webpack --no-interactive`
|
`generate @nx/web:app apps/${appName} --bundler=webpack --no-interactive --unitTestRunner=vitest --linter=eslint`
|
||||||
);
|
);
|
||||||
|
|
||||||
const srcPath = `apps/${appName}/src`;
|
const srcPath = `apps/${appName}/src`;
|
||||||
|
|||||||
@ -5,7 +5,9 @@ import {
|
|||||||
readNxJson,
|
readNxJson,
|
||||||
readProjectConfiguration,
|
readProjectConfiguration,
|
||||||
Tree,
|
Tree,
|
||||||
|
updateJson,
|
||||||
updateNxJson,
|
updateNxJson,
|
||||||
|
writeJson,
|
||||||
} from '@nx/devkit';
|
} from '@nx/devkit';
|
||||||
import { getProjects, readJson } from '@nx/devkit';
|
import { getProjects, readJson } from '@nx/devkit';
|
||||||
import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing';
|
import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing';
|
||||||
@ -694,4 +696,161 @@ describe('app', () => {
|
|||||||
).toBe(false);
|
).toBe(false);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('TS solution setup', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
tree = createTreeWithEmptyWorkspace();
|
||||||
|
updateJson(tree, 'package.json', (json) => {
|
||||||
|
json.workspaces = ['packages/*', 'apps/*'];
|
||||||
|
return json;
|
||||||
|
});
|
||||||
|
writeJson(tree, 'tsconfig.base.json', {
|
||||||
|
compilerOptions: {
|
||||||
|
composite: true,
|
||||||
|
declaration: true,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
writeJson(tree, 'tsconfig.json', {
|
||||||
|
extends: './tsconfig.base.json',
|
||||||
|
files: [],
|
||||||
|
references: [],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should add project references when using TS solution', async () => {
|
||||||
|
await applicationGenerator(tree, {
|
||||||
|
directory: 'apps/myapp',
|
||||||
|
addPlugin: true,
|
||||||
|
linter: 'none',
|
||||||
|
style: 'none',
|
||||||
|
bundler: 'vite',
|
||||||
|
unitTestRunner: 'vitest',
|
||||||
|
e2eTestRunner: 'playwright',
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(readJson(tree, 'tsconfig.json').references).toMatchInlineSnapshot(`
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"path": "./apps/myapp-e2e",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "./apps/myapp",
|
||||||
|
},
|
||||||
|
]
|
||||||
|
`);
|
||||||
|
expect(readJson(tree, 'apps/myapp/tsconfig.json')).toMatchInlineSnapshot(`
|
||||||
|
{
|
||||||
|
"extends": "../../tsconfig.base.json",
|
||||||
|
"files": [],
|
||||||
|
"include": [],
|
||||||
|
"references": [
|
||||||
|
{
|
||||||
|
"path": "./tsconfig.app.json",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "./tsconfig.spec.json",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}
|
||||||
|
`);
|
||||||
|
expect(readJson(tree, 'apps/myapp/tsconfig.app.json'))
|
||||||
|
.toMatchInlineSnapshot(`
|
||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"module": "esnext",
|
||||||
|
"moduleResolution": "bundler",
|
||||||
|
"outDir": "out-tsc/myapp",
|
||||||
|
"rootDir": "src",
|
||||||
|
"tsBuildInfoFile": "out-tsc/myapp/tsconfig.app.tsbuildinfo",
|
||||||
|
"types": [
|
||||||
|
"node",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
"exclude": [
|
||||||
|
"out-tsc",
|
||||||
|
"dist",
|
||||||
|
"src/**/*.spec.ts",
|
||||||
|
"src/**/*.test.ts",
|
||||||
|
"vite.config.ts",
|
||||||
|
"vite.config.mts",
|
||||||
|
"vitest.config.ts",
|
||||||
|
"vitest.config.mts",
|
||||||
|
"src/**/*.test.tsx",
|
||||||
|
"src/**/*.spec.tsx",
|
||||||
|
"src/**/*.test.js",
|
||||||
|
"src/**/*.spec.js",
|
||||||
|
"src/**/*.test.jsx",
|
||||||
|
"src/**/*.spec.jsx",
|
||||||
|
],
|
||||||
|
"extends": "../../tsconfig.base.json",
|
||||||
|
"include": [
|
||||||
|
"src/**/*.ts",
|
||||||
|
],
|
||||||
|
}
|
||||||
|
`);
|
||||||
|
expect(readJson(tree, 'apps/myapp/tsconfig.spec.json'))
|
||||||
|
.toMatchInlineSnapshot(`
|
||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"module": "esnext",
|
||||||
|
"moduleResolution": "bundler",
|
||||||
|
"outDir": "./out-tsc/vitest",
|
||||||
|
"types": [
|
||||||
|
"vitest/globals",
|
||||||
|
"vitest/importMeta",
|
||||||
|
"vite/client",
|
||||||
|
"node",
|
||||||
|
"vitest",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
"extends": "../../tsconfig.base.json",
|
||||||
|
"include": [
|
||||||
|
"vite.config.ts",
|
||||||
|
"vite.config.mts",
|
||||||
|
"vitest.config.ts",
|
||||||
|
"vitest.config.mts",
|
||||||
|
"src/**/*.test.ts",
|
||||||
|
"src/**/*.spec.ts",
|
||||||
|
"src/**/*.test.tsx",
|
||||||
|
"src/**/*.spec.tsx",
|
||||||
|
"src/**/*.test.js",
|
||||||
|
"src/**/*.spec.js",
|
||||||
|
"src/**/*.test.jsx",
|
||||||
|
"src/**/*.spec.jsx",
|
||||||
|
"src/**/*.d.ts",
|
||||||
|
],
|
||||||
|
"references": [
|
||||||
|
{
|
||||||
|
"path": "./tsconfig.app.json",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}
|
||||||
|
`);
|
||||||
|
expect(readJson(tree, 'apps/myapp-e2e/tsconfig.json'))
|
||||||
|
.toMatchInlineSnapshot(`
|
||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"allowJs": true,
|
||||||
|
"outDir": "out-tsc/playwright",
|
||||||
|
"sourceMap": false,
|
||||||
|
},
|
||||||
|
"exclude": [
|
||||||
|
"out-tsc",
|
||||||
|
"test-output",
|
||||||
|
],
|
||||||
|
"extends": "../../tsconfig.base.json",
|
||||||
|
"include": [
|
||||||
|
"**/*.ts",
|
||||||
|
"**/*.js",
|
||||||
|
"playwright.config.ts",
|
||||||
|
"src/**/*.spec.ts",
|
||||||
|
"src/**/*.spec.js",
|
||||||
|
"src/**/*.test.ts",
|
||||||
|
"src/**/*.test.js",
|
||||||
|
"src/**/*.d.ts",
|
||||||
|
],
|
||||||
|
}
|
||||||
|
`);
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@ -13,7 +13,6 @@ import {
|
|||||||
readNxJson,
|
readNxJson,
|
||||||
readProjectConfiguration,
|
readProjectConfiguration,
|
||||||
runTasksInSerial,
|
runTasksInSerial,
|
||||||
TargetConfiguration,
|
|
||||||
Tree,
|
Tree,
|
||||||
updateJson,
|
updateJson,
|
||||||
updateNxJson,
|
updateNxJson,
|
||||||
@ -49,7 +48,12 @@ import { logShowProjectCommand } from '@nx/devkit/src/utils/log-show-project-com
|
|||||||
import staticServeConfiguration from '../static-serve/static-serve-configuration';
|
import staticServeConfiguration from '../static-serve/static-serve-configuration';
|
||||||
import { findPluginForConfigFile } from '@nx/devkit/src/utils/find-plugin-for-config-file';
|
import { findPluginForConfigFile } from '@nx/devkit/src/utils/find-plugin-for-config-file';
|
||||||
import { E2EWebServerDetails } from '@nx/devkit/src/generators/e2e-web-server-info-utils';
|
import { E2EWebServerDetails } from '@nx/devkit/src/generators/e2e-web-server-info-utils';
|
||||||
import { assertNotUsingTsSolutionSetup } from '@nx/js/src/utils/typescript/ts-solution-setup';
|
import {
|
||||||
|
addProjectToTsSolutionWorkspace,
|
||||||
|
isUsingTsSolutionSetup,
|
||||||
|
updateTsconfigFiles,
|
||||||
|
} from '@nx/js/src/utils/typescript/ts-solution-setup';
|
||||||
|
import { getImportPath } from '@nx/js/src/utils/get-import-path';
|
||||||
|
|
||||||
interface NormalizedSchema extends Schema {
|
interface NormalizedSchema extends Schema {
|
||||||
projectName: string;
|
projectName: string;
|
||||||
@ -57,9 +61,14 @@ interface NormalizedSchema extends Schema {
|
|||||||
e2eProjectName: string;
|
e2eProjectName: string;
|
||||||
e2eProjectRoot: string;
|
e2eProjectRoot: string;
|
||||||
parsedTags: string[];
|
parsedTags: string[];
|
||||||
|
isUsingTsSolutionConfig: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
function createApplicationFiles(tree: Tree, options: NormalizedSchema) {
|
function createApplicationFiles(tree: Tree, options: NormalizedSchema) {
|
||||||
|
const rootTsConfigPath = getRelativePathToRootTsConfig(
|
||||||
|
tree,
|
||||||
|
options.appProjectRoot
|
||||||
|
);
|
||||||
if (options.bundler === 'vite') {
|
if (options.bundler === 'vite') {
|
||||||
generateFiles(
|
generateFiles(
|
||||||
tree,
|
tree,
|
||||||
@ -70,10 +79,7 @@ function createApplicationFiles(tree: Tree, options: NormalizedSchema) {
|
|||||||
...names(options.name),
|
...names(options.name),
|
||||||
tmpl: '',
|
tmpl: '',
|
||||||
offsetFromRoot: offsetFromRoot(options.appProjectRoot),
|
offsetFromRoot: offsetFromRoot(options.appProjectRoot),
|
||||||
rootTsConfigPath: getRelativePathToRootTsConfig(
|
rootTsConfigPath,
|
||||||
tree,
|
|
||||||
options.appProjectRoot
|
|
||||||
),
|
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
@ -86,10 +92,7 @@ function createApplicationFiles(tree: Tree, options: NormalizedSchema) {
|
|||||||
...names(options.name),
|
...names(options.name),
|
||||||
tmpl: '',
|
tmpl: '',
|
||||||
offsetFromRoot: offsetFromRoot(options.appProjectRoot),
|
offsetFromRoot: offsetFromRoot(options.appProjectRoot),
|
||||||
rootTsConfigPath: getRelativePathToRootTsConfig(
|
rootTsConfigPath,
|
||||||
tree,
|
|
||||||
options.appProjectRoot
|
|
||||||
),
|
|
||||||
webpackPluginOptions: hasWebpackPlugin(tree)
|
webpackPluginOptions: hasWebpackPlugin(tree)
|
||||||
? {
|
? {
|
||||||
compiler: options.compiler,
|
compiler: options.compiler,
|
||||||
@ -116,6 +119,22 @@ function createApplicationFiles(tree: Tree, options: NormalizedSchema) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (options.isUsingTsSolutionConfig) {
|
||||||
|
updateJson(
|
||||||
|
tree,
|
||||||
|
joinPathFragments(options.appProjectRoot, 'tsconfig.json'),
|
||||||
|
() => ({
|
||||||
|
extends: rootTsConfigPath,
|
||||||
|
files: [],
|
||||||
|
include: [],
|
||||||
|
references: [
|
||||||
|
{
|
||||||
|
path: './tsconfig.app.json',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
})
|
||||||
|
);
|
||||||
|
} else {
|
||||||
updateJson(
|
updateJson(
|
||||||
tree,
|
tree,
|
||||||
joinPathFragments(options.appProjectRoot, 'tsconfig.json'),
|
joinPathFragments(options.appProjectRoot, 'tsconfig.json'),
|
||||||
@ -129,6 +148,7 @@ function createApplicationFiles(tree: Tree, options: NormalizedSchema) {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function setupBundler(tree: Tree, options: NormalizedSchema) {
|
async function setupBundler(tree: Tree, options: NormalizedSchema) {
|
||||||
@ -205,6 +225,7 @@ async function setupBundler(tree: Tree, options: NormalizedSchema) {
|
|||||||
} else if (options.bundler === 'none') {
|
} else if (options.bundler === 'none') {
|
||||||
const project = readProjectConfiguration(tree, options.projectName);
|
const project = readProjectConfiguration(tree, options.projectName);
|
||||||
addBuildTargetDefaults(tree, `@nx/js:${options.compiler}`);
|
addBuildTargetDefaults(tree, `@nx/js:${options.compiler}`);
|
||||||
|
project.targets ??= {};
|
||||||
project.targets.build = {
|
project.targets.build = {
|
||||||
executor: `@nx/js:${options.compiler}`,
|
executor: `@nx/js:${options.compiler}`,
|
||||||
outputs: ['{options.outputPath}'],
|
outputs: ['{options.outputPath}'],
|
||||||
@ -221,20 +242,27 @@ async function setupBundler(tree: Tree, options: NormalizedSchema) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function addProject(tree: Tree, options: NormalizedSchema) {
|
async function addProject(tree: Tree, options: NormalizedSchema) {
|
||||||
const targets: Record<string, TargetConfiguration> = {};
|
if (options.isUsingTsSolutionConfig) {
|
||||||
|
writeJson(tree, joinPathFragments(options.appProjectRoot, 'package.json'), {
|
||||||
addProjectConfiguration(
|
name: getImportPath(tree, options.name),
|
||||||
tree,
|
version: '0.0.1',
|
||||||
options.projectName,
|
private: true,
|
||||||
{
|
nx: {
|
||||||
|
name: options.name,
|
||||||
|
projectType: 'application',
|
||||||
|
sourceRoot: `${options.appProjectRoot}/src`,
|
||||||
|
tags: options.parsedTags?.length ? options.parsedTags : undefined,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
addProjectConfiguration(tree, options.projectName, {
|
||||||
projectType: 'application',
|
projectType: 'application',
|
||||||
root: options.appProjectRoot,
|
root: options.appProjectRoot,
|
||||||
sourceRoot: joinPathFragments(options.appProjectRoot, 'src'),
|
sourceRoot: joinPathFragments(options.appProjectRoot, 'src'),
|
||||||
tags: options.parsedTags,
|
tags: options.parsedTags,
|
||||||
targets,
|
targets: {},
|
||||||
},
|
});
|
||||||
options.standaloneConfig
|
}
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function setDefaults(tree: Tree, options: NormalizedSchema) {
|
function setDefaults(tree: Tree, options: NormalizedSchema) {
|
||||||
@ -258,8 +286,6 @@ export async function applicationGenerator(host: Tree, schema: Schema) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export async function applicationGeneratorInternal(host: Tree, schema: Schema) {
|
export async function applicationGeneratorInternal(host: Tree, schema: Schema) {
|
||||||
assertNotUsingTsSolutionSetup(host, 'web', 'application');
|
|
||||||
|
|
||||||
const options = await normalizeOptions(host, schema);
|
const options = await normalizeOptions(host, schema);
|
||||||
|
|
||||||
const tasks: GeneratorCallback[] = [];
|
const tasks: GeneratorCallback[] = [];
|
||||||
@ -432,6 +458,22 @@ export async function applicationGeneratorInternal(host: Tree, schema: Schema) {
|
|||||||
const { configurationGenerator } = ensurePackage<
|
const { configurationGenerator } = ensurePackage<
|
||||||
typeof import('@nx/cypress')
|
typeof import('@nx/cypress')
|
||||||
>('@nx/cypress', nxVersion);
|
>('@nx/cypress', nxVersion);
|
||||||
|
if (options.isUsingTsSolutionConfig) {
|
||||||
|
writeJson(
|
||||||
|
host,
|
||||||
|
joinPathFragments(options.e2eProjectRoot, 'package.json'),
|
||||||
|
{
|
||||||
|
name: options.e2eProjectName,
|
||||||
|
version: '0.0.1',
|
||||||
|
private: true,
|
||||||
|
nx: {
|
||||||
|
projectType: 'application',
|
||||||
|
sourceRoot: joinPathFragments(options.e2eProjectRoot, 'src'),
|
||||||
|
implicitDependencies: [options.projectName],
|
||||||
|
},
|
||||||
|
}
|
||||||
|
);
|
||||||
|
} else {
|
||||||
addProjectConfiguration(host, options.e2eProjectName, {
|
addProjectConfiguration(host, options.e2eProjectName, {
|
||||||
root: options.e2eProjectRoot,
|
root: options.e2eProjectRoot,
|
||||||
sourceRoot: joinPathFragments(options.e2eProjectRoot, 'src'),
|
sourceRoot: joinPathFragments(options.e2eProjectRoot, 'src'),
|
||||||
@ -440,6 +482,7 @@ export async function applicationGeneratorInternal(host: Tree, schema: Schema) {
|
|||||||
tags: [],
|
tags: [],
|
||||||
implicitDependencies: [options.projectName],
|
implicitDependencies: [options.projectName],
|
||||||
});
|
});
|
||||||
|
}
|
||||||
const cypressTask = await configurationGenerator(host, {
|
const cypressTask = await configurationGenerator(host, {
|
||||||
...options,
|
...options,
|
||||||
project: options.e2eProjectName,
|
project: options.e2eProjectName,
|
||||||
@ -493,6 +536,22 @@ export async function applicationGeneratorInternal(host: Tree, schema: Schema) {
|
|||||||
const { configurationGenerator: playwrightConfigGenerator } = ensurePackage<
|
const { configurationGenerator: playwrightConfigGenerator } = ensurePackage<
|
||||||
typeof import('@nx/playwright')
|
typeof import('@nx/playwright')
|
||||||
>('@nx/playwright', nxVersion);
|
>('@nx/playwright', nxVersion);
|
||||||
|
if (options.isUsingTsSolutionConfig) {
|
||||||
|
writeJson(
|
||||||
|
host,
|
||||||
|
joinPathFragments(options.e2eProjectRoot, 'package.json'),
|
||||||
|
{
|
||||||
|
name: options.e2eProjectName,
|
||||||
|
version: '0.0.1',
|
||||||
|
private: true,
|
||||||
|
nx: {
|
||||||
|
projectType: 'application',
|
||||||
|
sourceRoot: joinPathFragments(options.e2eProjectRoot, 'src'),
|
||||||
|
implicitDependencies: [options.projectName],
|
||||||
|
},
|
||||||
|
}
|
||||||
|
);
|
||||||
|
} else {
|
||||||
addProjectConfiguration(host, options.e2eProjectName, {
|
addProjectConfiguration(host, options.e2eProjectName, {
|
||||||
root: options.e2eProjectRoot,
|
root: options.e2eProjectRoot,
|
||||||
sourceRoot: joinPathFragments(options.e2eProjectRoot, 'src'),
|
sourceRoot: joinPathFragments(options.e2eProjectRoot, 'src'),
|
||||||
@ -501,6 +560,7 @@ export async function applicationGeneratorInternal(host: Tree, schema: Schema) {
|
|||||||
tags: [],
|
tags: [],
|
||||||
implicitDependencies: [options.projectName],
|
implicitDependencies: [options.projectName],
|
||||||
});
|
});
|
||||||
|
}
|
||||||
const playwrightTask = await playwrightConfigGenerator(host, {
|
const playwrightTask = await playwrightConfigGenerator(host, {
|
||||||
project: options.e2eProjectName,
|
project: options.e2eProjectName,
|
||||||
skipFormat: true,
|
skipFormat: true,
|
||||||
@ -592,7 +652,24 @@ export async function applicationGeneratorInternal(host: Tree, schema: Schema) {
|
|||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!schema.skipFormat) {
|
updateTsconfigFiles(
|
||||||
|
host,
|
||||||
|
options.appProjectRoot,
|
||||||
|
'tsconfig.app.json',
|
||||||
|
{
|
||||||
|
module: 'esnext',
|
||||||
|
moduleResolution: 'bundler',
|
||||||
|
},
|
||||||
|
options.linter === 'eslint'
|
||||||
|
? ['eslint.config.js', 'eslint.config.cjs', 'eslint.config.mjs']
|
||||||
|
: undefined
|
||||||
|
);
|
||||||
|
|
||||||
|
if (options.isUsingTsSolutionConfig) {
|
||||||
|
addProjectToTsSolutionWorkspace(host, options.appProjectRoot);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!options.skipFormat) {
|
||||||
await formatFiles(host);
|
await formatFiles(host);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -622,6 +699,7 @@ async function normalizeOptions(
|
|||||||
|
|
||||||
const e2eProjectName = `${appProjectName}-e2e`;
|
const e2eProjectName = `${appProjectName}-e2e`;
|
||||||
const e2eProjectRoot = `${appProjectRoot}-e2e`;
|
const e2eProjectRoot = `${appProjectRoot}-e2e`;
|
||||||
|
const isUsingTsSolutionConfig = isUsingTsSolutionSetup(host);
|
||||||
|
|
||||||
const npmScope = getNpmScope(host);
|
const npmScope = getNpmScope(host);
|
||||||
|
|
||||||
@ -646,6 +724,7 @@ async function normalizeOptions(
|
|||||||
e2eProjectRoot,
|
e2eProjectRoot,
|
||||||
e2eProjectName,
|
e2eProjectName,
|
||||||
parsedTags,
|
parsedTags,
|
||||||
|
isUsingTsSolutionConfig,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -13,7 +13,6 @@ export interface Schema {
|
|||||||
inSourceTests?: boolean;
|
inSourceTests?: boolean;
|
||||||
e2eTestRunner?: 'cypress' | 'playwright' | 'none';
|
e2eTestRunner?: 'cypress' | 'playwright' | 'none';
|
||||||
linter?: Linter | LinterType;
|
linter?: Linter | LinterType;
|
||||||
standaloneConfig?: boolean;
|
|
||||||
setParserOptionsProject?: boolean;
|
setParserOptionsProject?: boolean;
|
||||||
strict?: boolean;
|
strict?: boolean;
|
||||||
addPlugin?: boolean;
|
addPlugin?: boolean;
|
||||||
|
|||||||
@ -54,8 +54,8 @@
|
|||||||
"bundler": {
|
"bundler": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"description": "The bundler to use.",
|
"description": "The bundler to use.",
|
||||||
"enum": ["webpack", "none", "vite"],
|
"enum": ["vite", "webpack", "none"],
|
||||||
"default": "webpack",
|
"default": "vite",
|
||||||
"x-prompt": "Which bundler do you want to use?",
|
"x-prompt": "Which bundler do you want to use?",
|
||||||
"x-priority": "important"
|
"x-priority": "important"
|
||||||
},
|
},
|
||||||
@ -63,7 +63,8 @@
|
|||||||
"description": "The tool to use for running lint checks.",
|
"description": "The tool to use for running lint checks.",
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"enum": ["eslint", "none"],
|
"enum": ["eslint", "none"],
|
||||||
"default": "eslint"
|
"default": "none",
|
||||||
|
"x-prompt": "Which linter would you like to use?"
|
||||||
},
|
},
|
||||||
"skipFormat": {
|
"skipFormat": {
|
||||||
"description": "Skip formatting files",
|
"description": "Skip formatting files",
|
||||||
@ -74,8 +75,9 @@
|
|||||||
"unitTestRunner": {
|
"unitTestRunner": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"enum": ["vitest", "jest", "none"],
|
"enum": ["vitest", "jest", "none"],
|
||||||
"default": "vitest",
|
"default": "none",
|
||||||
"description": "Test runner to use for unit tests. Default value is 'jest' when using 'webpack' or 'none' as the bundler and 'vitest' when using 'vite' as the bundler"
|
"description": "Test runner to use for unit tests. Default value is 'jest' when using 'webpack' or 'none' as the bundler and 'vitest' when using 'vite' as the bundler",
|
||||||
|
"x-prompt": "What unit test runner should be used?"
|
||||||
},
|
},
|
||||||
"inSourceTests": {
|
"inSourceTests": {
|
||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
@ -102,12 +104,6 @@
|
|||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
"description": "Creates an application with strict mode and strict type checking.",
|
"description": "Creates an application with strict mode and strict type checking.",
|
||||||
"default": true
|
"default": true
|
||||||
},
|
|
||||||
"standaloneConfig": {
|
|
||||||
"description": "Split the project configuration into `<projectRoot>/project.json` rather than including it inside workspace.json",
|
|
||||||
"type": "boolean",
|
|
||||||
"default": true,
|
|
||||||
"x-deprecated": "Nx only supports standaloneConfig"
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"required": ["directory"],
|
"required": ["directory"],
|
||||||
|
|||||||
@ -6,7 +6,6 @@ import {
|
|||||||
runTasksInSerial,
|
runTasksInSerial,
|
||||||
Tree,
|
Tree,
|
||||||
} from '@nx/devkit';
|
} from '@nx/devkit';
|
||||||
import { assertNotUsingTsSolutionSetup } from '@nx/js/src/utils/typescript/ts-solution-setup';
|
|
||||||
import { nxVersion } from '../../utils/versions';
|
import { nxVersion } from '../../utils/versions';
|
||||||
import { Schema } from './schema';
|
import { Schema } from './schema';
|
||||||
|
|
||||||
@ -27,8 +26,6 @@ function updateDependencies(tree: Tree, schema: Schema) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export async function webInitGenerator(tree: Tree, schema: Schema) {
|
export async function webInitGenerator(tree: Tree, schema: Schema) {
|
||||||
assertNotUsingTsSolutionSetup(tree, 'web', 'init');
|
|
||||||
|
|
||||||
let installTask: GeneratorCallback = () => {};
|
let installTask: GeneratorCallback = () => {};
|
||||||
if (!schema.skipPackageJson) {
|
if (!schema.skipPackageJson) {
|
||||||
installTask = updateDependencies(tree, schema);
|
installTask = updateDependencies(tree, schema);
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user