Skip to content

Commit

Permalink
feat(@angular/cli): support sourcemaps and minification in scripts
Browse files Browse the repository at this point in the history
Adds sourcemap and minification to javascript added via the `scripts` array in `.angular-cli.json`.

`script-loader` is no longer used, which should help with CSP since it used `eval`.

Scripts will no longer appear in the console output for `ng build`, as they are now assets instead of webpack entry points.

It's no longer possible to have the `output` property of both a `scripts` and a `styles` entry pointing to the same file. This wasn't officially supported or listed in the docs, but used to be possible.

Fix #2796
Fix #7226
Fix #7290

Related to #6872
  • Loading branch information
filipesilva authored and Brocco committed Aug 17, 2017
1 parent b9a62e0 commit e8f27f0
Show file tree
Hide file tree
Showing 12 changed files with 202 additions and 67 deletions.
80 changes: 72 additions & 8 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,6 @@
"resolve": "^1.1.7",
"rxjs": "^5.4.2",
"sass-loader": "^6.0.3",
"script-loader": "^0.7.0",
"semver": "^5.3.0",
"silent-error": "^1.0.0",
"source-map": "^0.5.6",
Expand All @@ -94,6 +93,7 @@
"typescript": "~2.4.2",
"url-loader": "^0.5.7",
"webpack": "~3.4.1",
"webpack-concat-plugin": "1.4.0",
"webpack-dev-middleware": "^1.11.0",
"webpack-dev-server": "~2.5.1",
"webpack-merge": "^4.1.0",
Expand Down
41 changes: 35 additions & 6 deletions packages/@angular/cli/models/webpack-configs/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,11 @@ import * as webpack from 'webpack';
import * as path from 'path';
import { GlobCopyWebpackPlugin } from '../../plugins/glob-copy-webpack-plugin';
import { NamedLazyChunksWebpackPlugin } from '../../plugins/named-lazy-chunks-webpack-plugin';
import { InsertConcatAssetsWebpackPlugin } from '../../plugins/insert-concat-assets-webpack-plugin';
import { extraEntryParser, getOutputHashFormat } from './utils';
import { WebpackConfigOptions } from '../webpack-config';

const ConcatPlugin = require('webpack-concat-plugin');
const ProgressPlugin = require('webpack/lib/ProgressPlugin');
const CircularDependencyPlugin = require('circular-dependency-plugin');

