Skip to content

Commit 800484d

Browse files
committed
feat(@angular/cli): support ES2015 target
1 parent 642f6ba commit 800484d

File tree

8 files changed

+164
-54
lines changed

8 files changed

+164
-54
lines changed

package-lock.json

+63-42
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

+1
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,7 @@
9292
"stylus": "^0.54.5",
9393
"stylus-loader": "^3.0.1",
9494
"typescript": "~2.4.2",
95+
"uglifyjs-webpack-plugin": "1.0.0-beta.1",
9596
"url-loader": "^0.5.7",
9697
"webpack": "~3.5.5",
9798
"webpack-concat-plugin": "1.4.0",

packages/@angular/cli/models/webpack-configs/common.ts

+12
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
import * as webpack from 'webpack';
22
import * as path from 'path';
33
import * as CopyWebpackPlugin from 'copy-webpack-plugin';
4+
import * as ts from 'typescript';
45
import { NamedLazyChunksWebpackPlugin } from '../../plugins/named-lazy-chunks-webpack-plugin';
56
import { InsertConcatAssetsWebpackPlugin } from '../../plugins/insert-concat-assets-webpack-plugin';
67
import { extraEntryParser, getOutputHashFormat, AssetPattern } from './utils';
78
import { isDirectory } from '../../utilities/is-directory';
89
import { WebpackConfigOptions } from '../webpack-config';
10+
import { readTsconfig } from '../../utilities/read-tsconfig';
911

1012
const ConcatPlugin = require('webpack-concat-plugin');
1113
const ProgressPlugin = require('webpack/lib/ProgressPlugin');
@@ -149,10 +151,20 @@ export function getCommonConfig(wco: WebpackConfigOptions) {
149151
extraPlugins.push(new NamedLazyChunksWebpackPlugin());
150152
}
151153

