diff --git a/packages/angular_devkit/build_angular/src/browser/index.ts b/packages/angular_devkit/build_angular/src/browser/index.ts index 9cf285de5084..73d207564458 100644 --- a/packages/angular_devkit/build_angular/src/browser/index.ts +++ b/packages/angular_devkit/build_angular/src/browser/index.ts @@ -40,6 +40,7 @@ import { getStatsConfig, getStylesConfig, getWorkerConfig, + normalizeExtraEntryPoints, } from '../angular-cli-files/models/webpack-configs'; import { IndexHtmlTransform, @@ -238,16 +239,16 @@ export function buildWebpackBrowser( let files: EmittedFiles[] | undefined; const [firstBuild, secondBuild] = buildEvents; + if (isDifferentialLoadingNeeded) { + const scriptsEntryPointName = normalizeExtraEntryPoints(options.scripts || [], 'scripts') + .map(x => x.bundleName); - if (buildEvents.length === 2) { moduleFiles = firstBuild.emittedFiles || []; - noModuleFiles = secondBuild.emittedFiles; - files = moduleFiles.filter(x => x.extension === '.css'); - } else if (options.watch && isDifferentialLoadingNeeded) { - // differential loading is not enabled in watch mode - // but we still want to use module type tags - moduleFiles = firstBuild.emittedFiles || []; - files = moduleFiles.filter(x => x.extension === '.css'); + files = moduleFiles.filter(x => x.extension === '.css' || (x.name && scriptsEntryPointName.includes(x.name))); + + if (buildEvents.length === 2) { + noModuleFiles = secondBuild.emittedFiles; + } } else { const { emittedFiles = [] } = firstBuild; files = emittedFiles.filter(x => x.name !== 'polyfills-es5'); diff --git a/packages/angular_devkit/build_angular/test/browser/scripts-array_spec_large.ts b/packages/angular_devkit/build_angular/test/browser/scripts-array_spec_large.ts index 77edd2f02376..64af80cc7230 100644 --- a/packages/angular_devkit/build_angular/test/browser/scripts-array_spec_large.ts +++ b/packages/angular_devkit/build_angular/test/browser/scripts-array_spec_large.ts @@ -48,7 +48,7 @@ describe('Browser Builder scripts array', () => { afterEach(async () => host.restore().toPromise()); it('works', async () => { - const matches: { [path: string]: string } = { + const matches: Record = { 'scripts.js': 'input-script', 'lazy-script.js': 'lazy-script', 'renamed-script.js': 'pre-rename-script', @@ -71,8 +71,41 @@ describe('Browser Builder scripts array', () => { scripts: getScriptsOption(), } as {}); - for (const fileName of Object.keys(matches)) { - expect(await files[fileName]).toMatch(matches[fileName]); + for (const [fileName, content] of Object.entries(matches)) { + expect(await files[fileName]).toMatch(content); + } + }); + + it('works in watch mode with differential loading', async () => { + const matches: Record = { + 'scripts.js': 'input-script', + 'lazy-script.js': 'lazy-script', + 'renamed-script.js': 'pre-rename-script', + 'renamed-lazy-script.js': 'pre-rename-lazy-script', + 'main.js': 'input-script', + 'index.html': '' + + '' + + '' + + '' + + '' + + '', + }; + + host.writeMultipleFiles(scripts); + host.appendToFile('src/main.ts', '\nimport \'./input-script.js\';'); + + // Enable differential loading + host.appendToFile('browserslist', '\nIE 10'); + + // Remove styles so we don't have to account for them in the index.html order check. + const { files } = await browserBuild(architect, host, target, { + styles: [], + scripts: getScriptsOption(), + watch: true, + } as {}); + + for (const [fileName, content] of Object.entries(matches)) { + expect(await files[fileName]).toMatch(content); } }); diff --git a/tests/legacy-cli/e2e/tests/basic/scripts-array.ts b/tests/legacy-cli/e2e/tests/basic/scripts-array.ts index 504d7a12ee4e..816b40be0a14 100644 --- a/tests/legacy-cli/e2e/tests/basic/scripts-array.ts +++ b/tests/legacy-cli/e2e/tests/basic/scripts-array.ts @@ -1,118 +1,74 @@ // TODO(architect): edit the architect config instead of the cli config. -import { - writeMultipleFiles, - expectFileToMatch, - appendToFile, - expectFileMatchToExist, -} from '../../utils/fs'; +import { oneLineTrim } from 'common-tags'; +import { appendToFile, expectFileToMatch, writeMultipleFiles } from '../../utils/fs'; import { ng } from '../../utils/process'; import { updateJsonFile } from '../../utils/project'; -import { oneLineTrim } from 'common-tags'; -import * as fs from 'fs'; -import * as path from 'path'; -// tslint:disable:max-line-length -export default function() { - return ( - writeMultipleFiles({ - 'src/string-script.js': "console.log('string-script'); var number = 1+1;", - 'src/zstring-script.js': "console.log('zstring-script');", - 'src/fstring-script.js': "console.log('fstring-script');", - 'src/ustring-script.js': "console.log('ustring-script');", - 'src/bstring-script.js': "console.log('bstring-script');", - 'src/astring-script.js': "console.log('astring-script');", - 'src/cstring-script.js': "console.log('cstring-script');", - 'src/input-script.js': "console.log('input-script');", - 'src/lazy-script.js': "console.log('lazy-script');", - 'src/pre-rename-script.js': "console.log('pre-rename-script');", - 'src/pre-rename-lazy-script.js': "console.log('pre-rename-lazy-script');", - }) - .then(() => appendToFile('src/main.ts', "import './string-script.js';")) - .then(() => - updateJsonFile('angular.json', configJson => { - const appArchitect = configJson.projects['test-project'].architect; - appArchitect.build.options.scripts = [ - { input: 'src/string-script.js' }, - { input: 'src/zstring-script.js' }, - { input: 'src/fstring-script.js' }, - { input: 'src/ustring-script.js' }, - { input: 'src/bstring-script.js' }, - { input: 'src/astring-script.js' }, - { input: 'src/cstring-script.js' }, - { input: 'src/input-script.js' }, - { input: 'src/lazy-script.js', inject: false }, - { input: 'src/pre-rename-script.js', bundleName: 'renamed-script' }, - { - input: 'src/pre-rename-lazy-script.js', - bundleName: 'renamed-lazy-script', - inject: false, - }, - ]; - }), - ) - .then(() => ng('build', '--extract-css')) - // files were created successfully - .then(() => expectFileToMatch('dist/test-project/scripts.js', 'string-script')) - .then(() => expectFileToMatch('dist/test-project/scripts.js', 'input-script')) - .then(() => expectFileToMatch('dist/test-project/lazy-script.js', 'lazy-script')) - .then(() => expectFileToMatch('dist/test-project/renamed-script.js', 'pre-rename-script')) - .then(() => - expectFileToMatch('dist/test-project/renamed-lazy-script.js', 'pre-rename-lazy-script'), - ) - // index.html lists the right bundles - .then(() => - expectFileToMatch( - 'dist/test-project/index.html', - oneLineTrim` - - - - - - - - - - - `, - ), - ) - // Ensure scripts can be separately imported from the app. - .then(() => - expectFileToMatch('dist/test-project/main-es5.js', "console.log('string-script');"), - ) - .then(() => - expectFileToMatch('dist/test-project/main-es2015.js', "console.log('string-script');"), - ) - ); - // TODO(architect): disabled until --prod is added. - // Verify uglify, sourcemaps and hashes. Lazy scripts should not get hashes. - // .then(() => ng('build', '--prod', '--source-map')) - // .then(() => expectFileMatchToExist('dist', /scripts\.[0-9a-f]{20}\.js/)) - // .then(fileName => expectFileToMatch(`dist/${fileName}`, 'var number=2;')) - // .then(() => expectFileMatchToExist('dist', /scripts\.[0-9a-f]{20}\.js\.map/)) - // .then(() => expectFileMatchToExist('dist', /renamed-script\.[0-9a-f]{20}\.js/)) - // .then(() => expectFileMatchToExist('dist', /renamed-script\.[0-9a-f]{20}\.js.map/)) - // .then(() => expectFileToMatch('dist/test-project/lazy-script.js', 'lazy-script')) - // .then(() => expectFileToMatch('dist/test-project/enamed-lazy-script.js', 'pre-rename-lazy-script')) +export default async function () { + await writeMultipleFiles({ + 'src/string-script.js': "console.log('string-script'); var number = 1+1;", + 'src/zstring-script.js': "console.log('zstring-script');", + 'src/fstring-script.js': "console.log('fstring-script');", + 'src/ustring-script.js': "console.log('ustring-script');", + 'src/bstring-script.js': "console.log('bstring-script');", + 'src/astring-script.js': "console.log('astring-script');", + 'src/cstring-script.js': "console.log('cstring-script');", + 'src/input-script.js': "console.log('input-script');", + 'src/lazy-script.js': "console.log('lazy-script');", + 'src/pre-rename-script.js': "console.log('pre-rename-script');", + 'src/pre-rename-lazy-script.js': "console.log('pre-rename-lazy-script');", + }); + + await appendToFile('src/main.ts', "import './string-script.js';"); - // // Expect order to be preserved. - // .then(() => { - // const [fileName] = fs.readdirSync('dist') - // .filter(name => name.match(/^scripts\..*\.js$/)); + await updateJsonFile('angular.json', configJson => { + const appArchitect = configJson.projects['test-project'].architect; + appArchitect.build.options.scripts = [ + { input: 'src/string-script.js' }, + { input: 'src/zstring-script.js' }, + { input: 'src/fstring-script.js' }, + { input: 'src/ustring-script.js' }, + { input: 'src/bstring-script.js' }, + { input: 'src/astring-script.js' }, + { input: 'src/cstring-script.js' }, + { input: 'src/input-script.js' }, + { input: 'src/lazy-script.js', inject: false }, + { input: 'src/pre-rename-script.js', bundleName: 'renamed-script' }, + { + input: 'src/pre-rename-lazy-script.js', + bundleName: 'renamed-lazy-script', + inject: false, + }, + ]; + }); - // const content = fs.readFileSync(path.join('dist', fileName), 'utf-8'); - // const re = new RegExp(/['"]string-script['"].*/.source - // + /['"]zstring-script['"].*/.source - // + /['"]fstring-script['"].*/.source - // + /['"]ustring-script['"].*/.source - // + /['"]bstring-script['"].*/.source - // + /['"]astring-script['"].*/.source - // + /['"]cstring-script['"].*/.source - // + /['"]input-script['"]/.source); - // if (!content.match(re)) { - // throw new Error('Scripts are not included in order.'); - // } - // }); + await ng('build', '--extract-css'); + + // files were created successfully + await expectFileToMatch('dist/test-project/scripts.js', 'string-script'); + await expectFileToMatch('dist/test-project/scripts.js', 'input-script'); + await expectFileToMatch('dist/test-project/lazy-script.js', 'lazy-script'); + await expectFileToMatch('dist/test-project/renamed-script.js', 'pre-rename-script'); + await expectFileToMatch('dist/test-project/renamed-lazy-script.js', 'pre-rename-lazy-script'); + + // index.html lists the right bundles + await expectFileToMatch( + 'dist/test-project/index.html', + oneLineTrim` + + + + + + + + + + + `, + ); + // Ensure scripts can be separately imported from the app. + await expectFileToMatch('dist/test-project/main-es5.js', "console.log('string-script');"); + await expectFileToMatch('dist/test-project/main-es2015.js', "console.log('string-script');"); }