Skip to content

Commit

Permalink
feat(@angular/cli): support ES2015 target
Browse files Browse the repository at this point in the history
  • Loading branch information
filipesilva authored and hansl committed Sep 13, 2017
1 parent cd404e2 commit dea04b1
Show file tree
Hide file tree
Showing 8 changed files with 164 additions and 54 deletions.
105 changes: 63 additions & 42 deletions package-lock.json

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

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@
"stylus": "^0.54.5",
"stylus-loader": "^3.0.1",
"typescript": "~2.4.2",
"uglifyjs-webpack-plugin": "1.0.0-beta.1",
"url-loader": "^0.5.7",
"webpack": "~3.5.5",
"webpack-concat-plugin": "1.4.0",
Expand Down
12 changes: 12 additions & 0 deletions packages/@angular/cli/models/webpack-configs/common.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
import * as webpack from 'webpack';
import * as path from 'path';
import * as CopyWebpackPlugin from 'copy-webpack-plugin';
import * as ts from 'typescript';
import { NamedLazyChunksWebpackPlugin } from '../../plugins/named-lazy-chunks-webpack-plugin';
import { InsertConcatAssetsWebpackPlugin } from '../../plugins/insert-concat-assets-webpack-plugin';
import { extraEntryParser, getOutputHashFormat, AssetPattern } from './utils';
import { isDirectory } from '../../utilities/is-directory';
import { WebpackConfigOptions } from '../webpack-config';
import { readTsconfig } from '../../utilities/read-tsconfig';

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

// Read the tsconfig to determine if we should prefer ES2015 modules.
const tsconfigPath = path.resolve(projectRoot, appConfig.root, appConfig.tsconfig);
const tsConfig = readTsconfig(tsconfigPath);
const supportES2015 = tsConfig.options.target !== ts.ScriptTarget.ES3
&& tsConfig.options.target !== ts.ScriptTarget.ES5;