Expand All @@ -15,7 +17,6 @@ const CircularDependencyPlugin = require('circular-dependency-plugin');
*
* require('source-map-loader')
* require('raw-loader')
* require('script-loader')
* require('url-loader')
* require('file-loader')
* require('@angular-devkit/build-optimizer')
Expand Down Expand Up @@ -45,12 +46,40 @@ export function getCommonConfig(wco: WebpackConfigOptions) {
// process global scripts
if (appConfig.scripts.length > 0) {
const globalScripts = extraEntryParser(appConfig.scripts, appRoot, 'scripts');

// add entry points and lazy chunks
globalScripts.forEach(script => {
let scriptPath = `script-loader!${script.path}`;
entryPoints[script.entry] = (entryPoints[script.entry] || []).concat(scriptPath);
const globalScriptsByEntry = globalScripts
.reduce((prev: { entry: string, paths: string[], lazy: boolean }[], curr) => {

let existingEntry = prev.find((el) => el.entry === curr.entry);
if (existingEntry) {
existingEntry.paths.push(curr.path);
// All entries have to be lazy for the bundle to be lazy.
existingEntry.lazy = existingEntry.lazy && curr.lazy;
} else {
prev.push({ entry: curr.entry, paths: [curr.path], lazy: curr.lazy });
}
return prev;
}, []);


// Add a new asset for each entry.
globalScriptsByEntry.forEach((script) => {
const hash = hashFormat.chunk !== '' && !script.lazy ? '.[hash]' : '';
extraPlugins.push(new ConcatPlugin({
uglify: buildOptions.target === 'production' ? { sourceMapIncludeSources: true } : false,
sourceMap: buildOptions.sourcemaps,
name: script.entry,
// Lazy scripts don't get a hash, otherwise they can't be loaded by name.
fileName: `[name]${script.lazy ? '' : hash}.bundle.js`,
filesToConcat: script.paths
}));
});

// Insert all the assets created by ConcatPlugin in the right place in index.html.
extraPlugins.push(new InsertConcatAssetsWebpackPlugin(
globalScriptsByEntry
.filter((el) => !el.lazy)
.map((el) => el.entry)
));
}

// process asset entries
Expand Down
9 changes: 5 additions & 4 deletions packages/@angular/cli/models/webpack-configs/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,15 +73,16 @@ export interface HashFormat {
chunk: string;
extract: string;
file: string;
script: string;
}

export function getOutputHashFormat(option: string, length = 20): HashFormat {
/* tslint:disable:max-line-length */
const hashFormats: { [option: string]: HashFormat } = {
none: { chunk: '', extract: '', file: '' },
media: { chunk: '', extract: '', file: `.[hash:${length}]` },
bundles: { chunk: `.[chunkhash:${length}]`, extract: `.[contenthash:${length}]`, file: '' },
all: { chunk: `.[chunkhash:${length}]`, extract: `.[contenthash:${length}]`, file: `.[hash:${length}]` },
none: { chunk: '', extract: '', file: '' , script: '' },
media: { chunk: '', extract: '', file: `.[hash:${length}]`, script: '' },
bundles: { chunk: `.[chunkhash:${length}]`, extract: `.[contenthash:${length}]`, file: '' , script: '.[hash]' },
all: { chunk: `.[chunkhash:${length}]`, extract: `.[contenthash:${length}]`, file: `.[hash:${length}]`, script: '.[hash]' },
};
/* tslint:enable:max-line-length */
return hashFormats[option] || hashFormats['none'];
Expand Down
2 changes: 1 addition & 1 deletion packages/@angular/cli/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,6 @@
"resolve": "^1.1.7",
"rxjs": "^5.4.2",
"sass-loader": "^6.0.3",
"script-loader": "^0.7.0",
"semver": "^5.1.0",
"silent-error": "^1.0.0",
"source-map-loader": "^0.2.0",
Expand All @@ -79,6 +78,7 @@
"typescript": ">=2.0.0 <2.5.0",
"url-loader": "^0.5.7",
"webpack": "~3.4.1",
"webpack-concat-plugin": "1.4.0",
"webpack-dev-middleware": "^1.11.0",
"webpack-dev-server": "~2.5.1",
"webpack-merge": "^4.1.0",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
// Add assets from `ConcatPlugin` to index.html.

export class InsertConcatAssetsWebpackPlugin {
// Priority list of where to insert asset.
private insertAfter = [
/polyfills(\.[0-9a-f]{20})?\.bundle\.js/,
/inline(\.[0-9a-f]{20})?\.bundle\.js/,
];

constructor(private entryNames: string[]) { }

apply(compiler: any): void {
compiler.plugin('compilation', (compilation: any) => {
compilation.plugin('html-webpack-plugin-before-html-generation',
(htmlPluginData: any, callback: any) => {

const fileNames = this.entryNames.map((entryName) => {
const fileName = htmlPluginData.assets.webpackConcat
&& htmlPluginData.assets.webpackConcat[entryName];

if (!fileName) {
// Something went wrong and the asset was not correctly added.
throw new Error(`Cannot find file for ${entryName} script.`);
}

return fileName;
});

let insertAt = 0;

// TODO: try to figure out if there are duplicate bundle names when adding and throw
for (let el of this.insertAfter) {
const jsIdx = htmlPluginData.assets.js.findIndex((js: string) => js.match(el));
if (jsIdx !== -1) {
insertAt = jsIdx + 1;
break;
}
}

htmlPluginData.assets.js.splice(insertAt, 0, ...fileNames);
callback(null, htmlPluginData);
});
});
}
}
4 changes: 3 additions & 1 deletion packages/@angular/cli/plugins/webpack.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,7 @@ module.exports = {
require('../plugins/suppress-entry-chunks-webpack-plugin')
.SuppressExtractedTextChunksWebpackPlugin,
NamedLazyChunksWebpackPlugin:
require('../plugins/named-lazy-chunks-webpack-plugin').NamedLazyChunksWebpackPlugin
require('../plugins/named-lazy-chunks-webpack-plugin').NamedLazyChunksWebpackPlugin,
InsertConcatAssetsWebpackPlugin:
require('../plugins/insert-concat-assets-webpack-plugin').InsertConcatAssetsWebpackPlugin
};
20 changes: 19 additions & 1 deletion packages/@angular/cli/tasks/eject.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ const ExtractTextPlugin = require('extract-text-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const SilentError = require('silent-error');
const CircularDependencyPlugin = require('circular-dependency-plugin');
const ConcatPlugin = require('webpack-concat-plugin');
const Task = require('../ember-cli/lib/models/task');

const ProgressPlugin = require('webpack/lib/ProgressPlugin');
Expand Down Expand Up @@ -85,6 +86,10 @@ class JsonWebpackSerializer {
};
}

private _insertConcatAssetsWebpackPluginSerialize(value: any): any {
return value.entryNames;
}

private _commonsChunkPluginSerialize(value: any): any {
let minChunks = value.minChunks;
switch (typeof minChunks) {
Expand Down Expand Up @@ -149,6 +154,10 @@ class JsonWebpackSerializer {
return plugin.options;
}

private _concatPlugin(plugin: any) {
return plugin.settings;
}

private _pluginsReplacer(plugins: any[]) {
return plugins.map(plugin => {
let args = plugin.options || undefined;
Expand Down Expand Up @@ -184,6 +193,10 @@ class JsonWebpackSerializer {
args = this._globCopyWebpackPluginSerialize(plugin);
this._addImport('@angular/cli/plugins/webpack', 'GlobCopyWebpackPlugin');
break;
case angularCliPlugins.InsertConcatAssetsWebpackPlugin:
args = this._insertConcatAssetsWebpackPluginSerialize(plugin);
this._addImport('@angular/cli/plugins/webpack', 'InsertConcatAssetsWebpackPlugin');
break;
case webpack.optimize.CommonsChunkPlugin:
args = this._commonsChunkPluginSerialize(plugin);
this._addImport('webpack.optimize', 'CommonsChunkPlugin');
Expand All @@ -210,6 +223,11 @@ class JsonWebpackSerializer {
case LicenseWebpackPlugin:
args = this._licenseWebpackPlugin(plugin);
this._addImport('license-webpack-plugin', 'LicenseWebpackPlugin');
break;
case ConcatPlugin:
args = this._concatPlugin(plugin);
this.variableImports['webpack-concat-plugin'] = 'ConcatPlugin';
break;
default:
if (plugin.constructor.name == 'AngularServiceWorkerPlugin') {
this._addImport('@angular/service-worker/build/webpack', plugin.constructor.name);
Expand Down Expand Up @@ -513,13 +531,13 @@ export default Task.extend({
'postcss-url',
'raw-loader',
'sass-loader',
'script-loader',
'source-map-loader',
'istanbul-instrumenter-loader',
'style-loader',
'stylus-loader',
'url-loader',
'circular-dependency-plugin',
'webpack-concat-plugin',
].forEach((packageName: string) => {
packageJson['devDependencies'][packageName] = ourPackageJson['dependencies'][packageName];
});
Expand Down
6 changes: 1 addition & 5 deletions packages/@angular/cli/utilities/package-chunk-sort.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { ExtraEntry, extraEntryParser } from '../models/webpack-configs/utils';

// Sort chunks according to a predefined order:
// inline, polyfills, all scripts, all styles, vendor, main
// inline, polyfills, all styles, vendor, main
export function packageChunkSort(appConfig: any) {
let entryPoints = ['inline', 'polyfills', 'sw-register'];

Expand All @@ -11,10 +11,6 @@ export function packageChunkSort(appConfig: any) {
}
};

if (appConfig.scripts) {
extraEntryParser(appConfig.scripts, './', 'scripts').forEach(pushExtraEntries);
}

if (appConfig.styles) {
extraEntryParser(appConfig.styles, './', 'styles').forEach(pushExtraEntries);
}
Expand Down
Loading

0 comments on commit e8f27f0

Please sign in to comment.