Skip to content

Commit

Permalink
fix(@angular-devkit/build-angular): avoid attempting to optimize copi…
Browse files Browse the repository at this point in the history
…ed JavaScript assets

When in watch mode (`ng serve`/`ng build --watch`), Webpack's `copy-webpack-plugin` is currently used to implement the project `assets` option within `angular.json`. Files specified by the `assets` option are intended to be copied to the output unmodified and in their original form.  However, if any JavaScript assets were present they previously would have been unintentionally subject to their respective optimization plugins which would result in modified asset outputs and the potential for breakage of the assets. `ng build` outside of watch mode uses a direct file copy with copy-on-write (where supported) to process assets and is therefore not affected by this situation.
When the `copy-webpack-plugin` is used, it adds a `copied` flag to an asset's info metadata. This flag is now used to exclude all such copied JavaScript assets from optimization.
  • Loading branch information
clydin authored and alan-agius4 committed Aug 5, 2021
1 parent 8499cfe commit f5d019f
Show file tree
Hide file tree
Showing 2 changed files with 68 additions and 25 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
/**
* @license
* Copyright Google LLC All Rights Reserved.
*
* 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 { serveWebpackBrowser } from '../../index';
import { executeOnceAndFetch } from '../execute-fetch';
import {
BASE_OPTIONS,
DEV_SERVER_BUILDER_INFO,
describeBuilder,
setupBrowserTarget,
} from '../setup';

describeBuilder(serveWebpackBrowser, DEV_SERVER_BUILDER_INFO, (harness) => {
describe('Behavior: "browser builder assets"', () => {
it('serves a project JavaScript asset unmodified', async () => {
const javascriptFileContent = '/* a comment */const foo = `bar`;\n\n\n';
await harness.writeFile('src/extra.js', javascriptFileContent);

setupBrowserTarget(harness, {
assets: ['src/extra.js'],
optimization: {
scripts: true,
},
});

harness.useTarget('serve', {
...BASE_OPTIONS,
});

const { result, response } = await executeOnceAndFetch(harness, 'extra.js');

expect(result?.success).toBeTrue();
expect(await response?.text()).toBe(javascriptFileContent);
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -96,34 +96,36 @@ export class JavaScriptOptimizerPlugin {
}

const scriptAsset = compilation.getAsset(assetName);
// Skip assets that have already been optimized or are verbatim copies (project assets)
if (!scriptAsset || scriptAsset.info.minimized || scriptAsset.info.copied) {
continue;
}

if (scriptAsset && !scriptAsset.info.minimized) {
const { source: scriptAssetSource, name } = scriptAsset;
let cacheItem;

if (cache) {
const eTag = cache.getLazyHashedEtag(scriptAssetSource);
cacheItem = cache.getItemCache(name, eTag);
const cachedOutput = await cacheItem.getPromise<
{ source: sources.Source } | undefined
>();

if (cachedOutput) {
compilation.updateAsset(name, cachedOutput.source, {
minimized: true,
});
continue;
}
const { source: scriptAssetSource, name } = scriptAsset;
let cacheItem;

if (cache) {
const eTag = cache.getLazyHashedEtag(scriptAssetSource);
cacheItem = cache.getItemCache(name, eTag);
const cachedOutput = await cacheItem.getPromise<
{ source: sources.Source } | undefined
>();

if (cachedOutput) {
compilation.updateAsset(name, cachedOutput.source, {
minimized: true,
});
continue;
}

const { source, map } = scriptAssetSource.sourceAndMap();
scriptsToOptimize.push({
name: scriptAsset.name,
code: typeof source === 'string' ? source : source.toString(),
map,
cacheItem,
});
}

const { source, map } = scriptAssetSource.sourceAndMap();
scriptsToOptimize.push({
name: scriptAsset.name,
code: typeof source === 'string' ? source : source.toString(),
map,
cacheItem,
});
}

if (scriptsToOptimize.length === 0) {
Expand Down

0 comments on commit f5d019f

Please sign in to comment.