Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit c93ffca

Browse files
committedJan 19, 2017
refactor(build): consolidate build options
1 parent cd296bc commit c93ffca

20 files changed

+237
-323
lines changed
 

‎package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,7 @@
115115
"walk-sync": "^0.2.6",
116116
"webpack": "2.2.0",
117117
"webpack-dev-server": "2.2.0-rc.0",
118-
"webpack-merge": "^0.14.0",
118+
"webpack-merge": "^2.4.0",
119119
"webpack-sources": "^0.1.3",
120120
"zone.js": "^0.7.2"
121121
},

‎packages/angular-cli/commands/build.run.ts

Lines changed: 2 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,35 +1,8 @@
11
import { Version } from '../upgrade/version';
22
import WebpackBuild from '../tasks/build-webpack';
3-
import { BuildOptions } from './build';
4-
5-
export default function buildRun(commandOptions: BuildOptions) {
6-
if (commandOptions.environment === '') {
7-
if (commandOptions.target === 'development') {
8-
commandOptions.environment = 'dev';
9-
}
10-
if (commandOptions.target === 'production') {
11-
commandOptions.environment = 'prod';
12-
}
13-
}
14-
15-
if (!commandOptions.outputHashing) {
16-
if (commandOptions.target === 'development') {
17-
commandOptions.outputHashing = 'none';
18-
}
19-
if (commandOptions.target === 'production') {
20-
commandOptions.outputHashing = 'all';
21-
}
22-
}
23-
24-
if (typeof commandOptions.sourcemap === 'undefined') {
25-
if (commandOptions.target == 'development') {
26-
commandOptions.sourcemap = true;
27-
}
28-
if (commandOptions.target == 'production') {
29-
commandOptions.sourcemap = false;
30-
}
31-
}
3+
import { BuildTaskOptions } from './build';
324

5+
export default function buildRun(commandOptions: BuildTaskOptions) {
336
const project = this.project;
347

358
// Check angular version.
@@ -38,9 +11,6 @@ export default function buildRun(commandOptions: BuildOptions) {
3811
const buildTask = new WebpackBuild({
3912
cliProject: project,
4013
ui: this.ui,
41-
outputPath: commandOptions.outputPath,
42-
target: commandOptions.target,
43-
environment: commandOptions.environment,
4414
});
4515

4616
return buildTask.run(commandOptions);

‎packages/angular-cli/commands/build.ts

Lines changed: 37 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -1,63 +1,51 @@
1+
import { BuildOptions } from '../models/webpack-config';
2+
13
const Command = require('../ember-cli/lib/models/command');
24

3-
export interface BuildOptions {
4-
target?: string;
5-
environment?: string;
6-
outputPath?: string;
5+
// defaults for BuildOptions
6+
export const BaseBuildCommandOptions: any = [
7+
{
8+
name: 'target',
9+
type: String,
10+
default: 'development',
11+
aliases: ['t', { 'dev': 'development' }, { 'prod': 'production' }]
12+
},
13+
{ name: 'environment', type: String, aliases: ['e'] },
14+
{ name: 'output-path', type: 'Path', aliases: ['op'] },
15+
{ name: 'aot', type: Boolean, default: false },
16+
{ name: 'sourcemap', type: Boolean, aliases: ['sm'] },
17+
{ name: 'vendor-chunk', type: Boolean, default: true, aliases: ['vc'] },
18+
{ name: 'base-href', type: String, default: '/', aliases: ['bh'] },
19+
{ name: 'deploy-url', type: String, aliases: ['d'] },
20+
{ name: 'verbose', type: Boolean, default: false, aliases: ['v'] },
21+
{ name: 'progress', type: Boolean, default: true, aliases: ['pr'] },
22+
{ name: 'i18n-file', type: String },
23+
{ name: 'i18n-format', type: String },
24+
{ name: 'locale', type: String },
25+
{ name: 'extract-css', type: Boolean, aliases: ['ec']},
26+
{
27+
name: 'output-hashing',
28+
type: String,
29+
values: ['none', 'all', 'media', 'bundles'],
30+
description: 'define the output filename cache-busting hashing mode',
31+
aliases: ['oh']
32+
},
33+
];
34+
35+
export interface BuildTaskOptions extends BuildOptions {
736
watch?: boolean;
8-
watcher?: string;
9-
supressSizes: boolean;
10-
baseHref?: string;
11-
aot?: boolean;
12-
sourcemap?: boolean;
13-
vendorChunk?: boolean;
14-
verbose?: boolean;
15-
progress?: boolean;
16-
i18nFile?: string;
17-
i18nFormat?: string;
18-
locale?: string;
19-
deployUrl?: string;
20-
outputHashing?: string;
21-
extractCss?: boolean | null;
2237
}
2338

2439
const BuildCommand = Command.extend({
2540
name: 'build',
2641
description: 'Builds your app and places it into the output path (dist/ by default).',
2742
aliases: ['b'],
2843

29-
availableOptions: [
30-
{
31-
name: 'target',
32-
type: String,
33-
default: 'development',
34-
aliases: ['t', { 'dev': 'development' }, { 'prod': 'production' }]
35-
},
36-
{ name: 'environment', type: String, default: '', aliases: ['e'] },
37-
{ name: 'output-path', type: 'Path', default: null, aliases: ['o'] },
38-
{ name: 'watch', type: Boolean, default: false, aliases: ['w'] },
39-
{ name: 'watcher', type: String },
40-
{ name: 'suppress-sizes', type: Boolean, default: false },
41-
{ name: 'base-href', type: String, default: null, aliases: ['bh'] },
42-
{ name: 'aot', type: Boolean, default: false },
43-
{ name: 'sourcemap', type: Boolean, aliases: ['sm'] },
44-
{ name: 'vendor-chunk', type: Boolean, default: true },
45-
{ name: 'verbose', type: Boolean, default: false },
46-
{ name: 'progress', type: Boolean, default: true },
47-
{ name: 'i18n-file', type: String, default: null },
48-
{ name: 'i18n-format', type: String, default: null },
49-
{ name: 'locale', type: String, default: null },
50-
{ name: 'deploy-url', type: String, default: null, aliases: ['d'] },
51-
{
52-
name: 'output-hashing',
53-
type: String,
54-
values: ['none', 'all', 'media', 'bundles'],
55-
description: 'define the output filename cache-busting hashing mode'
56-
},
57-
{ name: 'extract-css', type: Boolean, default: true }
58-
],
44+
availableOptions: BaseBuildCommandOptions.concat([
45+
{ name: 'watch', type: Boolean, default: false, aliases: ['w'] }
46+
]),
5947

60-
run: function (commandOptions: BuildOptions) {
48+
run: function (commandOptions: BuildTaskOptions) {
6149
return require('./build.run').default.call(this, commandOptions);
6250
}
6351
});

‎packages/angular-cli/commands/serve.run.ts

Lines changed: 1 addition & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -11,37 +11,19 @@ PortFinder.basePort = 49152;
1111
const getPort = <any>denodeify(PortFinder.getPort);
1212

1313
export default function serveRun(commandOptions: ServeTaskOptions) {
14-
if (commandOptions.environment === '') {
15-
if (commandOptions.target === 'development') {
16-
commandOptions.environment = 'dev';
17-
}
18-
if (commandOptions.target === 'production') {
19-
commandOptions.environment = 'prod';
20-
}
21-
}
22-
23-
// default to extractCss to true on prod target
24-
if (typeof commandOptions.extractCss === 'undefined') {
25-
commandOptions.extractCss = commandOptions.target === 'production';
26-
}
27-
2814
// Check angular version.
2915
Version.assertAngularVersionIs2_3_1OrHigher(this.project.root);
3016
commandOptions.liveReloadHost = commandOptions.liveReloadHost || commandOptions.host;
3117

3218
return checkExpressPort(commandOptions)
3319
.then(() => autoFindLiveReloadPort(commandOptions))
3420
.then((opts: ServeTaskOptions) => {
35-
commandOptions = assign({}, opts, {
36-
baseURL: this.project.config(commandOptions.target).baseURL || '/'
37-
});
38-
3921
const serve = new ServeWebpackTask({
4022
ui: this.ui,
4123
project: this.project,
4224
});
4325

44-
return serve.run(commandOptions);
26+
return serve.run(opts);
4527
});
4628
}
4729

‎packages/angular-cli/commands/serve.ts

Lines changed: 7 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,44 +1,35 @@
1+
import { BuildOptions } from '../models/webpack-config';
2+
import { BaseBuildCommandOptions } from './build';
3+
14
const PortFinder = require('portfinder');
25
const Command = require('../ember-cli/lib/models/command');
36

47
PortFinder.basePort = 49152;
58

69
const defaultPort = process.env.PORT || 4200;
710

8-
export interface ServeTaskOptions {
11+
export interface ServeTaskOptions extends BuildOptions {
912
port?: number;
1013
host?: string;
1114
proxyConfig?: string;
12-
watcher?: string;
1315
liveReload?: boolean;
1416
liveReloadHost?: string;
1517
liveReloadPort?: number;
1618
liveReloadBaseUrl?: string;
1719
liveReloadLiveCss?: boolean;
18-
target?: string;
19-
environment?: string;
2020
ssl?: boolean;
2121
sslKey?: string;
2222
sslCert?: string;
23-
aot?: boolean;
24-
sourcemap?: boolean;
25-
verbose?: boolean;
26-
progress?: boolean;
2723
open?: boolean;
28-
vendorChunk?: boolean;
2924
hmr?: boolean;
30-
i18nFile?: string;
31-
i18nFormat?: string;
32-
locale?: string;
33-
extractCss?: boolean | null;
3425
}
3526

3627
const ServeCommand = Command.extend({
3728
name: 'serve',
3829
description: 'Builds and serves your app, rebuilding on file changes.',
3930
aliases: ['server', 's'],
4031

41-
availableOptions: [
32+
availableOptions: BaseBuildCommandOptions.concat([
4233
{ name: 'port', type: Number, default: defaultPort, aliases: ['p'] },
4334
{
4435
name: 'host',
@@ -48,7 +39,6 @@ const ServeCommand = Command.extend({
4839
description: 'Listens only on localhost by default'
4940
},
5041
{ name: 'proxy-config', type: 'Path', aliases: ['pc'] },
51-
{ name: 'watcher', type: String, default: 'events', aliases: ['w'] },
5242
{ name: 'live-reload', type: Boolean, default: true, aliases: ['lr'] },
5343
{
5444
name: 'live-reload-host',
@@ -74,21 +64,9 @@ const ServeCommand = Command.extend({
7464
default: true,
7565
description: 'Whether to live reload CSS (default true)'
7666
},
77-
{
78-
name: 'target',
79-
type: String,
80-
default: 'development',
81-
aliases: ['t', { 'dev': 'development' }, { 'prod': 'production' }]
82-
},
83-
{ name: 'environment', type: String, default: '', aliases: ['e'] },
8467
{ name: 'ssl', type: Boolean, default: false },
8568
{ name: 'ssl-key', type: String, default: 'ssl/server.key' },
8669
{ name: 'ssl-cert', type: String, default: 'ssl/server.crt' },
87-
{ name: 'aot', type: Boolean, default: false },
88-
{ name: 'sourcemap', type: Boolean, default: true, aliases: ['sm'] },
89-
{ name: 'vendor-chunk', type: Boolean, default: true },
90-
{ name: 'verbose', type: Boolean, default: false },
91-
{ name: 'progress', type: Boolean, default: true },
9270
{
9371
name: 'open',
9472
type: Boolean,
@@ -101,12 +79,8 @@ const ServeCommand = Command.extend({
10179
type: Boolean,
10280
default: false,
10381
description: 'Enable hot module replacement',
104-
},
105-
{ name: 'i18n-file', type: String, default: null },
106-
{ name: 'i18n-format', type: String, default: null },
107-
{ name: 'locale', type: String, default: null },
108-
{ name: 'extract-css', type: Boolean, default: null }
109-
],
82+
}
83+
]),
11084

11185
run: function(commandOptions: ServeTaskOptions) {
11286
return require('./serve.run').default.call(this, commandOptions);

‎packages/angular-cli/models/index.ts

Lines changed: 0 additions & 5 deletions
This file was deleted.

‎packages/angular-cli/models/webpack-build-development.ts

Lines changed: 0 additions & 3 deletions
This file was deleted.
Lines changed: 99 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -1,91 +1,124 @@
11
import {
2-
getWebpackAotConfigPartial,
3-
getWebpackNonAotConfigPartial
4-
} from './webpack-build-typescript';
2+
getAotConfig,
3+
getNonAotConfig
4+
} from './webpack-configs/typescript';
55
const webpackMerge = require('webpack-merge');
66
import { CliConfig } from './config';
7-
import { getWebpackCommonConfig } from './webpack-build-common';
8-
import { getWebpackDevConfigPartial } from './webpack-build-development';
9-
import { getWebpackProdConfigPartial } from './webpack-build-production';
7+
import { CliConfig as ConfigInterface } from '../lib/config/schema';
8+
import { getWebpackCommonConfig } from './webpack-configs/common';
9+
import { getDevConfig } from './webpack-configs/development';
10+
import { getProdConfig } from './webpack-configs/production';
1011
import {
11-
getWebpackMobileConfigPartial,
12-
getWebpackMobileProdConfigPartial
13-
} from './webpack-build-mobile';
12+
getMobileConfig,
13+
getMobileProdConfig
14+
} from './webpack-configs/mobile';
1415

16+
const path = require('path');
17+
18+
export interface BuildOptions {
19+
target?: string;
20+
environment?: string;
21+
outputPath?: string;
22+
aot?: boolean;
23+
sourcemap?: boolean;
24+
vendorChunk?: boolean;
25+
baseHref?: string;
26+
deployUrl?: string;
27+
verbose?: boolean;
28+
progress?: boolean;
29+
i18nFile?: string;
30+
i18nFormat?: string;
31+
locale?: string;
32+
extractCss?: boolean;
33+
outputHashing?: string;
34+
}
35+
36+
export interface WebpackConfigOptions {
37+
projectRoot: string;
38+
buildOptions: BuildOptions;
39+
appConfig: any;
40+
}
1541

1642
export class NgCliWebpackConfig {
17-
// TODO: When webpack2 types are finished lets replace all these any types
18-
// so this is more maintainable in the future for devs
1943
public config: any;
44+
constructor(buildOptions: BuildOptions) {
45+
46+
this.validateBuildOptions(buildOptions);
2047

21-
constructor(
22-
public ngCliProject: any,
23-
public target: string,
24-
public environment: string,
25-
outputDir?: string,
26-
baseHref?: string,
27-
i18nFile?: string,
28-
i18nFormat?: string,
29-
locale?: string,
30-
isAoT = false,
31-
sourcemap = true,
32-
vendorChunk = false,
33-
verbose = false,
34-
progress = true,
35-
deployUrl?: string,
36-
outputHashing?: string,
37-
extractCss = true,
38-
) {
48+
const configPath = CliConfig.configFilePath();
49+
const projectRoot = path.dirname(configPath);
3950
const appConfig = CliConfig.fromProject().config.apps[0];
40-
const projectRoot = this.ngCliProject.root;
41-
42-
appConfig.outDir = outputDir || appConfig.outDir;
43-
appConfig.deployUrl = deployUrl || appConfig.deployUrl;
44-
45-
let baseConfig = getWebpackCommonConfig(
46-
projectRoot,
47-
environment,
48-
appConfig,
49-
baseHref,
50-
sourcemap,
51-
vendorChunk,
52-
verbose,
53-
progress,
54-
outputHashing,
55-
extractCss,
56-
);
57-
let targetConfigPartial = this.getTargetConfig(projectRoot, appConfig, sourcemap, verbose);
51+
52+
buildOptions = this.addTargetDefaults(buildOptions);
53+
buildOptions = this.addAppConfigDefaults(buildOptions, appConfig);
54+
55+
const wco: WebpackConfigOptions = { projectRoot, buildOptions, appConfig };
56+
57+
let webpackConfigs = [
58+
getWebpackCommonConfig(wco),
59+
this.getTargetConfig(wco)
60+
];
5861

5962
if (appConfig.mobile) {
60-
let mobileConfigPartial = getWebpackMobileConfigPartial(projectRoot, appConfig);
61-
let mobileProdConfigPartial = getWebpackMobileProdConfigPartial(projectRoot, appConfig);
62-
baseConfig = webpackMerge(baseConfig, mobileConfigPartial);
63-
if (this.target == 'production') {
64-
targetConfigPartial = webpackMerge(targetConfigPartial, mobileProdConfigPartial);
63+
webpackConfigs.push(getMobileConfig(wco));
64+
if (buildOptions.target == 'production') {
65+
webpackConfigs.push(getMobileProdConfig(wco));
6566
}
6667
}
6768

68-
let config = webpackMerge(baseConfig, targetConfigPartial);
69-
7069
if (appConfig.main) {
71-
const typescriptConfigPartial = isAoT
72-
? getWebpackAotConfigPartial(projectRoot, appConfig, i18nFile, i18nFormat, locale)
73-
: getWebpackNonAotConfigPartial(projectRoot, appConfig);
74-
75-
config = webpackMerge(config, typescriptConfigPartial);
70+
const typescriptConfigPartial = buildOptions.aot
71+
? getAotConfig(wco)
72+
: getNonAotConfig(wco);
73+
webpackConfigs.push(typescriptConfigPartial);
7674
}
7775

78-
this.config = config;
76+
this.config = webpackMerge(webpackConfigs);
7977
}
8078

81-
getTargetConfig(projectRoot: string, appConfig: any, sourcemap: boolean, verbose: boolean): any {
82-
switch (this.target) {
79+
getTargetConfig(webpackConfigOptions: WebpackConfigOptions): any {
80+
switch (webpackConfigOptions.buildOptions.target) {
8381
case 'development':
84-
return getWebpackDevConfigPartial(projectRoot, appConfig);
82+
return getDevConfig(webpackConfigOptions);
8583
case 'production':
86-
return getWebpackProdConfigPartial(projectRoot, appConfig, sourcemap, verbose);
87-
default:
88-
throw new Error("Invalid build target. Only 'development' and 'production' are available.");
84+
return getProdConfig(webpackConfigOptions);
8985
}
9086
}
87+
88+
// Validate build options
89+
private validateBuildOptions(buildOptions: BuildOptions) {
90+
if (buildOptions.target !== 'development' && buildOptions.target !== 'production') {
91+
throw new Error("Invalid build target. Only 'development' and 'production' are available.");
92+
}
93+
}
94+
95+
// Fill in defaults for build targets
96+
private addTargetDefaults(buildOptions: BuildOptions) {
97+
const targetDefaults: any = {
98+
development: {
99+
environment: 'dev',
100+
outputHashing: 'none',
101+
sourcemap: true,
102+
extractCss: false
103+
},
104+
production: {
105+
environment: 'prod',
106+
outputHashing: 'all',
107+
sourcemap: false,
108+
extractCss: true
109+
}
110+
};
111+
112+
return Object.assign({}, targetDefaults[buildOptions.target], buildOptions);
113+
}
114+
115+
// Fill in defaults from angular-cli.json
116+
private addAppConfigDefaults(buildOptions: BuildOptions, appConfig: any) {
117+
const appConfigDefaults = {
118+
outputPath: appConfig.outDir,
119+
deployUrl: appConfig.deployUrl
120+
};
121+
122+
return Object.assign({}, appConfigDefaults, buildOptions);
123+
}
91124
}

‎packages/angular-cli/models/webpack-build-common.ts renamed to ‎packages/angular-cli/models/webpack-configs/common.ts

Lines changed: 28 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,13 @@
11
import * as webpack from 'webpack';
22
import * as path from 'path';
3-
import { GlobCopyWebpackPlugin } from '../plugins/glob-copy-webpack-plugin';
4-
import { SuppressEntryChunksWebpackPlugin } from '../plugins/suppress-entry-chunks-webpack-plugin';
5-
import { packageChunkSort } from '../utilities/package-chunk-sort';
3+
import { GlobCopyWebpackPlugin } from '../../plugins/glob-copy-webpack-plugin';
4+
import {
5+
SuppressEntryChunksWebpackPlugin
6+
} from '../../plugins/suppress-entry-chunks-webpack-plugin';
7+
import { packageChunkSort } from '../../utilities/package-chunk-sort';
68
import { BaseHrefWebpackPlugin } from '@angular-cli/base-href-webpack';
7-
import { extraEntryParser, makeCssLoaders, getOutputHashFormat } from './webpack-build-utils';
9+
import { extraEntryParser, makeCssLoaders, getOutputHashFormat } from './utils';
10+
import { WebpackConfigOptions } from '../webpack-config';
811

912
const autoprefixer = require('autoprefixer');
1013
const ProgressPlugin = require('webpack/lib/ProgressPlugin');
@@ -24,18 +27,8 @@ const SilentError = require('silent-error');
2427
* require('file-loader')
2528
*/
2629

27-
export function getWebpackCommonConfig(
28-
projectRoot: string,
29-
environment: string,
30-
appConfig: any,
31-
baseHref: string,
32-
sourcemap: boolean,
33-
vendorChunk: boolean,
34-
verbose: boolean,
35-
progress: boolean,
36-
outputHashing: string,
37-
extractCss: boolean,
38-
) {
30+
export function getWebpackCommonConfig(wco: WebpackConfigOptions) {
31+
const { projectRoot, buildOptions, appConfig } = wco;
3932

4033
const appRoot = path.resolve(projectRoot, appConfig.root);
4134
const nodeModules = path.resolve(projectRoot, 'node_modules');
@@ -51,7 +44,7 @@ export function getWebpackCommonConfig(
5144
}
5245

5346
// determine hashing format
54-
const hashFormat = getOutputHashFormat(outputHashing);
47+
const hashFormat = getOutputHashFormat(buildOptions.outputHashing);
5548

5649
// process global scripts
5750
if (appConfig.scripts && appConfig.scripts.length > 0) {
@@ -93,13 +86,13 @@ export function getWebpackCommonConfig(
9386
// create css loaders for component css and for global css
9487
extraRules.push(...makeCssLoaders(globalStyles.map((style) => style.path)));
9588

96-
if (extractCss && extractedCssEntryPoints.length > 0) {
89+
if (buildOptions.extractCss && extractedCssEntryPoints.length > 0) {
9790
// don't emit the .js entry point for extracted styles
9891
extraPlugins.push(new SuppressEntryChunksWebpackPlugin({ chunks: extractedCssEntryPoints }));
9992
}
10093
}
10194

102-
if (vendorChunk) {
95+
if (buildOptions.vendorChunk) {
10396
extraPlugins.push(new webpack.optimize.CommonsChunkPlugin({
10497
name: 'vendor',
10598
chunks: ['main'],
@@ -112,8 +105,8 @@ export function getWebpackCommonConfig(
112105
if (!('source' in appConfig.environments)) {
113106
throw new SilentError(`Environment configuration does not contain "source" entry.`);
114107
}
115-
if (!(environment in appConfig.environments)) {
116-
throw new SilentError(`Environment "${environment}" does not exist.`);
108+
if (!(buildOptions.environment in appConfig.environments)) {
109+
throw new SilentError(`Environment "${buildOptions.environment}" does not exist.`);
117110
}
118111

119112
extraPlugins.push(new webpack.NormalModuleReplacementPlugin(
@@ -122,7 +115,7 @@ export function getWebpackCommonConfig(
122115
// See https://webpack.github.io/docs/list-of-plugins.html#normalmodulereplacementplugin
123116
new RegExp(path.resolve(appRoot, appConfig.environments['source'])
124117
.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, '\\$&')),
125-
path.resolve(appRoot, appConfig.environments[environment])
118+
path.resolve(appRoot, appConfig.environments[buildOptions.environment])
126119
));
127120
}
128121

@@ -134,10 +127,12 @@ export function getWebpackCommonConfig(
134127
}));
135128
}
136129

137-
if (progress) { extraPlugins.push(new ProgressPlugin({ profile: verbose, colors: true })); }
130+
if (buildOptions.progress) {
131+
extraPlugins.push(new ProgressPlugin({ profile: buildOptions.verbose, colors: true }));
132+
}
138133

139134
return {
140-
devtool: sourcemap ? 'source-map' : false,
135+
devtool: buildOptions.sourcemap ? 'source-map' : false,
141136
resolve: {
142137
extensions: ['.ts', '.js'],
143138
modules: [nodeModules],
@@ -148,8 +143,8 @@ export function getWebpackCommonConfig(
148143
context: projectRoot,
149144
entry: entryPoints,
150145
output: {
151-
path: path.resolve(projectRoot, appConfig.outDir),
152-
publicPath: appConfig.deployUrl,
146+
path: path.resolve(projectRoot, buildOptions.outputPath),
147+
publicPath: buildOptions.deployUrl,
153148
filename: `[name]${hashFormat.chunk}.bundle.js`,
154149
sourceMapFilename: `[name]${hashFormat.chunk}.bundle.map`,
155150
chunkFilename: `[id]${hashFormat.chunk}.chunk.js`
@@ -175,17 +170,17 @@ export function getWebpackCommonConfig(
175170
plugins: [
176171
new ExtractTextPlugin({
177172
filename: `[name]${hashFormat.extract}.bundle.css`,
178-
disable: !extractCss
173+
disable: !buildOptions.extractCss
179174
}),
180175
new HtmlWebpackPlugin({
181176
template: path.resolve(appRoot, appConfig.index),
182-
filename: path.resolve(appConfig.outDir, appConfig.index),
177+
filename: path.resolve(buildOptions.outputPath, appConfig.index),
183178
chunksSortMode: packageChunkSort(['inline', 'styles', 'scripts', 'vendor', 'main']),
184179
excludeChunks: lazyChunks,
185180
xhtml: true
186181
}),
187182
new BaseHrefWebpackPlugin({
188-
baseHref: baseHref
183+
baseHref: buildOptions.baseHref
189184
}),
190185
new webpack.optimize.CommonsChunkPlugin({
191186
minChunks: Infinity,
@@ -195,10 +190,10 @@ export function getWebpackCommonConfig(
195190
test: /\.(css|scss|sass|less|styl)$/,
196191
options: {
197192
postcss: [autoprefixer()],
198-
cssLoader: { sourceMap: sourcemap },
199-
sassLoader: { sourceMap: sourcemap },
200-
lessLoader: { sourceMap: sourcemap },
201-
stylusLoader: { sourceMap: sourcemap },
193+
cssLoader: { sourceMap: buildOptions.sourcemap },
194+
sassLoader: { sourceMap: buildOptions.sourcemap },
195+
lessLoader: { sourceMap: buildOptions.sourcemap },
196+
stylusLoader: { sourceMap: buildOptions.sourcemap },
202197
// context needed as a workaround https://github.com/jtangelder/sass-loader/issues/285
203198
context: projectRoot,
204199
},
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import { WebpackConfigOptions } from '../webpack-config';
2+
3+
export const getDevConfig = function (wco: WebpackConfigOptions) {
4+
return {};
5+
};

‎packages/angular-cli/models/webpack-build-mobile.ts renamed to ‎packages/angular-cli/models/webpack-configs/mobile.ts

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
import * as path from 'path';
22
const OfflinePlugin = require('offline-plugin');
3-
import { GlobCopyWebpackPlugin } from '../plugins/glob-copy-webpack-plugin';
4-
import { PrerenderWebpackPlugin } from '../utilities/prerender-webpack-plugin';
3+
import { GlobCopyWebpackPlugin } from '../../plugins/glob-copy-webpack-plugin';
4+
import { PrerenderWebpackPlugin } from '../../utilities/prerender-webpack-plugin';
5+
import { WebpackConfigOptions } from '../webpack-config';
56

6-
export const getWebpackMobileConfigPartial = function (projectRoot: string, appConfig: any) {
7+
export const getMobileConfig = function (wco: WebpackConfigOptions) {
8+
const { projectRoot, appConfig } = wco;
79
// Hardcoded files and paths here should be part of appConfig when
810
// reworking the mobile app functionality
911
return {
@@ -21,7 +23,7 @@ export const getWebpackMobileConfigPartial = function (projectRoot: string, appC
2123
};
2224
};
2325

24-
export const getWebpackMobileProdConfigPartial = function (projectRoot: string, appConfig: any) {
26+
export const getMobileProdConfig = function (wco: WebpackConfigOptions) {
2527
return {
2628
entry: {
2729
'sw-install': path.resolve(__dirname, '../utilities/sw-install.js')

‎packages/angular-cli/models/webpack-build-production.ts renamed to ‎packages/angular-cli/models/webpack-configs/production.ts

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
import * as path from 'path';
22
import * as webpack from 'webpack';
3-
import {CompressionPlugin} from '../lib/webpack/compression-plugin';
3+
import { CompressionPlugin } from '../../lib/webpack/compression-plugin';
4+
import { WebpackConfigOptions } from '../webpack-config';
45
const autoprefixer = require('autoprefixer');
56
const postcssDiscardComments = require('postcss-discard-comments');
67

7-
export const getWebpackProdConfigPartial = function(projectRoot: string,
8-
appConfig: any,
9-
sourcemap: boolean,
10-
verbose: any) {
8+
9+
export const getProdConfig = function (wco: WebpackConfigOptions) {
10+
const { projectRoot, buildOptions, appConfig } = wco;
1111
const appRoot = path.resolve(projectRoot, appConfig.root);
1212

1313
return {
@@ -17,15 +17,15 @@ export const getWebpackProdConfigPartial = function(projectRoot: string,
1717
}),
1818
new webpack.LoaderOptionsPlugin({ minimize: true }),
1919
new webpack.optimize.UglifyJsPlugin(<any>{
20-
mangle: { screw_ie8 : true },
21-
compress: { screw_ie8: true, warnings: verbose },
22-
sourceMap: sourcemap
20+
mangle: { screw_ie8: true },
21+
compress: { screw_ie8: true, warnings: buildOptions.verbose },
22+
sourceMap: buildOptions.sourcemap
2323
}),
2424
new CompressionPlugin({
25-
asset: '[path].gz[query]',
26-
algorithm: 'gzip',
27-
test: /\.js$|\.html$|\.css$/,
28-
threshold: 10240
25+
asset: '[path].gz[query]',
26+
algorithm: 'gzip',
27+
test: /\.js$|\.html$|\.css$/,
28+
threshold: 10240
2929
}),
3030
// LoaderOptionsPlugin needs to be fully duplicated because webpackMerge will replace it.
3131
new webpack.LoaderOptionsPlugin({
@@ -35,10 +35,10 @@ export const getWebpackProdConfigPartial = function(projectRoot: string,
3535
autoprefixer(),
3636
postcssDiscardComments
3737
],
38-
cssLoader: { sourceMap: sourcemap },
39-
sassLoader: { sourceMap: sourcemap },
40-
lessLoader: { sourceMap: sourcemap },
41-
stylusLoader: { sourceMap: sourcemap },
38+
cssLoader: { sourceMap: buildOptions.sourcemap },
39+
sassLoader: { sourceMap: buildOptions.sourcemap },
40+
lessLoader: { sourceMap: buildOptions.sourcemap },
41+
stylusLoader: { sourceMap: buildOptions.sourcemap },
4242
// context needed as a workaround https://github.com/jtangelder/sass-loader/issues/285
4343
context: projectRoot,
4444
}

‎packages/angular-cli/models/webpack-build-test.js renamed to ‎packages/angular-cli/models/webpack-configs/test.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ const ProgressPlugin = require('webpack/lib/ProgressPlugin');
2626
*/
2727

2828

29-
const getWebpackTestConfig = function (projectRoot, environment, appConfig, testConfig) {
29+
const getTestConfig = function (projectRoot, environment, appConfig, testConfig) {
3030

3131
const appRoot = path.resolve(projectRoot, appConfig.root);
3232
const extraRules = [];
@@ -151,4 +151,4 @@ const getWebpackTestConfig = function (projectRoot, environment, appConfig, test
151151
};
152152
}
153153

154-
module.exports.getWebpackTestConfig = getWebpackTestConfig;
154+
module.exports.getTestConfig = getTestConfig;

‎packages/angular-cli/models/webpack-build-typescript.ts renamed to ‎packages/angular-cli/models/webpack-configs/typescript.ts

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import * as path from 'path';
22
import {AotPlugin} from '@ngtools/webpack';
3+
import { WebpackConfigOptions } from '../webpack-config';
34

45

56
const g: any = global;
@@ -8,7 +9,8 @@ const webpackLoader: string = g['angularCliIsLocal']
89
: '@ngtools/webpack';
910

1011

11-
export const getWebpackNonAotConfigPartial = function(projectRoot: string, appConfig: any) {
12+
export const getNonAotConfig = function(wco: WebpackConfigOptions) {
13+
const { projectRoot, appConfig } = wco;
1214
let exclude = [ '**/*.spec.ts' ];
1315
if (appConfig.test) { exclude.push(path.join(projectRoot, appConfig.root, appConfig.test)); };
1416
return {
@@ -32,8 +34,8 @@ export const getWebpackNonAotConfigPartial = function(projectRoot: string, appCo
3234
};
3335
};
3436

35-
export const getWebpackAotConfigPartial = function(projectRoot: string, appConfig: any,
36-
i18nFile: string, i18nFormat: string, locale: string) {
37+
export const getAotConfig = function(wco: WebpackConfigOptions) {
38+
const { projectRoot, buildOptions, appConfig } = wco;
3739
let exclude = [ '**/*.spec.ts' ];
3840
if (appConfig.test) { exclude.push(path.join(projectRoot, appConfig.root, appConfig.test)); };
3941
return {
@@ -50,9 +52,9 @@ export const getWebpackAotConfigPartial = function(projectRoot: string, appConfi
5052
new AotPlugin({
5153
tsConfigPath: path.resolve(projectRoot, appConfig.root, appConfig.tsconfig),
5254
mainPath: path.join(projectRoot, appConfig.root, appConfig.main),
53-
i18nFile: i18nFile,
54-
i18nFormat: i18nFormat,
55-
locale: locale,
55+
i18nFile: buildOptions.i18nFile,
56+
i18nFormat: buildOptions.i18nFormat,
57+
locale: buildOptions.locale,
5658
exclude: exclude
5759
})
5860
]

‎packages/angular-cli/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@
9797
"walk-sync": "^0.2.6",
9898
"webpack": "2.2.0",
9999
"webpack-dev-server": "2.2.0-rc.0",
100-
"webpack-merge": "^0.14.0",
100+
"webpack-merge": "^2.4.0",
101101
"webpack-sources": "^0.1.3",
102102
"zone.js": "^0.7.2"
103103
},

‎packages/angular-cli/plugins/karma.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
const path = require('path');
22
const fs = require('fs');
33

4-
const getWebpackTestConfig = require('../models/webpack-build-test').getWebpackTestConfig;
4+
const getTestConfig = require('../models/webpack-configs/test').getTestConfig;
55
const CliConfig = require('../models/config').CliConfig;
66

77
const init = (config) => {
@@ -42,7 +42,7 @@ const init = (config) => {
4242
}
4343

4444
// add webpack config
45-
const webpackConfig = getWebpackTestConfig(config.basePath, environment, appConfig, testConfig);
45+
const webpackConfig = getTestConfig(config.basePath, environment, appConfig, testConfig);
4646
const webpackMiddlewareConfig = {
4747
noInfo: true, // Hide webpack output because its noisy.
4848
stats: { // Also prevent chunk and module display output, cleaner look. Only emit errors.

‎packages/angular-cli/tasks/build-webpack.ts

Lines changed: 7 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -2,41 +2,22 @@ import * as rimraf from 'rimraf';
22
import * as path from 'path';
33
const Task = require('../ember-cli/lib/models/task');
44
import * as webpack from 'webpack';
5-
import { BuildOptions } from '../commands/build';
5+
import { BuildTaskOptions } from '../commands/build';
66
import { NgCliWebpackConfig } from '../models/webpack-config';
7-
import { getWebpackStatsConfig } from '../models/';
7+
import { getWebpackStatsConfig } from '../models/webpack-configs/utils';
88
import { CliConfig } from '../models/config';
99

1010

1111
export default Task.extend({
12-
run: function (runTaskOptions: BuildOptions) {
12+
run: function (runTaskOptions: BuildTaskOptions) {
1313

1414
const project = this.cliProject;
1515

16-
const outputDir = runTaskOptions.outputPath || CliConfig.fromProject().config.apps[0].outDir;
17-
const deployUrl = runTaskOptions.deployUrl ||
18-
CliConfig.fromProject().config.apps[0].deployUrl;
19-
rimraf.sync(path.resolve(project.root, outputDir));
20-
const config = new NgCliWebpackConfig(
21-
project,
22-
runTaskOptions.target,
23-
runTaskOptions.environment,
24-
outputDir,
25-
runTaskOptions.baseHref,
26-
runTaskOptions.i18nFile,
27-
runTaskOptions.i18nFormat,
28-
runTaskOptions.locale,
29-
runTaskOptions.aot,
30-
runTaskOptions.sourcemap,
31-
runTaskOptions.vendorChunk,
32-
runTaskOptions.verbose,
33-
runTaskOptions.progress,
34-
deployUrl,
35-
runTaskOptions.outputHashing,
36-
runTaskOptions.extractCss,
37-
).config;
16+
const outputPath = runTaskOptions.outputPath || CliConfig.fromProject().config.apps[0].outDir;
17+
rimraf.sync(path.resolve(project.root, outputPath));
3818

39-
const webpackCompiler = webpack(config);
19+
const webpackConfig = new NgCliWebpackConfig(runTaskOptions).config;
20+
const webpackCompiler = webpack(webpackConfig);
4021
const statsConfig = getWebpackStatsConfig(runTaskOptions.verbose);
4122

4223
return new Promise((resolve, reject) => {

‎packages/angular-cli/tasks/serve-webpack.ts

Lines changed: 14 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ const SilentError = require('silent-error');
55
const Task = require('../ember-cli/lib/models/task');
66
import * as webpack from 'webpack';
77
const WebpackDevServer = require('webpack-dev-server');
8-
import { getWebpackStatsConfig } from '../models/';
8+
import { getWebpackStatsConfig } from '../models/webpack-configs/utils';
99
import { NgCliWebpackConfig } from '../models/webpack-config';
1010
import { ServeTaskOptions } from '../commands/serve';
1111
import { CliConfig } from '../models/config';
@@ -22,24 +22,14 @@ export default Task.extend({
2222
const projectConfig = CliConfig.fromProject().config;
2323
const appConfig = projectConfig.apps[0];
2424

25-
let config = new NgCliWebpackConfig(
26-
this.project,
27-
serveTaskOptions.target,
28-
serveTaskOptions.environment,
29-
undefined,
30-
undefined,
31-
serveTaskOptions.i18nFile,
32-
serveTaskOptions.i18nFormat,
33-
serveTaskOptions.locale,
34-
serveTaskOptions.aot,
35-
serveTaskOptions.sourcemap,
36-
serveTaskOptions.vendorChunk,
37-
serveTaskOptions.verbose,
38-
serveTaskOptions.progress,
39-
undefined,
40-
undefined,
41-
serveTaskOptions.extractCss
42-
).config;
25+
const serveDefaults = {
26+
// default deployUrl to '' on serve to prevent the default from angular-cli.json
27+
deployUrl: ''
28+
};
29+
30+
serveTaskOptions = Object.assign({}, serveDefaults, serveTaskOptions);
31+
32+
let webpackConfig = new NgCliWebpackConfig(serveTaskOptions).config;
4333

4434
// This allows for live reload of page when changes are made to repo.
4535
// https://webpack.github.io/docs/webpack-dev-server.html#inline-mode
@@ -57,18 +47,18 @@ export default Task.extend({
5747
ui.writeLine(` See ${chalk.blue(webpackHmrLink)}`);
5848
ui.writeLine(' for information on working with HMR for Webpack.');
5949
entryPoints.push('webpack/hot/dev-server');
60-
config.plugins.push(new webpack.HotModuleReplacementPlugin());
61-
config.plugins.push(new webpack.NamedModulesPlugin());
50+
webpackConfig.plugins.push(new webpack.HotModuleReplacementPlugin());
51+
webpackConfig.plugins.push(new webpack.NamedModulesPlugin());
6252
if (serveTaskOptions.extractCss) {
6353
ui.writeLine(oneLine`
6454
${chalk.yellow('NOTICE')} (HMR) does not allow for CSS hot reload when used
6555
together with '--extract-css'.
6656
`);
6757
}
6858
}
69-
if (!config.entry.main) { config.entry.main = []; }
70-
config.entry.main.unshift(...entryPoints);
71-
webpackCompiler = webpack(config);
59+
if (!webpackConfig.entry.main) { webpackConfig.entry.main = []; }
60+
webpackConfig.entry.main.unshift(...entryPoints);
61+
webpackCompiler = webpack(webpackConfig);
7262

7363
const statsConfig = getWebpackStatsConfig(serveTaskOptions.verbose);
7464

‎tests/e2e/tests/build/output-dir.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import {updateJsonFile} from '../../utils/project';
66

77

88
export default function() {
9-
return ng('build', '-o', './build-output')
9+
return ng('build', '-op', './build-output')
1010
.then(() => expectFileToExist('./build-output/index.html'))
1111
.then(() => expectFileToExist('./build-output/main.bundle.js'))
1212
.then(() => expectToFail(expectGitToBeClean))

0 commit comments

Comments
 (0)
Please sign in to comment.