feat(misc): do not generate tsconfig.base.json for simple standalone … (#13605)

This commit is contained in:
Victor Savkin 2022-12-05 10:07:01 -05:00 committed by GitHub
parent eb3242ab44
commit 91c19f5c0a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
25 changed files with 263 additions and 386 deletions

18
.editorconfig Normal file
View File

@ -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

View File

@ -1,10 +0,0 @@
{
"extends": "<%= rootTsConfigPath %>",
"files": [],
"include": [],
"references": [
{
"path": "./tsconfig.app.json"
}
]
}

View File

@ -10,10 +10,6 @@ export function createFiles(tree: Tree, options: NormalizedSchema) {
options.appProjectRoot, options.appProjectRoot,
{ {
...options, ...options,
rootTsConfigPath: getRelativePathToRootTsConfig(
tree,
options.appProjectRoot
),
tpl: '', tpl: '',
} }
); );

View File

@ -11,8 +11,16 @@ import {
import { replaceAppNameWithPath } from '@nrwl/workspace/src/utils/cli-config-utils'; import { replaceAppNameWithPath } from '@nrwl/workspace/src/utils/cli-config-utils';
import { E2eTestRunner, UnitTestRunner } from '../../../../utils/test-runners'; import { E2eTestRunner, UnitTestRunner } from '../../../../utils/test-runners';
import type { NormalizedSchema } from './normalized-schema'; 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) { export function updateConfigFiles(host: Tree, options: NormalizedSchema) {
if (!options.rootProject) {
extractTsConfigBase(host);
}
updateTsConfigOptions(host, options); updateTsConfigOptions(host, options);
updateAppAndE2EProjectConfigurations(host, options); updateAppAndE2EProjectConfigurations(host, options);
} }
@ -36,14 +44,13 @@ function updateTsConfigOptions(host: Tree, options: NormalizedSchema) {
], ],
})); }));
// tsconfig.json createTsConfig(
updateJson(host, `${options.appProjectRoot}/tsconfig.json`, (json) => ({ host,
...json, options.appProjectRoot,
compilerOptions: { 'app',
...json.compilerOptions, options,
target: 'es2020', getRelativePathToRootTsConfig(host, options.appProjectRoot)
}, );
}));
} }
function updateAppAndE2EProjectConfigurations( function updateAppAndE2EProjectConfigurations(

View File

@ -1073,9 +1073,7 @@ describe('app', () => {
expect(appTree.exists('src/app/app.module.ts')).toBe(true); expect(appTree.exists('src/app/app.module.ts')).toBe(true);
expect(appTree.exists('src/app/app.component.ts')).toBe(true); expect(appTree.exists('src/app/app.component.ts')).toBe(true);
expect(appTree.exists('e2e/cypress.config.ts')).toBe(true); expect(appTree.exists('e2e/cypress.config.ts')).toBe(true);
expect(readJson(appTree, 'tsconfig.json').extends).toEqual( expect(readJson(appTree, 'tsconfig.json').extends).toBeUndefined();
'./tsconfig.base.json'
);
const project = readProjectConfiguration(appTree, 'my-app'); const project = readProjectConfiguration(appTree, 'my-app');
expect(project.targets.build.options['outputPath']).toBe('dist/my-app'); expect(project.targets.build.options['outputPath']).toBe('dist/my-app');
}); });

View File