return {
resolve: {
extensions: ['.ts', '.js'],
modules: ['node_modules', nodeModules],
mainFields: [
...(supportES2015 ? ['es2015'] : []),
'browser', 'module', 'main'
],
symlinks: !buildOptions.preserveSymlinks
},
resolveLoader: {
Expand Down
56 changes: 44 additions & 12 deletions packages/@angular/cli/models/webpack-configs/production.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,23 @@ import * as path from 'path';
import * as webpack from 'webpack';
import * as fs from 'fs';
import * as semver from 'semver';
import * as ts from 'typescript';
import { stripIndent } from 'common-tags';
import { LicenseWebpackPlugin } from 'license-webpack-plugin';
import { PurifyPlugin } from '@angular-devkit/build-optimizer';
import { StaticAssetPlugin } from '../../plugins/static-asset';
import { GlobCopyWebpackPlugin } from '../../plugins/glob-copy-webpack-plugin';
import { WebpackConfigOptions } from '../webpack-config';
import { readTsconfig } from '../../utilities/read-tsconfig';

const UglifyJSPlugin = require('uglifyjs-webpack-plugin');


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

let extraPlugins: any[] = [];
let entryPoints: {[key: string]: string[]} = {};
let entryPoints: { [key: string]: string[] } = {};

if (appConfig.serviceWorker) {
const nodeModules = path.resolve(projectRoot, 'node_modules');
Expand Down Expand Up @@ -66,7 +70,7 @@ export const getProdConfig = function (wco: WebpackConfigOptions) {
extraPlugins.push(new GlobCopyWebpackPlugin({
patterns: [
'ngsw-manifest.json',
{glob: 'ngsw-manifest.json', input: path.resolve(projectRoot, appConfig.root), output: ''}
{ glob: 'ngsw-manifest.json', input: path.resolve(projectRoot, appConfig.root), output: '' }
],
globOptions: {
cwd: projectRoot,
Expand Down Expand Up @@ -99,7 +103,7 @@ export const getProdConfig = function (wco: WebpackConfigOptions) {
}));
}

const uglifyCompressOptions: any = { screw_ie8: true, warnings: buildOptions.verbose };
const uglifyCompressOptions: any = {};

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

// Read the tsconfig to determine if we should apply ES6 uglify.
const tsconfigPath = path.resolve(projectRoot, appConfig.root, appConfig.tsconfig);
const tsConfig = readTsconfig(tsconfigPath);
const supportES2015 = tsConfig.options.target !== ts.ScriptTarget.ES3
&& tsConfig.options.target !== ts.ScriptTarget.ES5;

if (supportES2015) {
extraPlugins.push(new UglifyJSPlugin({
sourceMap: buildOptions.sourcemaps,
uglifyOptions: {
ecma: 6,
warnings: buildOptions.verbose,
ie8: false,
mangle: true,
compress: uglifyCompressOptions,
output: {
ascii_only: true,
comments: false
},
}
}));
} else {
uglifyCompressOptions.screw_ie8 = true;
uglifyCompressOptions.warnings = buildOptions.verbose;
extraPlugins.push(new webpack.optimize.UglifyJsPlugin(<any>{
mangle: { screw_ie8: true },
compress: uglifyCompressOptions,
output: { ascii_only: true },
sourceMap: buildOptions.sourcemaps,
comments: false
}));

}

return {
entry: entryPoints,
plugins: extraPlugins.concat([
plugins: [
new webpack.EnvironmentPlugin({
'NODE_ENV': 'production'
}),
new webpack.HashedModuleIdsPlugin(),
new webpack.optimize.ModuleConcatenationPlugin(),
new webpack.optimize.UglifyJsPlugin(<any>{
mangle: { screw_ie8: true },
compress: uglifyCompressOptions,
output: { ascii_only: true },
sourceMap: buildOptions.sourcemaps,
comments: false
})
])
...extraPlugins
]
};
};
1 change: 1 addition & 0 deletions packages/@angular/cli/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@
"stylus": "^0.54.5",
"stylus-loader": "^3.0.1",
"typescript": ">=2.0.0 <2.6.0",
"uglifyjs-webpack-plugin": "1.0.0-beta.1",
"url-loader": "^0.5.7",
"webpack": "~3.5.5",
"webpack-concat-plugin": "1.4.0",
Expand Down
10 changes: 10 additions & 0 deletions packages/@angular/cli/tasks/eject.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ const HtmlWebpackPlugin = require('html-webpack-plugin');
const SilentError = require('silent-error');
const CircularDependencyPlugin = require('circular-dependency-plugin');
const ConcatPlugin = require('webpack-concat-plugin');
const UglifyJSPlugin = require('uglifyjs-webpack-plugin');
const Task = require('../ember-cli/lib/models/task');

const ProgressPlugin = require('webpack/lib/ProgressPlugin');
Expand Down Expand Up @@ -158,6 +159,10 @@ class JsonWebpackSerializer {
return plugin.settings;
}

private _uglifyjsPlugin(plugin: any) {
return plugin.options;
}

private _pluginsReplacer(plugins: any[]) {
return plugins.map(plugin => {
let args = plugin.options || undefined;
Expand Down Expand Up @@ -229,6 +234,10 @@ class JsonWebpackSerializer {
args = this._concatPlugin(plugin);
this.variableImports['webpack-concat-plugin'] = 'ConcatPlugin';
break;
case UglifyJSPlugin:
args = this._uglifyjsPlugin(plugin);
this.variableImports['uglifyjs-webpack-plugin'] = 'UglifyJsPlugin';
break;
default:
if (plugin.constructor.name == 'AngularServiceWorkerPlugin') {
this._addImport('@angular/service-worker/build/webpack', plugin.constructor.name);
Expand Down Expand Up @@ -546,6 +555,7 @@ export default Task.extend({
'circular-dependency-plugin',
'webpack-concat-plugin',
'copy-webpack-plugin',
'uglifyjs-webpack-plugin',
].forEach((packageName: string) => {
packageJson['devDependencies'][packageName] = ourPackageJson['dependencies'][packageName];
});
Expand Down
10 changes: 10 additions & 0 deletions packages/@angular/cli/utilities/read-tsconfig.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import * as path from 'path';
import * as ts from 'typescript';

export function readTsconfig(tsconfigPath: string) {
const configResult = ts.readConfigFile(tsconfigPath, ts.sys.readFile);
const tsConfig = ts.parseJsonConfigFileContent(configResult.config, ts.sys,
path.dirname(tsconfigPath), undefined, tsconfigPath);
return tsConfig;
}

23 changes: 23 additions & 0 deletions tests/e2e/tests/build/script-target.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { appendToFile, expectFileToMatch } from '../../utils/fs';
import { ng } from '../../utils/process';
import { expectToFail } from '../../utils/utils';
import { updateJsonFile } from '../../utils/project';


export default function () {
return Promise.resolve()
// Force import a known ES6 module and build with prod.
// ES6 modules will cause UglifyJS to fail on a ES5 compilation target (default).
.then(() => appendToFile('src/main.ts', `
import * as es6module from '@angular/core/@angular/core';
console.log(es6module);
`))
.then(() => expectToFail(() => ng('build', '--prod')))
.then(() => updateJsonFile('tsconfig.json', configJson => {
const compilerOptions = configJson['compilerOptions'];
compilerOptions['target'] = 'es2015';
}))
.then(() => ng('build', '--prod', '--output-hashing=none'))
// Check class constructors are present in the vendor output.
.then(() => expectFileToMatch('dist/vendor.bundle.js', /class \w{constructor\(\){/));
}

0 comments on commit dea04b1

Please sign in to comment.