From 2084123cd4220201463cdbf0fdb065d41c3bc0f8 Mon Sep 17 00:00:00 2001 From: Alan Date: Thu, 18 Apr 2019 11:20:04 +0200 Subject: [PATCH] fix(@schematics/angular): generate `tsconfig.worker.json` outside of the `src` folder This is to align with the folder structure of version 8, were tsconfigs are outside of the `src` folder Also, this change remove the dud `tsconfig.json` in the `src` folder and instead we add the triple slash lib reference `/// ` for IDE support. --- .../test/browser/web-worker_spec_large.ts | 2 + .../project-tsconfig/tsconfig.json.template | 10 --- .../tsconfig.worker.json.template | 4 +- .../__name@dasherize__.worker.ts.template | 2 + .../schematics/angular/web-worker/index.ts | 74 +++++-------------- .../angular/web-worker/index_spec.ts | 29 +++++--- tests/legacy-cli/e2e/tests/build/worker.ts | 4 +- 7 files changed, 47 insertions(+), 78 deletions(-) delete mode 100644 packages/schematics/angular/web-worker/files/project-tsconfig/tsconfig.json.template diff --git a/packages/angular_devkit/build_angular/test/browser/web-worker_spec_large.ts b/packages/angular_devkit/build_angular/test/browser/web-worker_spec_large.ts index a7373d110fd0..711a9267e118 100644 --- a/packages/angular_devkit/build_angular/test/browser/web-worker_spec_large.ts +++ b/packages/angular_devkit/build_angular/test/browser/web-worker_spec_large.ts @@ -26,6 +26,8 @@ describe('Browser Builder Web Worker support', () => { const workerFiles: { [k: string]: string } = { 'src/app/dep.ts': `export const foo = 'bar';`, 'src/app/app.worker.ts': ` + /// + import { foo } from './dep'; console.log('hello from worker'); addEventListener('message', ({ data }) => { diff --git a/packages/schematics/angular/web-worker/files/project-tsconfig/tsconfig.json.template b/packages/schematics/angular/web-worker/files/project-tsconfig/tsconfig.json.template deleted file mode 100644 index b170f6d1d0e5..000000000000 --- a/packages/schematics/angular/web-worker/files/project-tsconfig/tsconfig.json.template +++ /dev/null @@ -1,10 +0,0 @@ -{ - "extends": "<%= relativePathToWorkspaceRoot %>/tsconfig.json", - "compilerOptions": { - "lib": [ - "es2018", - "dom", - "webworker" - ], - } -} diff --git a/packages/schematics/angular/web-worker/files/worker-tsconfig/tsconfig.worker.json.template b/packages/schematics/angular/web-worker/files/worker-tsconfig/tsconfig.worker.json.template index 33b92e255762..166d26bac399 100644 --- a/packages/schematics/angular/web-worker/files/worker-tsconfig/tsconfig.worker.json.template +++ b/packages/schematics/angular/web-worker/files/worker-tsconfig/tsconfig.worker.json.template @@ -1,5 +1,5 @@ { - "extends": "./tsconfig.json", + "extends": "<%= relativePathToWorkspaceRoot %>/tsconfig.json", "compilerOptions": { "outDir": "<%= relativePathToWorkspaceRoot %>/out-tsc/worker", "lib": [ @@ -9,6 +9,6 @@ "types": [] }, "include": [ - "**/*.worker.ts" + "src/**/*.worker.ts" ] } diff --git a/packages/schematics/angular/web-worker/files/worker/__name@dasherize__.worker.ts.template b/packages/schematics/angular/web-worker/files/worker/__name@dasherize__.worker.ts.template index 27020fe12b04..b7049b0b80c6 100644 --- a/packages/schematics/angular/web-worker/files/worker/__name@dasherize__.worker.ts.template +++ b/packages/schematics/angular/web-worker/files/worker/__name@dasherize__.worker.ts.template @@ -1,3 +1,5 @@ +/// + addEventListener('message', ({ data }) => { const response = `worker response to ${data}`; postMessage(response); diff --git a/packages/schematics/angular/web-worker/index.ts b/packages/schematics/angular/web-worker/index.ts index 25912657a876..92e6df7ff45c 100644 --- a/packages/schematics/angular/web-worker/index.ts +++ b/packages/schematics/angular/web-worker/index.ts @@ -5,7 +5,7 @@ * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license */ -import { JsonParseMode, parseJsonAst, strings, tags } from '@angular-devkit/core'; +import { JsonParseMode, join, normalize, parseJsonAst, strings, tags } from '@angular-devkit/core'; import { Rule, SchematicContext, SchematicsException, Tree, apply, applyTemplates, chain, mergeWith, move, noop, url, @@ -21,54 +21,16 @@ function addConfig(options: WebWorkerOptions, root: string, tsConfigPath: string return (host: Tree, context: SchematicContext) => { context.logger.debug('updating project configuration.'); - const tsConfigRules = []; - - // Add tsconfig.worker.json. - const relativePathToWorkspaceRoot = root.split('/').map(x => '..').join('/'); - tsConfigRules.push(mergeWith(apply(url('./files/worker-tsconfig'), [ - applyTemplates({ ...options, relativePathToWorkspaceRoot }), - move(root), - ]))); - - // Add project tsconfig.json. - // The project level tsconfig.json with webworker lib is for editor support since - // the dom and webworker libs are mutually exclusive. - // Note: this schematic does not change other tsconfigs to use the project-level tsconfig. - const projectTsConfigPath = `${root}/tsconfig.json`; - if (host.exists(projectTsConfigPath)) { - // If the file already exists, alter it. - const buffer = host.read(projectTsConfigPath); - if (buffer) { - const tsCfgAst = parseJsonAst(buffer.toString(), JsonParseMode.Loose); - if (tsCfgAst.kind != 'object') { - throw new SchematicsException('Invalid tsconfig. Was expecting an object'); - } - const optsAstNode = findPropertyInAstObject(tsCfgAst, 'compilerOptions'); - if (optsAstNode && optsAstNode.kind != 'object') { - throw new SchematicsException( - 'Invalid tsconfig "compilerOptions" property; Was expecting an object.'); - } - const libAstNode = findPropertyInAstObject(tsCfgAst, 'lib'); - if (libAstNode && libAstNode.kind != 'array') { - throw new SchematicsException('Invalid tsconfig "lib" property; expected an array.'); - } - const newLibProp = 'webworker'; - if (libAstNode && !libAstNode.value.includes(newLibProp)) { - const recorder = host.beginUpdate(projectTsConfigPath); - appendValueInAstArray(recorder, libAstNode, newLibProp); - host.commitUpdate(recorder); - } - } - } else { - // Otherwise create it. - tsConfigRules.push(mergeWith(apply(url('./files/project-tsconfig'), [ - applyTemplates({ ...options, relativePathToWorkspaceRoot }), - move(root), - ]))); - } + // todo: replace with the new helper method in a seperate PR + // https://github.com/angular/angular-cli/pull/14207 + const rootNormalized = root.endsWith('/') ? root.slice(0, -1) : root; + const relativePathToWorkspaceRoot = + rootNormalized + ? rootNormalized.split('/').map(x => '..').join('/') + : '.'; // Add worker glob exclusion to tsconfig.app.json. - const workerGlob = '**/*.worker.ts'; + const workerGlob = 'src/**/*.worker.ts'; const buffer = host.read(tsConfigPath); if (buffer) { const tsCfgAst = parseJsonAst(buffer.toString(), JsonParseMode.Loose); @@ -80,17 +42,19 @@ function addConfig(options: WebWorkerOptions, root: string, tsConfigPath: string throw new SchematicsException('Invalid tsconfig "exclude" property; expected an array.'); } - if (filesAstNode && filesAstNode.value.indexOf(workerGlob) == -1) { + if (filesAstNode && !filesAstNode.value.includes(workerGlob)) { const recorder = host.beginUpdate(tsConfigPath); appendValueInAstArray(recorder, filesAstNode, workerGlob); host.commitUpdate(recorder); } } - return chain([ - // Add tsconfigs. - ...tsConfigRules, - ]); + return mergeWith( + apply(url('./files/worker-tsconfig'), [ + applyTemplates({ ...options, relativePathToWorkspaceRoot }), + move(root), + ]), + ); }; } @@ -145,7 +109,7 @@ export default function (options: WebWorkerOptions): Rule { throw new SchematicsException('Option "project" is required.'); } if (!options.target) { - throw new SchematicsException('Option (target) is required.'); + throw new SchematicsException('Option "target" is required.'); } const project = workspace.projects.get(options.project); @@ -169,11 +133,11 @@ export default function (options: WebWorkerOptions): Rule { const parsedPath = parseName(options.path, options.name); options.name = parsedPath.name; options.path = parsedPath.path; - const root = project.root || project.sourceRoot || ''; + const root = project.root || ''; const needWebWorkerConfig = !projectTargetOptions.webWorkerTsConfig; if (needWebWorkerConfig) { - const workerConfigPath = `${root.endsWith('/') ? root : root + '/'}tsconfig.worker.json`; + const workerConfigPath = join(normalize(root), 'tsconfig.worker.json'); projectTargetOptions.webWorkerTsConfig = workerConfigPath; // add worker tsconfig to lint architect target diff --git a/packages/schematics/angular/web-worker/index_spec.ts b/packages/schematics/angular/web-worker/index_spec.ts index 25ef32d9a9b5..bc68cba035d5 100644 --- a/packages/schematics/angular/web-worker/index_spec.ts +++ b/packages/schematics/angular/web-worker/index_spec.ts @@ -20,7 +20,6 @@ describe('Service Worker Schematic', () => { project: 'bar', target: 'build', name: 'app', - // path: 'src/app', snippet: true, }; @@ -54,18 +53,14 @@ describe('Service Worker Schematic', () => { expect(tree.exists(path)).toEqual(true); }); - it('should put a new tsconfig.json file in the project root', async () => { - const tree = await schematicRunner.runSchematicAsync('web-worker', defaultOptions, appTree) - .toPromise(); - const path = '/projects/bar/tsconfig.json'; - expect(tree.exists(path)).toEqual(true); - }); - it('should put the tsconfig.worker.json file in the project root', async () => { const tree = await schematicRunner.runSchematicAsync('web-worker', defaultOptions, appTree) .toPromise(); const path = '/projects/bar/tsconfig.worker.json'; expect(tree.exists(path)).toEqual(true); + + const { compilerOptions } = JSON.parse(tree.readContent(path)); + expect(compilerOptions.outDir).toBe('../../out-tsc/worker'); }); it('should add the webWorkerTsConfig option to workspace', async () => { @@ -80,7 +75,7 @@ describe('Service Worker Schematic', () => { const tree = await schematicRunner.runSchematicAsync('web-worker', defaultOptions, appTree) .toPromise(); const { exclude } = JSON.parse(tree.readContent('/projects/bar/tsconfig.app.json')); - expect(exclude).toContain('**/*.worker.ts'); + expect(exclude).toContain('src/**/*.worker.ts'); }); it('should add snippet to sibling file', async () => { @@ -103,4 +98,20 @@ describe('Service Worker Schematic', () => { 'projects/bar/tsconfig.worker.json', ]); }); + + it(`should add 'tsconfig.worker.json' outside of 'src' directory in root app`, async () => { + const rootAppOptions = { ...appOptions, projectRoot: '', name: 'foo' }; + const workerOptions = { ...defaultOptions, project: 'foo' }; + + appTree = await schematicRunner.runSchematicAsync('application', rootAppOptions, appTree) + .toPromise(); + const tree = await schematicRunner.runSchematicAsync('web-worker', workerOptions, appTree) + .toPromise(); + + const path = '/tsconfig.worker.json'; + expect(tree.exists(path)).toEqual(true); + + const { compilerOptions } = JSON.parse(tree.readContent(path)); + expect(compilerOptions.outDir).toBe('./out-tsc/worker'); + }); }); diff --git a/tests/legacy-cli/e2e/tests/build/worker.ts b/tests/legacy-cli/e2e/tests/build/worker.ts index 7c9398687af6..759bb57e36c8 100644 --- a/tests/legacy-cli/e2e/tests/build/worker.ts +++ b/tests/legacy-cli/e2e/tests/build/worker.ts @@ -14,8 +14,8 @@ export default async function () { const workerPath = join('src', 'app', 'app.worker.ts'); const snippetPath = join('src', 'app', 'app.component.ts'); - const projectTsConfig = join('src', 'tsconfig.json'); - const workerTsConfig = join('src', 'tsconfig.worker.json'); + const projectTsConfig = 'tsconfig.json'; + const workerTsConfig = 'tsconfig.worker.json'; await ng('generate', 'web-worker', 'app'); await expectFileToExist(workerPath);