diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000000000..9eb1bd5a2a315 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,18 @@ +# EditorConfig is awesome: https://EditorConfig.org + +# top-most EditorConfig file +root = true + +# Unix-style newlines with a newline ending every file +[*] +end_of_line = lf +insert_final_newline = true + +# 4 space indentation +[*.{js,ts,jsx,tsx}] +indent_style = space +indent_size = 2 + +[package.json] +indent_style = space +indent_size = 2 \ No newline at end of file diff --git a/packages/angular/src/generators/application/angular-v14/files/tsconfig.json b/packages/angular/src/generators/application/angular-v14/files/tsconfig.json deleted file mode 100644 index 595598eddbf3e..0000000000000 --- a/packages/angular/src/generators/application/angular-v14/files/tsconfig.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "extends": "<%= rootTsConfigPath %>", - "files": [], - "include": [], - "references": [ - { - "path": "./tsconfig.app.json" - } - ] -} diff --git a/packages/angular/src/generators/application/angular-v14/lib/create-files.ts b/packages/angular/src/generators/application/angular-v14/lib/create-files.ts index 1588633a0c487..d2ec7f3b8cdcb 100644 --- a/packages/angular/src/generators/application/angular-v14/lib/create-files.ts +++ b/packages/angular/src/generators/application/angular-v14/lib/create-files.ts @@ -10,10 +10,6 @@ export function createFiles(tree: Tree, options: NormalizedSchema) { options.appProjectRoot, { ...options, - rootTsConfigPath: getRelativePathToRootTsConfig( - tree, - options.appProjectRoot - ), tpl: '', } ); diff --git a/packages/angular/src/generators/application/angular-v14/lib/update-config-files.ts b/packages/angular/src/generators/application/angular-v14/lib/update-config-files.ts index f7946113e2f05..3476327b3faf2 100644 --- a/packages/angular/src/generators/application/angular-v14/lib/update-config-files.ts +++ b/packages/angular/src/generators/application/angular-v14/lib/update-config-files.ts @@ -11,8 +11,16 @@ import { import { replaceAppNameWithPath } from '@nrwl/workspace/src/utils/cli-config-utils'; import { E2eTestRunner, UnitTestRunner } from '../../../../utils/test-runners'; import type { NormalizedSchema } from './normalized-schema'; +import { + createTsConfig, + extractTsConfigBase, +} from '../../../utils/create-ts-config'; +import { getRelativePathToRootTsConfig } from '@nrwl/workspace/src/utilities/typescript'; export function updateConfigFiles(host: Tree, options: NormalizedSchema) { + if (!options.rootProject) { + extractTsConfigBase(host); + } updateTsConfigOptions(host, options); updateAppAndE2EProjectConfigurations(host, options); } @@ -36,14 +44,13 @@ function updateTsConfigOptions(host: Tree, options: NormalizedSchema) { ], })); - // tsconfig.json - updateJson(host, `${options.appProjectRoot}/tsconfig.json`, (json) => ({ - ...json, - compilerOptions: { - ...json.compilerOptions, - target: 'es2020', - }, - })); + createTsConfig( + host, + options.appProjectRoot, + 'app', + options, + getRelativePathToRootTsConfig(host, options.appProjectRoot) + ); } function updateAppAndE2EProjectConfigurations( diff --git a/packages/angular/src/generators/application/application.spec.ts b/packages/angular/src/generators/application/application.spec.ts index 2ce99a96cc095..83a36f95be8a9 100644 --- a/packages/angular/src/generators/application/application.spec.ts +++ b/packages/angular/src/generators/application/application.spec.ts @@ -1073,9 +1073,7 @@ describe('app', () => { expect(appTree.exists('src/app/app.module.ts')).toBe(true); expect(appTree.exists('src/app/app.component.ts')).toBe(true); expect(appTree.exists('e2e/cypress.config.ts')).toBe(true); - expect(readJson(appTree, 'tsconfig.json').extends).toEqual( - './tsconfig.base.json' - ); + expect(readJson(appTree, 'tsconfig.json').extends).toBeUndefined(); const project = readProjectConfiguration(appTree, 'my-app'); expect(project.targets.build.options['outputPath']).toBe('dist/my-app'); }); diff --git a/packages/angular/src/generators/application/application.v14.spec.ts b/packages/angular/src/generators/application/application.v14.spec.ts index c3336a8564280..7c2194bbb1241 100644 --- a/packages/angular/src/generators/application/application.v14.spec.ts +++ b/packages/angular/src/generators/application/application.v14.spec.ts @@ -214,18 +214,6 @@ describe('app', () => { expect(appTsConfig.extends).toBe('../../tsconfig.base.json'); }); - it('should support a root tsconfig.json instead of tsconfig.base.json', async () => { - // ARRANGE - appTree.rename('tsconfig.base.json', 'tsconfig.json'); - - // ACT - await generateApp(appTree, 'app'); - - // ASSERT - const appTsConfig = readJson(appTree, 'apps/app/tsconfig.json'); - expect(appTsConfig.extends).toBe('../../tsconfig.json'); - }); - it('should set default project', async () => { // ACT await generateApp(appTree); @@ -339,18 +327,6 @@ describe('app', () => { const appTsConfig = readJson(appTree, 'apps/my-dir/app/tsconfig.json'); expect(appTsConfig.extends).toBe('../../../tsconfig.base.json'); }); - - it('should support a root tsconfig.json instead of tsconfig.base.json', async () => { - // ARRANGE - appTree.rename('tsconfig.base.json', 'tsconfig.json'); - - // ACT - await generateApp(appTree, 'app', { directory: 'myDir' }); - - // ASSERT - const appTsConfig = readJson(appTree, 'apps/my-dir/app/tsconfig.json'); - expect(appTsConfig.extends).toBe('../../../tsconfig.json'); - }); }); describe('at the root', () => { diff --git a/packages/angular/src/generators/application/files/tsconfig.json b/packages/angular/src/generators/application/files/tsconfig.json deleted file mode 100644 index 595598eddbf3e..0000000000000 --- a/packages/angular/src/generators/application/files/tsconfig.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "extends": "<%= rootTsConfigPath %>", - "files": [], - "include": [], - "references": [ - { - "path": "./tsconfig.app.json" - } - ] -} diff --git a/packages/angular/src/generators/application/lib/update-config-files.ts b/packages/angular/src/generators/application/lib/update-config-files.ts index 703db4d0cd5ab..bdcb3261fcc13 100644 --- a/packages/angular/src/generators/application/lib/update-config-files.ts +++ b/packages/angular/src/generators/application/lib/update-config-files.ts @@ -11,6 +11,8 @@ import { import { replaceAppNameWithPath } from '@nrwl/workspace/src/utils/cli-config-utils'; import { E2eTestRunner, UnitTestRunner } from '../../../utils/test-runners'; import type { NormalizedSchema } from './normalized-schema'; +import { createTsConfig } from '../../utils/create-ts-config'; +import { getRelativePathToRootTsConfig } from '@nrwl/workspace/src/utilities/typescript'; export function updateConfigFiles(host: Tree, options: NormalizedSchema) { updateTsConfigOptions(host, options); @@ -37,14 +39,13 @@ function updateTsConfigOptions(host: Tree, options: NormalizedSchema) { })); // tsconfig.json - updateJson(host, `${options.appProjectRoot}/tsconfig.json`, (json) => ({ - ...json, - compilerOptions: { - ...json.compilerOptions, - target: 'es2022', - useDefineForClassFields: false, // This will eventually need updated when Angular switch to using TC39 Compliant code - }, - })); + createTsConfig( + host, + options.appProjectRoot, + 'app', + options, + getRelativePathToRootTsConfig(host, options.appProjectRoot) + ); } function updateAppAndE2EProjectConfigurations( diff --git a/packages/angular/src/generators/library/files/lib/tsconfig.json__tpl__ b/packages/angular/src/generators/library/files/lib/tsconfig.json__tpl__ deleted file mode 100644 index 6feda9591dc03..0000000000000 --- a/packages/angular/src/generators/library/files/lib/tsconfig.json__tpl__ +++ /dev/null @@ -1,14 +0,0 @@ -{ - "extends": "<%= rootTsConfigPath %>", - "files": [], - "include": [], - "references": [ - { - "path": "./tsconfig.lib.json" - }<% if (publishable) { %>, - { - "path": "./tsconfig.lib.prod.json" - } - <% } %> - ] -} diff --git a/packages/angular/src/generators/library/lib/update-tsconfig.ts b/packages/angular/src/generators/library/lib/update-tsconfig.ts index ac039886800a7..f9b907cdb61ac 100644 --- a/packages/angular/src/generators/library/lib/update-tsconfig.ts +++ b/packages/angular/src/generators/library/lib/update-tsconfig.ts @@ -1,7 +1,14 @@ import type { Tree } from '@nrwl/devkit'; import { joinPathFragments, updateJson } from '@nrwl/devkit'; -import { getRootTsConfigPathInTree } from '@nrwl/workspace/src/utilities/typescript'; +import { + getRelativePathToRootTsConfig, + getRootTsConfigPathInTree, +} from '@nrwl/workspace/src/utilities/typescript'; import { NormalizedSchema } from './normalized-schema'; +import { + createTsConfig, + extractTsConfigBase, +} from '../../utils/create-ts-config'; function updateRootConfig( host: Tree, @@ -44,14 +51,13 @@ function updateProjectConfig( }); // tsconfig.json - updateJson(host, `${options.projectRoot}/tsconfig.json`, (json) => ({ - ...json, - compilerOptions: { - ...json.compilerOptions, - target: 'es2022', - useDefineForClassFields: false, - }, - })); + createTsConfig( + host, + options.projectRoot, + 'lib', + options, + getRelativePathToRootTsConfig(host, options.projectRoot) + ); } function updateProjectIvyConfig( @@ -75,6 +81,7 @@ export function updateTsConfig( host: Tree, options: NormalizedSchema['libraryOptions'] ) { + extractTsConfigBase(host); updateRootConfig(host, options); updateProjectConfig(host, options); updateProjectIvyConfig(host, options); diff --git a/packages/angular/src/generators/library/library.spec.ts b/packages/angular/src/generators/library/library.spec.ts index 6f2b5f0a68b5a..b0a39ad74634f 100644 --- a/packages/angular/src/generators/library/library.spec.ts +++ b/packages/angular/src/generators/library/library.spec.ts @@ -313,16 +313,13 @@ describe('lib', () => { }); }); - it('should support a root tsconfig.json instead of tsconfig.base.json', async () => { - // ARRANGE + it('should create tsconfig.base.json when it is missing', async () => { tree.rename('tsconfig.base.json', 'tsconfig.json'); - // ACT await runLibraryGeneratorWithOpts(); - // ASSERT const appTsConfig = readJson(tree, 'libs/my-lib/tsconfig.json'); - expect(appTsConfig.extends).toBe('../../tsconfig.json'); + expect(appTsConfig.extends).toBe('../../tsconfig.base.json'); }); it('should check for existence of spec files before deleting them', async () => { @@ -663,56 +660,6 @@ describe('lib', () => { tsconfigJson.compilerOptions.paths['my-dir-my-lib/*'] ).toBeUndefined(); }); - - it('should create a local tsconfig.json', async () => { - // ACT - await runLibraryGeneratorWithOpts({ directory: 'myDir' }); - - // ASSERT - const tsconfigJson = readJson(tree, 'libs/my-dir/my-lib/tsconfig.json'); - - expect(tsconfigJson).toEqual({ - extends: '../../../tsconfig.base.json', - angularCompilerOptions: { - enableI18nLegacyMessageIdFormat: false, - strictInjectionParameters: true, - strictInputAccessModifiers: true, - strictTemplates: true, - }, - compilerOptions: { - forceConsistentCasingInFileNames: true, - noFallthroughCasesInSwitch: true, - noPropertyAccessFromIndexSignature: true, - noImplicitOverride: true, - noImplicitReturns: true, - strict: true, - target: 'es2022', - useDefineForClassFields: false, - }, - files: [], - include: [], - references: [ - { - path: './tsconfig.lib.json', - }, - { - path: './tsconfig.spec.json', - }, - ], - }); - }); - - it('should support a root tsconfig.json instead of tsconfig.base.json', async () => { - // ARRANGE - tree.rename('tsconfig.base.json', 'tsconfig.json'); - - // ACT - await runLibraryGeneratorWithOpts({ directory: 'myDir' }); - - // ASSERT - const appTsConfig = readJson(tree, 'libs/my-dir/my-lib/tsconfig.json'); - expect(appTsConfig.extends).toBe('../../../tsconfig.json'); - }); }); describe('at the root', () => { diff --git a/packages/angular/src/generators/utils/create-ts-config.ts b/packages/angular/src/generators/utils/create-ts-config.ts new file mode 100644 index 0000000000000..1fc2d88cbb9d6 --- /dev/null +++ b/packages/angular/src/generators/utils/create-ts-config.ts @@ -0,0 +1,42 @@ +import { Tree } from 'nx/src/generators/tree'; +import { tsConfigBaseOptions } from '@nrwl/workspace/src/utils/create-ts-config'; +import { writeJson } from 'nx/src/generators/utils/json'; +export { extractTsConfigBase } from '@nrwl/workspace/src/utils/create-ts-config'; + +export function createTsConfig( + host: Tree, + projectRoot: string, + type: 'app' | 'lib', + options: { + strict?: boolean; + style?: string; + bundler?: string; + rootProject?: boolean; + }, + relativePathToRootTsConfig: string +) { + const json = { + compilerOptions: { + target: 'es2022', + useDefineForClassFields: false, + }, + files: [], + include: [], + references: [ + { + path: type === 'app' ? './tsconfig.app.json' : './tsconfig.lib.json', + }, + ], + } as any; + + // inline tsconfig.base.json into the project + if (options.rootProject) { + json.compileOnSave = false; + json.compilerOptions = { ...tsConfigBaseOptions, ...json.compilerOptions }; + json.exclude = ['node_modules', 'tmp']; + } else { + json.extends = relativePathToRootTsConfig; + } + + writeJson(host, `${projectRoot}/tsconfig.json`, json); +} diff --git a/packages/react/src/generators/application/application.spec.ts b/packages/react/src/generators/application/application.spec.ts index 34a8f68f8a47e..6709445f40310 100644 --- a/packages/react/src/generators/application/application.spec.ts +++ b/packages/react/src/generators/application/application.spec.ts @@ -104,17 +104,7 @@ describe('app', () => { path: './tsconfig.spec.json', }, ]); - expect(tsconfig.compilerOptions.forceConsistentCasingInFileNames).toEqual( - true - ); expect(tsconfig.compilerOptions.strict).toEqual(true); - expect(tsconfig.compilerOptions.noImplicitOverride).toEqual(true); - expect( - tsconfig.compilerOptions.noPropertyAccessFromIndexSignature - ).toEqual(true); - expect(tsconfig.compilerOptions.noImplicitReturns).toEqual(true); - expect(tsconfig.compilerOptions.noFallthroughCasesInSwitch).toEqual(true); - const tsconfigApp = readJson(appTree, 'apps/my-app/tsconfig.app.json'); expect(tsconfigApp.compilerOptions.outDir).toEqual('../../dist/out-tsc'); expect(tsconfigApp.extends).toEqual('./tsconfig.json'); @@ -165,15 +155,6 @@ describe('app', () => { const tsConfig = readJson(appTree, 'apps/my-app/tsconfig.json'); expect(tsConfig.extends).toEqual('../../tsconfig.base.json'); }); - - it('should extend from root tsconfig.json when no tsconfig.base.json', async () => { - appTree.rename('tsconfig.base.json', 'tsconfig.json'); - - await applicationGenerator(appTree, schema); - - const tsConfig = readJson(appTree, 'apps/my-app/tsconfig.json'); - expect(tsConfig.extends).toEqual('../../tsconfig.json'); - }); }); describe('nested', () => { @@ -902,15 +883,7 @@ describe('app', () => { expect( tsconfigJson.compilerOptions.forceConsistentCasingInFileNames ).not.toBeDefined(); - expect(tsconfigJson.compilerOptions.strict).not.toBeDefined(); - expect(tsconfigJson.compilerOptions.noImplicitOverride).not.toBeDefined(); - expect( - tsconfigJson.compilerOptions.noPropertyAccessFromIndexSignature - ).not.toBeDefined(); - expect(tsconfigJson.compilerOptions.noImplicitReturns).not.toBeDefined(); - expect( - tsconfigJson.compilerOptions.noFallthroughCasesInSwitch - ).not.toBeDefined(); + expect(tsconfigJson.compilerOptions.strict).toEqual(false); }); }); @@ -931,24 +904,6 @@ describe('app', () => { describe('--root-project', () => { it('should create files at the root', async () => { - await applicationGenerator(appTree, { - ...schema, - rootProject: true, - bundler: 'webpack', - }); - expect(appTree.read('/src/main.tsx')).toBeDefined(); - expect(appTree.read('/e2e/cypress.config.ts')).toBeDefined(); - expect(readJson(appTree, '/tsconfig.json').extends).toEqual( - './tsconfig.base.json' - ); - expect( - readJson(appTree, '/workspace.json').projects['my-app'].architect[ - 'build' - ].options['outputPath'] - ).toEqual('dist/my-app'); - }); - - it('should create files at the root if bundler is vite', async () => { await applicationGenerator(appTree, { ...schema, name: 'my-app2', @@ -957,9 +912,11 @@ describe('app', () => { }); expect(appTree.read('/src/main.tsx')).toBeDefined(); expect(appTree.read('/e2e/cypress.config.ts')).toBeDefined(); - expect(readJson(appTree, '/tsconfig.json').extends).toEqual( - './tsconfig.base.json' - ); + + const rootTsConfig = readJson(appTree, '/tsconfig.json'); + expect(rootTsConfig.extends).toBeUndefined(); + expect(rootTsConfig.compilerOptions.sourceMap).toBe(true); + expect( readJson(appTree, '/workspace.json').projects['my-app2'].architect[ 'build' diff --git a/packages/react/src/generators/application/application.ts b/packages/react/src/generators/application/application.ts index b3ca1a78c5874..2001e69cf72a5 100644 --- a/packages/react/src/generators/application/application.ts +++ b/packages/react/src/generators/application/application.ts @@ -32,6 +32,7 @@ import { swcLoaderVersion, } from '../../utils/versions'; import { installCommonDependencies } from './lib/install-common-dependencies'; +import { extractTsConfigBase } from '../../utils/create-ts-config'; async function addLinting(host: Tree, options: NormalizedSchema) { const tasks: GeneratorCallback[] = []; @@ -90,6 +91,10 @@ export async function applicationGenerator(host: Tree, schema: Schema) { tasks.push(initTask); + if (!options.rootProject) { + extractTsConfigBase(host); + } + createApplicationFiles(host, options); addProject(host, options); diff --git a/packages/react/src/generators/application/files/common-vite/tsconfig.json__tmpl__ b/packages/react/src/generators/application/files/common-vite/tsconfig.json__tmpl__ deleted file mode 100644 index e1b7347c34ec3..0000000000000 --- a/packages/react/src/generators/application/files/common-vite/tsconfig.json__tmpl__ +++ /dev/null @@ -1,29 +0,0 @@ -{ - "extends": "<%= rootTsConfigPath %>", - "compilerOptions": { - "jsx": "react-jsx", - <% if (style === '@emotion/styled') { %>"jsxImportSource": "@emotion/react",<% } %> - "allowJs": false, - "esModuleInterop": false, - "allowSyntheticDefaultImports": true, - "forceConsistentCasingInFileNames": true, - "isolatedModules": true, - "lib": ["DOM", "DOM.Iterable", "ESNext"], - "module": "ESNext", - "moduleResolution": "Node", - "noEmit": true, - "resolveJsonModule": true, - "skipLibCheck": true, - "strict": true, - "target": "ESNext", - "types": ["vite/client"], - "useDefineForClassFields": true - }, - "files": [], - "include": [], - "references": [ - { - "path": "./tsconfig.app.json" - } - ] -} diff --git a/packages/react/src/generators/application/files/common/tsconfig.json__tmpl__ b/packages/react/src/generators/application/files/common/tsconfig.json__tmpl__ deleted file mode 100644 index fc23421ea4caf..0000000000000 --- a/packages/react/src/generators/application/files/common/tsconfig.json__tmpl__ +++ /dev/null @@ -1,17 +0,0 @@ -{ - "extends": "<%= rootTsConfigPath %>", - "compilerOptions": { - "jsx": "react-jsx", - <% if (style === '@emotion/styled') { %>"jsxImportSource": "@emotion/react",<% } %> - "allowJs": true, - "esModuleInterop": true, - "allowSyntheticDefaultImports": true - }, - "files": [], - "include": [], - "references": [ - { - "path": "./tsconfig.app.json" - } - ] -} diff --git a/packages/react/src/generators/application/lib/create-application-files.ts b/packages/react/src/generators/application/lib/create-application-files.ts index c8312b5c59e2a..187ecc047ec07 100644 --- a/packages/react/src/generators/application/lib/create-application-files.ts +++ b/packages/react/src/generators/application/lib/create-application-files.ts @@ -10,28 +10,7 @@ import { } from '@nrwl/devkit'; import { join } from 'path'; import { getRelativePathToRootTsConfig } from '@nrwl/workspace/src/utilities/typescript'; - -function updateTsConfig(host: Tree, options: NormalizedSchema) { - updateJson( - host, - joinPathFragments(options.appProjectRoot, 'tsconfig.json'), - (json) => { - if (options.strict) { - json.compilerOptions = { - ...json.compilerOptions, - forceConsistentCasingInFileNames: true, - strict: true, - noImplicitOverride: true, - noPropertyAccessFromIndexSignature: true, - noImplicitReturns: true, - noFallthroughCasesInSwitch: true, - }; - } - - return json; - } - ); -} +import { createTsConfig } from '../../../utils/create-ts-config'; export function createApplicationFiles(host: Tree, options: NormalizedSchema) { let styleSolutionSpecificAppFiles: string; @@ -47,15 +26,15 @@ export function createApplicationFiles(host: Tree, options: NormalizedSchema) { styleSolutionSpecificAppFiles = '../files/css-module'; } + const relativePathToRootTsConfig = getRelativePathToRootTsConfig( + host, + options.appProjectRoot + ); const templateVariables = { ...names(options.name), ...options, tmpl: '', offsetFromRoot: offsetFromRoot(options.appProjectRoot), - rootTsConfigPath: getRelativePathToRootTsConfig( - host, - options.appProjectRoot - ), }; generateFiles( @@ -99,5 +78,11 @@ export function createApplicationFiles(host: Tree, options: NormalizedSchema) { toJS(host); } - updateTsConfig(host, options); + createTsConfig( + host, + options.appProjectRoot, + 'app', + options, + relativePathToRootTsConfig + ); } diff --git a/packages/react/src/generators/library/files/common/tsconfig.json__tmpl__ b/packages/react/src/generators/library/files/common/tsconfig.json__tmpl__ deleted file mode 100644 index c5c5460225c53..0000000000000 --- a/packages/react/src/generators/library/files/common/tsconfig.json__tmpl__ +++ /dev/null @@ -1,17 +0,0 @@ -{ - "extends": "<%= rootTsConfigPath %>", - "compilerOptions": { - "jsx": "react-jsx", - <% if (style === '@emotion/styled') { %>"jsxImportSource": "@emotion/react",<% } %> - "allowJs": true, - "esModuleInterop": true, - "allowSyntheticDefaultImports": true - }, - "files": [], - "include": [], - "references": [ - { - "path": "./tsconfig.lib.json" - } - ] -} diff --git a/packages/react/src/generators/library/lib/create-files.ts b/packages/react/src/generators/library/lib/create-files.ts index b9f4830d201c8..8dc320d435052 100644 --- a/packages/react/src/generators/library/lib/create-files.ts +++ b/packages/react/src/generators/library/lib/create-files.ts @@ -10,14 +10,18 @@ import { import { getRelativePathToRootTsConfig } from '@nrwl/workspace/src/utilities/typescript'; import { NormalizedSchema } from '../schema'; +import { createTsConfig } from '../../../utils/create-ts-config'; export function createFiles(host: Tree, options: NormalizedSchema) { + const relativePathToRootTsConfig = getRelativePathToRootTsConfig( + host, + options.projectRoot + ); const substitutions = { ...options, ...names(options.name), tmpl: '', offsetFromRoot: offsetFromRoot(options.projectRoot), - rootTsConfigPath: getRelativePathToRootTsConfig(host, options.projectRoot), }; generateFiles( @@ -48,27 +52,11 @@ export function createFiles(host: Tree, options: NormalizedSchema) { toJS(host); } - updateTsConfig(host, options); -} - -function updateTsConfig(tree: Tree, options: NormalizedSchema) { - updateJson( - tree, - joinPathFragments(options.projectRoot, 'tsconfig.json'), - (json) => { - if (options.strict) { - json.compilerOptions = { - ...json.compilerOptions, - forceConsistentCasingInFileNames: true, - strict: true, - noImplicitOverride: true, - noPropertyAccessFromIndexSignature: true, - noImplicitReturns: true, - noFallthroughCasesInSwitch: true, - }; - } - - return json; - } + createTsConfig( + host, + options.projectRoot, + 'lib', + options, + relativePathToRootTsConfig ); } diff --git a/packages/react/src/generators/library/library.spec.ts b/packages/react/src/generators/library/library.spec.ts index 9e50cc710f01d..2bda3d4ad4948 100644 --- a/packages/react/src/generators/library/library.spec.ts +++ b/packages/react/src/generators/library/library.spec.ts @@ -96,12 +96,12 @@ describe('lib', () => { ]); }); - it('should update root tsconfig.json when no tsconfig.base.json', async () => { + it('should create tsconfig.base.json out of tsconfig.json', async () => { tree.rename('tsconfig.base.json', 'tsconfig.json'); await libraryGenerator(tree, defaultSchema); - const tsconfigJson = readJson(tree, '/tsconfig.json'); + const tsconfigJson = readJson(tree, '/tsconfig.base.json'); expect(tsconfigJson.compilerOptions.paths['@proj/my-lib']).toEqual([ 'libs/my-lib/src/index.ts', ]); @@ -133,27 +133,7 @@ describe('lib', () => { path: './tsconfig.spec.json', }, ]); - expect( - tsconfigJson.compilerOptions.forceConsistentCasingInFileNames - ).toEqual(true); expect(tsconfigJson.compilerOptions.strict).toEqual(true); - expect(tsconfigJson.compilerOptions.noImplicitOverride).toEqual(true); - expect( - tsconfigJson.compilerOptions.noPropertyAccessFromIndexSignature - ).toEqual(true); - expect(tsconfigJson.compilerOptions.noImplicitReturns).toEqual(true); - expect(tsconfigJson.compilerOptions.noFallthroughCasesInSwitch).toEqual( - true - ); - }); - - it('should extend from root tsconfig.json when no tsconfig.base.json', async () => { - tree.rename('tsconfig.base.json', 'tsconfig.json'); - - await libraryGenerator(tree, defaultSchema); - - const tsconfigJson = readJson(tree, 'libs/my-lib/tsconfig.json'); - expect(tsconfigJson.extends).toBe('../../tsconfig.json'); }); it('should extend the local tsconfig.json with tsconfig.spec.json', async () => { @@ -325,20 +305,6 @@ describe('lib', () => { ).toBeUndefined(); }); - it('should update root tsconfig.json when no tsconfig.base.json', async () => { - tree.rename('tsconfig.base.json', 'tsconfig.json'); - - await libraryGenerator(tree, { ...defaultSchema, directory: 'myDir' }); - - const tsconfigJson = readJson(tree, '/tsconfig.json'); - expect(tsconfigJson.compilerOptions.paths['@proj/my-dir/my-lib']).toEqual( - ['libs/my-dir/my-lib/src/index.ts'] - ); - expect( - tsconfigJson.compilerOptions.paths['my-dir-my-lib/*'] - ).toBeUndefined(); - }); - it('should create a local tsconfig.json', async () => { await libraryGenerator(tree, { ...defaultSchema, directory: 'myDir' }); @@ -353,15 +319,6 @@ describe('lib', () => { }, ]); }); - - it('should extend from root tsconfig.json when no tsconfig.base.json', async () => { - tree.rename('tsconfig.base.json', 'tsconfig.json'); - - await libraryGenerator(tree, { ...defaultSchema, directory: 'myDir' }); - - const tsconfigJson = readJson(tree, 'libs/my-dir/my-lib/tsconfig.json'); - expect(tsconfigJson.extends).toBe('../../../tsconfig.json'); - }); }); describe('--style scss', () => { @@ -704,18 +661,7 @@ describe('lib', () => { }); const tsconfigJson = readJson(tree, '/libs/my-lib/tsconfig.json'); - expect( - tsconfigJson.compilerOptions.forceConsistentCasingInFileNames - ).not.toBeDefined(); - expect(tsconfigJson.compilerOptions.strict).not.toBeDefined(); - expect(tsconfigJson.compilerOptions.noImplicitOverride).not.toBeDefined(); - expect( - tsconfigJson.compilerOptions.noPropertyAccessFromIndexSignature - ).not.toBeDefined(); - expect(tsconfigJson.compilerOptions.noImplicitReturns).not.toBeDefined(); - expect( - tsconfigJson.compilerOptions.noFallthroughCasesInSwitch - ).not.toBeDefined(); + expect(tsconfigJson.compilerOptions.strict).toEqual(false); }); }); diff --git a/packages/react/src/generators/library/library.ts b/packages/react/src/generators/library/library.ts index 2cd8444342539..7fbc2c39ee1a2 100644 --- a/packages/react/src/generators/library/library.ts +++ b/packages/react/src/generators/library/library.ts @@ -21,6 +21,7 @@ import { addLinting } from './lib/add-linting'; import { updateAppRoutes } from './lib/update-app-routes'; import { createFiles } from './lib/create-files'; import { updateBaseTsConfig } from './lib/update-base-tsconfig'; +import { extractTsConfigBase } from '../../utils/create-ts-config'; import { installCommonDependencies } from './lib/install-common-dependencies'; export async function libraryGenerator(host: Tree, schema: Schema) { @@ -36,6 +37,8 @@ export async function libraryGenerator(host: Tree, schema: Schema) { options.style = 'none'; } + extractTsConfigBase(host); + const initTask = await initGenerator(host, { ...options, e2eTestRunner: 'none', diff --git a/packages/react/src/utils/create-ts-config.ts b/packages/react/src/utils/create-ts-config.ts new file mode 100644 index 0000000000000..363ddaa85ced8 --- /dev/null +++ b/packages/react/src/utils/create-ts-config.ts @@ -0,0 +1,67 @@ +import { Tree } from 'nx/src/generators/tree'; +import * as shared from '@nrwl/workspace/src/utils/create-ts-config'; +import { writeJson } from 'nx/src/generators/utils/json'; + +export function createTsConfig( + host: Tree, + projectRoot: string, + type: 'app' | 'lib', + options: { + strict?: boolean; + style?: string; + bundler?: string; + rootProject?: boolean; + }, + relativePathToRootTsConfig: string +) { + const json = { + compilerOptions: { + jsx: 'react-jsx', + allowJs: false, + esModuleInterop: false, + allowSyntheticDefaultImports: true, + strict: options.strict, + }, + files: [], + include: [], + references: [ + { + path: type === 'app' ? './tsconfig.app.json' : './tsconfig.lib.json', + }, + ], + } as any; + + if (options.style === '@emotion/styled') { + json.compilerOptions.jsxImportSource = '@emotion/react'; + } + + if (options.bundler === 'vite') { + json.compilerOptions.types = ['vite/client']; + } + + // inline tsconfig.base.json into the project + if (options.rootProject) { + json.compileOnSave = false; + json.compilerOptions = { + ...shared.tsConfigBaseOptions, + ...json.compilerOptions, + }; + json.exclude = ['node_modules', 'tmp']; + } else { + json.extends = relativePathToRootTsConfig; + } + + writeJson(host, `${projectRoot}/tsconfig.json`, json); +} + +export function extractTsConfigBase(host: Tree) { + shared.extractTsConfigBase(host); + + if (host.exists('vite.config.ts')) { + const vite = host.read('vite.config.ts').toString(); + host.write( + 'vite.config.ts', + vite.replace(`projects: []`, `projects: ['tsconfig.base.json']`) + ); + } +} diff --git a/packages/vite/src/utils/generator-utils.ts b/packages/vite/src/utils/generator-utils.ts index 0596c4ba6c70d..4b116446cacdb 100644 --- a/packages/vite/src/utils/generator-utils.ts +++ b/packages/vite/src/utils/generator-utils.ts @@ -412,6 +412,9 @@ export function writeViteConfig(tree: Tree, options: Schema) { host: 'localhost', },`; + const projectsTsConfig = tree.exists('tsconfig.base.json') + ? "'tsconfig.base.json'" + : ''; switch (options.uiFramework) { case 'react': viteConfigContent = ` @@ -432,7 +435,7 @@ ${options.includeVitest ? '/// ' : ''} react(), tsconfigPaths({ root: '${offsetFromRoot(projectConfig.root)}', - projects: ['tsconfig.base.json'], + projects: [${projectsTsConfig}], }), ], ${buildOption} @@ -457,7 +460,7 @@ ${options.includeVitest ? '/// ' : ''} ${options.includeLib ? dtsPlugin : ''} tsconfigPaths({ root: '${offsetFromRoot(projectConfig.root)}', - projects: ['tsconfig.base.json'], + projects: [${projectsTsConfig}], }), ], ${buildOption} diff --git a/packages/workspace/src/generators/new/files-root-app/tsconfig.base.json b/packages/workspace/src/generators/new/files-root-app/tsconfig.base.json deleted file mode 100644 index 11253ac5c2b7b..0000000000000 --- a/packages/workspace/src/generators/new/files-root-app/tsconfig.base.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "compileOnSave": false, - "compilerOptions": { - "rootDir": ".", - "sourceMap": true, - "declaration": false, - "moduleResolution": "node", - "emitDecoratorMetadata": true, - "experimentalDecorators": true, - "importHelpers": true, - "target": "es2015", - "module": "esnext", - "lib": ["es2017", "dom"], - "skipLibCheck": true, - "skipDefaultLibCheck": true, - "baseUrl": ".", - "paths": {} - }, - "exclude": ["node_modules", "tmp"] -} diff --git a/packages/workspace/src/utils/create-ts-config.ts b/packages/workspace/src/utils/create-ts-config.ts new file mode 100644 index 0000000000000..6bb11be4781b8 --- /dev/null +++ b/packages/workspace/src/utils/create-ts-config.ts @@ -0,0 +1,48 @@ +import { Tree } from 'nx/src/generators/tree'; +import { readJson, updateJson, writeJson } from 'nx/src/generators/utils/json'; + +export const tsConfigBaseOptions = { + rootDir: '.', + sourceMap: true, + declaration: false, + moduleResolution: 'node', + emitDecoratorMetadata: true, + experimentalDecorators: true, + importHelpers: true, + target: 'es2015', + module: 'esnext', + lib: ['es2017', 'dom'], + skipLibCheck: true, + skipDefaultLibCheck: true, + baseUrl: '.', +}; + +export function extractTsConfigBase(host: Tree) { + if (host.exists('tsconfig.base.json')) return; + + const tsconfig = readJson(host, 'tsconfig.json'); + const baseCompilerOptions = {} as any; + for (let compilerOption of Object.keys(tsConfigBaseOptions)) { + baseCompilerOptions[compilerOption] = + tsconfig.compilerOptions[compilerOption]; + delete tsconfig.compilerOptions[compilerOption]; + } + writeJson(host, 'tsconfig.base.json', { + compileOnSave: false, + compilerOptions: baseCompilerOptions, + exclude: tsconfig.exclude, + }); + tsconfig.extends = './tsconfig.base.json'; + delete tsconfig.compileOnSave; + delete tsconfig.exclude; + + writeJson(host, 'tsconfig.json', tsconfig); + + // special case for updating e2e tests. + if (host.exists('e2e/tsconfig.json')) { + updateJson(host, 'e2e/tsconfig.json', (json) => { + json.extends = '../tsconfig.base.json'; + return json; + }); + } +}