154+
// Read the tsconfig to determine if we should prefer ES2015 modules.
155+
const tsconfigPath = path.resolve(projectRoot, appConfig.root, appConfig.tsconfig);
156+
const tsConfig = readTsconfig(tsconfigPath);
157+
const supportES2015 = tsConfig.options.target !== ts.ScriptTarget.ES3
158+
&& tsConfig.options.target !== ts.ScriptTarget.ES5;
159+
152160
return {
153161
resolve: {
154162
extensions: ['.ts', '.js'],
155163
modules: ['node_modules', nodeModules],
164+
mainFields: [
165+
...(supportES2015 ? ['es2015'] : []),
166+
'browser', 'module', 'main'
167+
],
156168
symlinks: !buildOptions.preserveSymlinks
157169
},
158170
resolveLoader: {

packages/@angular/cli/models/webpack-configs/production.ts

+44-12
Original file line numberDiff line numberDiff line change
@@ -2,19 +2,23 @@ import * as path from 'path';
22
import * as webpack from 'webpack';
33
import * as fs from 'fs';
44
import * as semver from 'semver';
5+
import * as ts from 'typescript';
56
import { stripIndent } from 'common-tags';
67
import { LicenseWebpackPlugin } from 'license-webpack-plugin';
78
import { PurifyPlugin } from '@angular-devkit/build-optimizer';
89
import { StaticAssetPlugin } from '../../plugins/static-asset';
910
import { GlobCopyWebpackPlugin } from '../../plugins/glob-copy-webpack-plugin';
1011
import { WebpackConfigOptions } from '../webpack-config';
12+
import { readTsconfig } from '../../utilities/read-tsconfig';
13+
14+
const UglifyJSPlugin = require('uglifyjs-webpack-plugin');
1115

1216

1317
export const getProdConfig = function (wco: WebpackConfigOptions) {
1418
const { projectRoot, buildOptions, appConfig } = wco;
1519

1620
let extraPlugins: any[] = [];
17-
let entryPoints: {[key: string]: string[]} = {};
21+
let entryPoints: { [key: string]: string[] } = {};
1822

1923
if (appConfig.serviceWorker) {
2024
const nodeModules = path.resolve(projectRoot, 'node_modules');
@@ -66,7 +70,7 @@ export const getProdConfig = function (wco: WebpackConfigOptions) {
6670
extraPlugins.push(new GlobCopyWebpackPlugin({
6771
patterns: [
6872
'ngsw-manifest.json',
69-
{glob: 'ngsw-manifest.json', input: path.resolve(projectRoot, appConfig.root), output: ''}
73+
{ glob: 'ngsw-manifest.json', input: path.resolve(projectRoot, appConfig.root), output: '' }
7074
],
7175
globOptions: {
7276
cwd: projectRoot,
@@ -99,7 +103,7 @@ export const getProdConfig = function (wco: WebpackConfigOptions) {
99103
}));
100104
}
101105

102-
const uglifyCompressOptions: any = { screw_ie8: true, warnings: buildOptions.verbose };
106+
const uglifyCompressOptions: any = {};
103107

104108
if (buildOptions.buildOptimizer) {
105109
// This plugin must be before webpack.optimize.UglifyJsPlugin.
@@ -110,21 +114,49 @@ export const getProdConfig = function (wco: WebpackConfigOptions) {
110114
uglifyCompressOptions.passes = 3;
111115
}
112116

117+
// Read the tsconfig to determine if we should apply ES6 uglify.
118+
const tsconfigPath = path.resolve(projectRoot, appConfig.root, appConfig.tsconfig);
119+
const tsConfig = readTsconfig(tsconfigPath);
120+
const supportES2015 = tsConfig.options.target !== ts.ScriptTarget.ES3
121+
&& tsConfig.options.target !== ts.ScriptTarget.ES5;
122+
123+
if (supportES2015) {
124+
extraPlugins.push(new UglifyJSPlugin({
125+
sourceMap: buildOptions.sourcemaps,
126+
uglifyOptions: {
127+
ecma: 6,
128+
warnings: buildOptions.verbose,
129+
ie8: false,
130+
mangle: true,
131+
compress: uglifyCompressOptions,
132+
output: {
133+
ascii_only: true,
134+
comments: false
135+
},
136+
}
137+
}));
138+
} else {
139+
uglifyCompressOptions.screw_ie8 = true;
140+
uglifyCompressOptions.warnings = buildOptions.verbose;
141+
extraPlugins.push(new webpack.optimize.UglifyJsPlugin(<any>{
142+
mangle: { screw_ie8: true },
143+
compress: uglifyCompressOptions,
144+
output: { ascii_only: true },
145+
sourceMap: buildOptions.sourcemaps,
146+
comments: false
147+
}));
148+
149+
}
150+
113151
return {
114152
entry: entryPoints,
115-
plugins: extraPlugins.concat([
153+
plugins: [
116154
new webpack.EnvironmentPlugin({
117155
'NODE_ENV': 'production'
118156
}),
119157
new webpack.HashedModuleIdsPlugin(),
120158
new webpack.optimize.ModuleConcatenationPlugin(),
121-
new webpack.optimize.UglifyJsPlugin(<any>{
122-
mangle: { screw_ie8: true },
123-
compress: uglifyCompressOptions,
124-
output: { ascii_only: true },
125-
sourceMap: buildOptions.sourcemaps,
126-
comments: false
127-
})
128-
])
159+
...extraPlugins
160+
]
129161
};
130162
};

packages/@angular/cli/package.json

+1
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@
7676
"stylus": "^0.54.5",
7777
"stylus-loader": "^3.0.1",
7878
"typescript": ">=2.0.0 <2.6.0",
79+
"uglifyjs-webpack-plugin": "1.0.0-beta.1",
7980
"url-loader": "^0.5.7",
8081
"webpack": "~3.5.5",
8182
"webpack-concat-plugin": "1.4.0",

packages/@angular/cli/tasks/eject.ts

+10
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ const HtmlWebpackPlugin = require('html-webpack-plugin');
2424
const SilentError = require('silent-error');
2525
const CircularDependencyPlugin = require('circular-dependency-plugin');
2626
const ConcatPlugin = require('webpack-concat-plugin');
27+
const UglifyJSPlugin = require('uglifyjs-webpack-plugin');
2728
const Task = require('../ember-cli/lib/models/task');
2829

2930
const ProgressPlugin = require('webpack/lib/ProgressPlugin');
@@ -158,6 +159,10 @@ class JsonWebpackSerializer {
158159
return plugin.settings;
159160
}
160161

162+
private _uglifyjsPlugin(plugin: any) {
163+
return plugin.options;
164+
}
165+
161166
private _pluginsReplacer(plugins: any[]) {
162167
return plugins.map(plugin => {
163168
let args = plugin.options || undefined;
@@ -229,6 +234,10 @@ class JsonWebpackSerializer {
229234
args = this._concatPlugin(plugin);
230235
this.variableImports['webpack-concat-plugin'] = 'ConcatPlugin';
231236
break;
237+
case UglifyJSPlugin:
238+
args = this._uglifyjsPlugin(plugin);
239+
this.variableImports['uglifyjs-webpack-plugin'] = 'UglifyJsPlugin';
240+
break;
232241
default:
233242
if (plugin.constructor.name == 'AngularServiceWorkerPlugin') {
234243
this._addImport('@angular/service-worker/build/webpack', plugin.constructor.name);
@@ -546,6 +555,7 @@ export default Task.extend({
546555
'circular-dependency-plugin',
547556
'webpack-concat-plugin',
548557
'copy-webpack-plugin',
558+
'uglifyjs-webpack-plugin',
549559
].forEach((packageName: string) => {
550560
packageJson['devDependencies'][packageName] = ourPackageJson['dependencies'][packageName];
551561
});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import * as path from 'path';
2+
import * as ts from 'typescript';
3+
4+
export function readTsconfig(tsconfigPath: string) {
5+
const configResult = ts.readConfigFile(tsconfigPath, ts.sys.readFile);
6+
const tsConfig = ts.parseJsonConfigFileContent(configResult.config, ts.sys,
7+
path.dirname(tsconfigPath), undefined, tsconfigPath);
8+
return tsConfig;
9+
}
10+
+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import { appendToFile, expectFileToMatch } from '../../utils/fs';
2+
import { ng } from '../../utils/process';
3+
import { expectToFail } from '../../utils/utils';
4+
import { updateJsonFile } from '../../utils/project';
5+
6+
7+
export default function () {
8+
return Promise.resolve()
9+
// Force import a known ES6 module and build with prod.
10+
// ES6 modules will cause UglifyJS to fail on a ES5 compilation target (default).
11+
.then(() => appendToFile('src/main.ts', `
12+
import * as es6module from '@angular/core/@angular/core';
13+
console.log(es6module);
14+
`))
15+
.then(() => expectToFail(() => ng('build', '--prod')))
16+
.then(() => updateJsonFile('tsconfig.json', configJson => {
17+
const compilerOptions = configJson['compilerOptions'];
18+
compilerOptions['target'] = 'es2015';
19+
}))
20+
.then(() => ng('build', '--prod', '--output-hashing=none'))
21+
// Check class constructors are present in the vendor output.
22+
.then(() => expectFileToMatch('dist/vendor.bundle.js', /class \w{constructor\(\){/));
23+
}

0 commit comments

Comments
 (0)