Skip to content

Re enable disabled ivy tests #15384

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 8 commits into from
Aug 30, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
61 changes: 30 additions & 31 deletions packages/angular_devkit/build_angular/src/app-shell/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,13 @@ import { JsonObject, experimental, join, normalize, resolve, schema } from '@ang
import { NodeJsSyncHost } from '@angular-devkit/core/node';
import * as fs from 'fs';
import * as path from 'path';
import { readTsconfig } from '../angular-cli-files/utilities/read-tsconfig';
import { augmentAppWithServiceWorker } from '../angular-cli-files/utilities/service-worker';
import { BrowserBuilderOutput } from '../browser';
import { Schema as BrowserBuilderSchema } from '../browser/schema';
import { ServerBuilderOutput } from '../server';
import { Schema as BuildWebpackAppShellSchema } from './schema';


async function _renderUniversal(
options: BuildWebpackAppShellSchema,
context: BuilderContext,
Expand All @@ -31,40 +31,48 @@ async function _renderUniversal(
const browserIndexOutputPath = path.join(browserResult.outputPath || '', 'index.html');
const indexHtml = fs.readFileSync(browserIndexOutputPath, 'utf8');
const serverBundlePath = await _getServerModuleBundlePath(options, context, serverResult);

const root = context.workspaceRoot;

// Get browser target options.
const browserTarget = targetFromTargetString(options.browserTarget);
const rawBrowserOptions = await context.getTargetOptions(browserTarget);
const browserBuilderName = await context.getBuilderNameForTarget(browserTarget);
const browserOptions = await context.validateOptions<JsonObject & BrowserBuilderSchema>(
rawBrowserOptions,
browserBuilderName,
);

// Determine if browser app was compiled using Ivy.
const { options: compilerOptions } = readTsconfig(browserOptions.tsConfig, context.workspaceRoot);
const ivy = compilerOptions.enableIvy;

// Initialize zone.js
const zonePackage = require.resolve('zone.js', { paths: [root] });
await import(zonePackage);

// Load platform server module renderer
const platformServerPackage = require.resolve('@angular/platform-server', { paths: [root] });
const renderModuleFactory = await import(platformServerPackage)
const renderOpts = {
document: indexHtml,
url: options.route,
};

// Render app to HTML using Ivy or VE
const html = await import(platformServerPackage)
// tslint:disable-next-line:no-implicit-dependencies
.then((m: typeof import('@angular/platform-server')) => m.renderModuleFactory);
.then((m: typeof import('@angular/platform-server')) =>
ivy
? m.renderModule(require(serverBundlePath).AppServerModule, renderOpts)
: m.renderModuleFactory(require(serverBundlePath).AppServerModuleNgFactory, renderOpts),
);

const AppServerModuleNgFactory = require(serverBundlePath).AppServerModuleNgFactory;
// Overwrite the client index file.
const outputIndexPath = options.outputIndexPath
? path.join(root, options.outputIndexPath)
: browserIndexOutputPath;

// Render to HTML and overwrite the client index file.
const html = await renderModuleFactory(AppServerModuleNgFactory, {
document: indexHtml,
url: options.route,
});

fs.writeFileSync(outputIndexPath, html);

const browserTarget = targetFromTargetString(options.browserTarget);
const rawBrowserOptions = await context.getTargetOptions(browserTarget);
const browserBuilderName = await context.getBuilderNameForTarget(browserTarget);
const browserOptions = await context.validateOptions<JsonObject & BrowserBuilderSchema>(
rawBrowserOptions,
browserBuilderName,
);

if (browserOptions.serviceWorker) {
const host = new NodeJsSyncHost();
// Create workspace.
Expand All @@ -81,10 +89,7 @@ async function _renderUniversal(
if (!projectName) {
throw new Error('Must either have a target from the context or a default project.');
}
const projectRoot = resolve(
workspace.root,
normalize(workspace.getProject(projectName).root),
);
const projectRoot = resolve(workspace.root, normalize(workspace.getProject(projectName).root));

await augmentAppWithServiceWorker(
host,
Expand All @@ -99,7 +104,6 @@ async function _renderUniversal(
return browserResult;
}


async function _getServerModuleBundlePath(
options: BuildWebpackAppShellSchema,
context: BuilderContext,
Expand All @@ -121,7 +125,6 @@ async function _getServerModuleBundlePath(
}
}


async function _appShellBuilder(
options: JsonObject & BuildWebpackAppShellSchema,
context: BuilderContext,
Expand All @@ -139,7 +142,7 @@ async function _appShellBuilder(

try {
const [browserResult, serverResult] = await Promise.all([
browserTargetRun.result as {} as BrowserBuilderOutput,
(browserTargetRun.result as {}) as BrowserBuilderOutput,
serverTargetRun.result,
]);

Expand All @@ -154,12 +157,8 @@ async function _appShellBuilder(
return { success: false, error: err.message };
} finally {
// Just be good citizens and stop those jobs.
await Promise.all([
browserTargetRun.stop(),
serverTargetRun.stop(),
]);
await Promise.all([browserTargetRun.stop(), serverTargetRun.stop()]);
}
}


export default createBuilder(_appShellBuilder);
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import { createArchitect, host, veEnabled } from '../utils';


// DISABLED_FOR_IVY These should pass but are currently not supported
// See https://github.com/angular/angular-cli/issues/15383 for details.
(veEnabled ? describe : xdescribe)('AppShell Builder', () => {
const target = { project: 'app', target: 'app-shell' };
let architect: Architect;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,14 @@ describe('Browser Builder lazy modules', () => {
);
}

function hasMissingModuleError(logger: TestLogger) {
// TS type error when using import().
return logger.includes('Cannot find module') ||
// Webpack error when using import() on a rebuild.
// There is no TS error because the type checker is forked on rebuilds.
logger.includes('Module not found');
}

const cases: [string, Record<string, string>][] = [
['string', lazyModuleStringImport],
['function', lazyModuleFnImport],
Expand All @@ -63,50 +71,6 @@ describe('Browser Builder lazy modules', () => {
expect('lazy-lazy-module.js' in files).toBe(true);
});

it('should show error when lazy route is invalid on watch mode AOT', async () => {
if (!veEnabled && name === 'string') {
pending('Does not apply to Ivy.');

return;
}

// DISABLED_FOR_IVY - These should pass but are currently not supported
if (!veEnabled) {
pending('Broken in Ivy');

return;
}

host.writeMultipleFiles(lazyModuleFiles);
host.writeMultipleFiles(imports);
host.replaceInFile('src/app/app.module.ts', 'lazy.module', 'invalid.module');

const logger = new TestLogger('rebuild-lazy-errors');
const overrides = { watch: true, aot: true };
const run = await architect.scheduleTarget(target, overrides, { logger });
await run.output
.pipe(
timeout(15000),
tap(buildEvent => expect(buildEvent.success).toBe(false)),
tap(() => {
// Webpack error when using loadchildren string syntax.
const hasMissingModuleError =
logger.includes('Could not resolve module') ||
// TS type error when using import().
logger.includes('Cannot find module') ||
// Webpack error when using import() on a rebuild.
// There is no TS error because the type checker is forked on rebuilds.
logger.includes('Module not found');
expect(hasMissingModuleError).toBe(true, 'Should show missing module error');
logger.clear();
host.appendToFile('src/main.ts', ' ');
}),
take(2),
)
.toPromise();
await run.stop();
});

it('supports lazy bundle for lazy routes with AOT', async () => {
host.writeMultipleFiles(lazyModuleFiles);
host.writeMultipleFiles(imports);
Expand All @@ -124,6 +88,52 @@ describe('Browser Builder lazy modules', () => {
});
}

// Errors for missing lazy routes are only supported with function syntax.
// `ngProgram.listLazyRoutes` will ignore invalid lazy routes in the route map.
describe(`Load children errors with function syntax`, () => {
it('should show error when lazy route is invalid', async () => {
host.writeMultipleFiles(lazyModuleFiles);
host.writeMultipleFiles(lazyModuleFnImport);
host.replaceInFile('src/app/app.module.ts', 'lazy.module', 'invalid.module');

const logger = new TestLogger('build-lazy-errors');
const run = await architect.scheduleTarget(target, {}, { logger });
const output = await run.result;
expect(output.success).toBe(false);
expect(hasMissingModuleError(logger)).toBe(true, 'Should show missing module error');
});

it('should show error when lazy route is invalid on watch mode AOT', async () => {
host.writeMultipleFiles(lazyModuleFiles);
host.writeMultipleFiles(lazyModuleFnImport);

let buildNumber = 0;
const logger = new TestLogger('rebuild-lazy-errors');
const overrides = { watch: true, aot: true };
const run = await architect.scheduleTarget(target, overrides, { logger });
await run.output
.pipe(
timeout(15000),
tap(buildEvent => {
buildNumber++;
switch (buildNumber) {
case 1:
expect(buildEvent.success).toBe(true);
host.replaceInFile('src/app/app.module.ts', 'lazy.module', 'invalid.module');
logger.clear();
break;
case 2:
expect(buildEvent.success).toBe(false);
break;
}
}),
take(2),
)
.toPromise();
await run.stop();
});
});

it(`supports lazy bundle for import() calls`, async () => {
host.writeMultipleFiles({
'src/lazy-module.ts': 'export const value = 42;',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -268,7 +268,7 @@ describe('Browser Builder rebuilds', () => {
it('rebuilds after errors in AOT', async () => {
// DISABLED_FOR_IVY - These should pass but are currently not supported
if (!veEnabled) {
pending('Broken in Ivy');
pending('Broken in Ivy: https://github.com/angular/angular/issues/32214');

return;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,7 @@ import { Architect } from '@angular-devkit/architect';
import * as path from 'path';
import { browserBuild, createArchitect, host, veEnabled } from '../utils';

// DISABLED_FOR_IVY These should pass but are currently not supported
(veEnabled ? describe : xdescribe)('Browser Builder external source map', () => {
describe('Browser Builder external source map', () => {
const target = { project: 'app', target: 'build' };
let architect: Architect;

Expand All @@ -30,8 +29,9 @@ import { browserBuild, createArchitect, host, veEnabled } from '../utils';
};

const { files } = await browserBuild(architect, host, target, overrides);
const sourcePath = JSON.parse(await files['vendor.js.map']).sources[0];
expect(path.extname(sourcePath)).toBe('.ts', `${sourcePath} extention should be '.ts'`);
const sourcePaths: string[] = JSON.parse(await files['vendor.js.map']).sources;
const hasTsSourcePaths = sourcePaths.some(p => path.extname(p) == '.ts');
expect(hasTsSourcePaths).toBe(true, `vendor.js.map should have '.ts' extentions`);
});

it(`works when using deprecated 'vendorSourceMap'`, async () => {
Expand All @@ -44,8 +44,9 @@ import { browserBuild, createArchitect, host, veEnabled } from '../utils';
};

const { files } = await browserBuild(architect, host, target, overrides);
const sourcePath = JSON.parse(await files['vendor.js.map']).sources[0];
expect(path.extname(sourcePath)).toBe('.ts', `${sourcePath} extention should be '.ts'`);
const sourcePaths: string[] = JSON.parse(await files['vendor.js.map']).sources;
const hasTsSourcePaths = sourcePaths.some(p => path.extname(p) == '.ts');
expect(hasTsSourcePaths).toBe(true, `vendor.js.map should have '.ts' extentions`);
});

it('does not map sourcemaps from external library when disabled', async () => {
Expand All @@ -58,7 +59,8 @@ import { browserBuild, createArchitect, host, veEnabled } from '../utils';
};

const { files } = await browserBuild(architect, host, target, overrides);
const sourcePath = JSON.parse(await files['vendor.js.map']).sources[0];
expect(path.extname(sourcePath)).toBe('.js', `${sourcePath} extention should be '.ts'`);
const sourcePaths: string[] = JSON.parse(await files['vendor.js.map']).sources;
const hasTsSourcePaths = sourcePaths.some(p => path.extname(p) == '.ts');
expect(hasTsSourcePaths).toBe(false, `vendor.js.map not should have '.ts' extentions`);
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,7 @@ import { BrowserBuilderOutput } from '../../src/browser';
import { createArchitect, host, veEnabled } from '../utils';


// DISABLED_FOR_IVY These should pass but are currently not supported
(veEnabled ? describe : xdescribe)('Server Builder', () => {
describe('Server Builder', () => {
const target = { project: 'app', target: 'server' };
let architect: Architect;

Expand All @@ -33,7 +32,12 @@ import { createArchitect, host, veEnabled } from '../utils';

const fileName = join(outputPath, 'main.js');
const content = virtualFs.fileBufferToString(host.scopedSync().read(normalize(fileName)));
expect(content).toMatch(/AppServerModuleNgFactory/);

if (veEnabled) {
expect(content).toMatch(/AppServerModuleNgFactory/);
} else {
expect(content).toMatch(/AppServerModule\.ngModuleDef/);
}

await run.stop();
});
Expand Down Expand Up @@ -68,16 +72,10 @@ import { createArchitect, host, veEnabled } from '../utils';

it('supports sourcemaps', async () => {
const overrides = { sourceMap: true };

const run = await architect.scheduleTarget(target, overrides);
const output = await run.result as BrowserBuilderOutput;
expect(output.success).toBe(true);

const fileName = join(outputPath, 'main.js');
const content = virtualFs.fileBufferToString(host.scopedSync().read(normalize(fileName)));
expect(content).toMatch(/AppServerModuleNgFactory/);
expect(host.scopedSync().exists(join(outputPath, 'main.js.map'))).toBeTruthy();

await run.stop();
});

Expand Down Expand Up @@ -144,7 +142,11 @@ import { createArchitect, host, veEnabled } from '../utils';

const fileName = join(outputPath, 'main.js');
const content = virtualFs.fileBufferToString(host.scopedSync().read(normalize(fileName)));
expect(content).toMatch(/AppServerModuleNgFactory/);
if (veEnabled) {
expect(content).toMatch(/AppServerModuleNgFactory/);
} else {
expect(content).toMatch(/AppServerModule\.ngModuleDef/);
}
}),
take(1),
).toPromise();
Expand Down
3 changes: 2 additions & 1 deletion packages/ngtools/webpack/src/angular_compiler_plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -596,7 +596,8 @@ export class AngularCompilerPlugin {
// Only do the unused TS files checks when under Ivy
// since previously we did include unused files in the compilation
// See: https://github.com/angular/angular-cli/pull/15030
if (!this._compilerOptions.enableIvy) {
// Don't do checks for compilations with errors, since that can result in a partial compilation.
if (!this._compilerOptions.enableIvy || compilation.errors.length > 0) {
return;
}

Expand Down
Loading