@ -214,18 +214,6 @@ describe('app', () => {
expect(appTsConfig.extends).toBe('../../tsconfig.base.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');
// ASSERT
const appTsConfig = readJson(appTree, 'apps/app/tsconfig.json');
expect(appTsConfig.extends).toBe('../../tsconfig.json');
});
it('should set default project', async () => { it('should set default project', async () => {
// ACT // ACT
await generateApp(appTree); await generateApp(appTree);
@ -339,18 +327,6 @@ describe('app', () => {
const appTsConfig = readJson(appTree, 'apps/my-dir/app/tsconfig.json'); const appTsConfig = readJson(appTree, 'apps/my-dir/app/tsconfig.json');
expect(appTsConfig.extends).toBe('../../../tsconfig.base.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', () => { describe('at the root', () => {

View File

@ -1,10 +0,0 @@
{
"extends": "<%= rootTsConfigPath %>",
"files": [],
"include": [],
"references": [
{
"path": "./tsconfig.app.json"
}
]
}

View File

@ -11,6 +11,8 @@ import {
import { replaceAppNameWithPath } from '@nrwl/workspace/src/utils/cli-config-utils'; import { replaceAppNameWithPath } from '@nrwl/workspace/src/utils/cli-config-utils';
import { E2eTestRunner, UnitTestRunner } from '../../../utils/test-runners'; import { E2eTestRunner, UnitTestRunner } from '../../../utils/test-runners';
import type { NormalizedSchema } from './normalized-schema'; 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) { export function updateConfigFiles(host: Tree, options: NormalizedSchema) {
updateTsConfigOptions(host, options); updateTsConfigOptions(host, options);
@ -37,14 +39,13 @@ function updateTsConfigOptions(host: Tree, options: NormalizedSchema) {
})); }));
// tsconfig.json // tsconfig.json
updateJson(host, `${options.appProjectRoot}/tsconfig.json`, (json) => ({ createTsConfig(
...json, host,
compilerOptions: { options.appProjectRoot,
...json.compilerOptions, 'app',
target: 'es2022', options,
useDefineForClassFields: false, // This will eventually need updated when Angular switch to using TC39 Compliant code getRelativePathToRootTsConfig(host, options.appProjectRoot)
}, );
}));
} }
function updateAppAndE2EProjectConfigurations( function updateAppAndE2EProjectConfigurations(

View File

@ -1,14 +0,0 @@
{
"extends": "<%= rootTsConfigPath %>",
"files": [],
"include": [],
"references": [
{
"path": "./tsconfig.lib.json"
}<% if (publishable) { %>,
{
"path": "./tsconfig.lib.prod.json"
}
<% } %>
]
}

View File

@ -1,7 +1,14 @@
import type { Tree } from '@nrwl/devkit'; import type { Tree } from '@nrwl/devkit';
import { joinPathFragments, updateJson } 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 { NormalizedSchema } from './normalized-schema';
import {
createTsConfig,
extractTsConfigBase,
} from '../../utils/create-ts-config';
function updateRootConfig( function updateRootConfig(
host: Tree, host: Tree,
@ -44,14 +51,13 @@ function updateProjectConfig(
}); });
// tsconfig.json // tsconfig.json
updateJson(host, `${options.projectRoot}/tsconfig.json`, (json) => ({ createTsConfig(
...json, host,
compilerOptions: { options.projectRoot,
...json.compilerOptions, 'lib',
target: 'es2022', options,
useDefineForClassFields: false, getRelativePathToRootTsConfig(host, options.projectRoot)
}, );
}));
} }
function updateProjectIvyConfig( function updateProjectIvyConfig(
@ -75,6 +81,7 @@ export function updateTsConfig(
host: Tree, host: Tree,
options: NormalizedSchema['libraryOptions'] options: NormalizedSchema['libraryOptions']
) { ) {
extractTsConfigBase(host);
updateRootConfig(host, options); updateRootConfig(host, options);
updateProjectConfig(host, options); updateProjectConfig(host, options);
updateProjectIvyConfig(host, options); updateProjectIvyConfig(host, options);

View File

@ -313,16 +313,13 @@ describe('lib', () => {
}); });
}); });
it('should support a root tsconfig.json instead of tsconfig.base.json', async () => { it('should create tsconfig.base.json when it is missing', async () => {
// ARRANGE
tree.rename('tsconfig.base.json', 'tsconfig.json'); tree.rename('tsconfig.base.json', 'tsconfig.json');
// ACT
await runLibraryGeneratorWithOpts(); await runLibraryGeneratorWithOpts();
// ASSERT
const appTsConfig = readJson(tree, 'libs/my-lib/tsconfig.json'); 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 () => { 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/*'] tsconfigJson.compilerOptions.paths['my-dir-my-lib/*']
).toBeUndefined(); ).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', () => { describe('at the root', () => {

View File

@ -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);
}

View File

@ -104,17 +104,7 @@ describe('app', () => {
path: './tsconfig.spec.json', path: './tsconfig.spec.json',
}, },
]); ]);
expect(tsconfig.compilerOptions.forceConsistentCasingInFileNames).toEqual(
true
);
expect(tsconfig.compilerOptions.strict).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'); const tsconfigApp = readJson(appTree, 'apps/my-app/tsconfig.app.json');
expect(tsconfigApp.compilerOptions.outDir).toEqual('../../dist/out-tsc'); expect(tsconfigApp.compilerOptions.outDir).toEqual('../../dist/out-tsc');
expect(tsconfigApp.extends).toEqual('./tsconfig.json'); expect(tsconfigApp.extends).toEqual('./tsconfig.json');
@ -165,15 +155,6 @@ describe('app', () => {
const tsConfig = readJson(appTree, 'apps/my-app/tsconfig.json'); const tsConfig = readJson(appTree, 'apps/my-app/tsconfig.json');
expect(tsConfig.extends).toEqual('../../tsconfig.base.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', () => { describe('nested', () => {
@ -902,15 +883,7 @@ describe('app', () => {
expect( expect(
tsconfigJson.compilerOptions.forceConsistentCasingInFileNames tsconfigJson.compilerOptions.forceConsistentCasingInFileNames
).not.toBeDefined(); ).not.toBeDefined();
expect(tsconfigJson.compilerOptions.strict).not.toBeDefined(); expect(tsconfigJson.compilerOptions.strict).toEqual(false);
expect(tsconfigJson.compilerOptions.noImplicitOverride).not.toBeDefined();
expect(
tsconfigJson.compilerOptions.noPropertyAccessFromIndexSignature
).not.toBeDefined();
expect(tsconfigJson.compilerOptions.noImplicitReturns).not.toBeDefined();
expect(
tsconfigJson.compilerOptions.noFallthroughCasesInSwitch
).not.toBeDefined();
}); });
}); });
@ -931,24 +904,6 @@ describe('app', () => {
describe('--root-project', () => { describe('--root-project', () => {
it('should create files at the root', async () => { 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, { await applicationGenerator(appTree, {
...schema, ...schema,
name: 'my-app2', name: 'my-app2',
@ -957,9 +912,11 @@ describe('app', () => {
}); });
expect(appTree.read('/src/main.tsx')).toBeDefined(); expect(appTree.read('/src/main.tsx')).toBeDefined();
expect(appTree.read('/e2e/cypress.config.ts')).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( expect(
readJson(appTree, '/workspace.json').projects['my-app2'].architect[ readJson(appTree, '/workspace.json').projects['my-app2'].architect[
'build' 'build'

View File

@ -32,6 +32,7 @@ import {
swcLoaderVersion, swcLoaderVersion,
} from '../../utils/versions'; } from '../../utils/versions';
import { installCommonDependencies } from './lib/install-common-dependencies'; import { installCommonDependencies } from './lib/install-common-dependencies';
import { extractTsConfigBase } from '../../utils/create-ts-config';
async function addLinting(host: Tree, options: NormalizedSchema) { async function addLinting(host: Tree, options: NormalizedSchema) {
const tasks: GeneratorCallback[] = []; const tasks: GeneratorCallback[] = [];
@ -90,6 +91,10 @@ export async function applicationGenerator(host: Tree, schema: Schema) {
tasks.push(initTask); tasks.push(initTask);
if (!options.rootProject) {
extractTsConfigBase(host);
}
createApplicationFiles(host, options); createApplicationFiles(host, options);
addProject(host, options); addProject(host, options);

View File

@ -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"
}
]
}

View File

@ -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"
}
]
}

View File

@ -10,28 +10,7 @@ import {
} from '@nrwl/devkit'; } from '@nrwl/devkit';
import { join } from 'path'; import { join } from 'path';
import { getRelativePathToRootTsConfig } from '@nrwl/workspace/src/utilities/typescript'; import { getRelativePathToRootTsConfig } from '@nrwl/workspace/src/utilities/typescript';
import { createTsConfig } from '../../../utils/create-ts-config';
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;
}
);
}
export function createApplicationFiles(host: Tree, options: NormalizedSchema) { export function createApplicationFiles(host: Tree, options: NormalizedSchema) {
let styleSolutionSpecificAppFiles: string; let styleSolutionSpecificAppFiles: string;
@ -47,15 +26,15 @@ export function createApplicationFiles(host: Tree, options: NormalizedSchema) {
styleSolutionSpecificAppFiles = '../files/css-module'; styleSolutionSpecificAppFiles = '../files/css-module';
} }
const relativePathToRootTsConfig = getRelativePathToRootTsConfig(
host,
options.appProjectRoot
);
const templateVariables = { const templateVariables = {
...names(options.name), ...names(options.name),
...options, ...options,
tmpl: '', tmpl: '',
offsetFromRoot: offsetFromRoot(options.appProjectRoot), offsetFromRoot: offsetFromRoot(options.appProjectRoot),
rootTsConfigPath: getRelativePathToRootTsConfig(
host,
options.appProjectRoot
),
}; };
generateFiles( generateFiles(
@ -99,5 +78,11 @@ export function createApplicationFiles(host: Tree, options: NormalizedSchema) {
toJS(host); toJS(host);
} }
updateTsConfig(host, options); createTsConfig(
host,
options.appProjectRoot,
'app',
options,
relativePathToRootTsConfig
);
} }

View File

@ -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"
}
]
}

View File

@ -10,14 +10,18 @@ import {
import { getRelativePathToRootTsConfig } from '@nrwl/workspace/src/utilities/typescript'; import { getRelativePathToRootTsConfig } from '@nrwl/workspace/src/utilities/typescript';
import { NormalizedSchema } from '../schema'; import { NormalizedSchema } from '../schema';
import { createTsConfig } from '../../../utils/create-ts-config';
export function createFiles(host: Tree, options: NormalizedSchema) { export function createFiles(host: Tree, options: NormalizedSchema) {
const relativePathToRootTsConfig = getRelativePathToRootTsConfig(
host,
options.projectRoot
);
const substitutions = { const substitutions = {
...options, ...options,
...names(options.name), ...names(options.name),
tmpl: '', tmpl: '',
offsetFromRoot: offsetFromRoot(options.projectRoot), offsetFromRoot: offsetFromRoot(options.projectRoot),
rootTsConfigPath: getRelativePathToRootTsConfig(host, options.projectRoot),
}; };
generateFiles( generateFiles(
@ -48,27 +52,11 @@ export function createFiles(host: Tree, options: NormalizedSchema) {
toJS(host); toJS(host);
} }
updateTsConfig(host, options); createTsConfig(
} host,
options.projectRoot,
function updateTsConfig(tree: Tree, options: NormalizedSchema) { 'lib',
updateJson( options,
tree, relativePathToRootTsConfig
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;
}
); );
} }

View File

@ -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'); tree.rename('tsconfig.base.json', 'tsconfig.json');
await libraryGenerator(tree, defaultSchema); 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([ expect(tsconfigJson.compilerOptions.paths['@proj/my-lib']).toEqual([
'libs/my-lib/src/index.ts', 'libs/my-lib/src/index.ts',
]); ]);
@ -133,27 +133,7 @@ describe('lib', () => {
path: './tsconfig.spec.json', path: './tsconfig.spec.json',
}, },
]); ]);
expect(
tsconfigJson.compilerOptions.forceConsistentCasingInFileNames
).toEqual(true);
expect(tsconfigJson.compilerOptions.strict).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 () => { it('should extend the local tsconfig.json with tsconfig.spec.json', async () => {
@ -325,20 +305,6 @@ describe('lib', () => {
).toBeUndefined(); ).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 () => { it('should create a local tsconfig.json', async () => {
await libraryGenerator(tree, { ...defaultSchema, directory: 'myDir' }); 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', () => { describe('--style scss', () => {
@ -704,18 +661,7 @@ describe('lib', () => {
}); });
const tsconfigJson = readJson(tree, '/libs/my-lib/tsconfig.json'); const tsconfigJson = readJson(tree, '/libs/my-lib/tsconfig.json');
expect( expect(tsconfigJson.compilerOptions.strict).toEqual(false);
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();
}); });
}); });

View File

@ -21,6 +21,7 @@ import { addLinting } from './lib/add-linting';
import { updateAppRoutes } from './lib/update-app-routes'; import { updateAppRoutes } from './lib/update-app-routes';
import { createFiles } from './lib/create-files'; import { createFiles } from './lib/create-files';
import { updateBaseTsConfig } from './lib/update-base-tsconfig'; import { updateBaseTsConfig } from './lib/update-base-tsconfig';
import { extractTsConfigBase } from '../../utils/create-ts-config';
import { installCommonDependencies } from './lib/install-common-dependencies'; import { installCommonDependencies } from './lib/install-common-dependencies';
export async function libraryGenerator(host: Tree, schema: Schema) { export async function libraryGenerator(host: Tree, schema: Schema) {
@ -36,6 +37,8 @@ export async function libraryGenerator(host: Tree, schema: Schema) {
options.style = 'none'; options.style = 'none';
} }
extractTsConfigBase(host);
const initTask = await initGenerator(host, { const initTask = await initGenerator(host, {
...options, ...options,
e2eTestRunner: 'none', e2eTestRunner: 'none',

View File

@ -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']`)
);
}
}

View File

@ -412,6 +412,9 @@ export function writeViteConfig(tree: Tree, options: Schema) {
host: 'localhost', host: 'localhost',
},`; },`;
const projectsTsConfig = tree.exists('tsconfig.base.json')
? "'tsconfig.base.json'"
: '';
switch (options.uiFramework) { switch (options.uiFramework) {
case 'react': case 'react':
viteConfigContent = ` viteConfigContent = `
@ -432,7 +435,7 @@ ${options.includeVitest ? '/// <reference types="vitest" />' : ''}
react(), react(),
tsconfigPaths({ tsconfigPaths({
root: '${offsetFromRoot(projectConfig.root)}', root: '${offsetFromRoot(projectConfig.root)}',
projects: ['tsconfig.base.json'], projects: [${projectsTsConfig}],
}), }),
], ],
${buildOption} ${buildOption}
@ -457,7 +460,7 @@ ${options.includeVitest ? '/// <reference types="vitest" />' : ''}
${options.includeLib ? dtsPlugin : ''} ${options.includeLib ? dtsPlugin : ''}
tsconfigPaths({ tsconfigPaths({
root: '${offsetFromRoot(projectConfig.root)}', root: '${offsetFromRoot(projectConfig.root)}',
projects: ['tsconfig.base.json'], projects: [${projectsTsConfig}],
}), }),
], ],
${buildOption} ${buildOption}

View File

@ -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"]
}

View File

@ -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;
});
}
}