Skip to content

feat(@angular/cli): support sourcemaps and minification in scripts #7279

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 1 commit into from
Aug 17, 2017
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
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 @@ -83,7 +83,6 @@
"rsvp": "^3.0.17",
"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 @@ -95,6 +94,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 @@ -68,7 +68,6 @@
"rsvp": "^3.0.17",
"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 @@ -80,6 +79,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