Skip to content

Commit

Permalink
feat: update to webpack 4
Browse files Browse the repository at this point in the history
  • Loading branch information
clydin committed Jan 31, 2018
1 parent ee40dc3 commit fabd7fd
Show file tree
Hide file tree
Showing 12 changed files with 331 additions and 578 deletions.
635 changes: 208 additions & 427 deletions package-lock.json

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@
"typescript": "^2.6.2",
"uglifyjs-webpack-plugin": "^1.1.5",
"url-loader": "^0.6.2",
"webpack": "~3.10.0",
"webpack": "^4.0.0-beta.0",
"webpack-dev-middleware": "~1.12.0",
"webpack-dev-server": "~2.11.0",
"webpack-merge": "^4.1.0",
Expand Down
9 changes: 2 additions & 7 deletions packages/@angular/cli/models/webpack-config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import { BuildOptions } from './build-options';
import {
getBrowserConfig,
getCommonConfig,
getDevConfig,
getProdConfig,
getStylesConfig,
getServerConfig,
Expand Down Expand Up @@ -48,10 +47,8 @@ export class NgCliWebpackConfig<T extends BuildOptions = BuildOptions> {
const supportES2015 = tsConfig.options.target !== projectTs.ScriptTarget.ES3
&& tsConfig.options.target !== projectTs.ScriptTarget.ES5;

// Only force if the default module kind is used (ES2015)
// Allows user to adjust module kind (to esNext for example)
buildOptions.forceTsCommonjs = buildOptions.forceTsCommonjs
&& tsConfig.options.module === projectTs.ModuleKind.ES2015;
// TODO: Remove this functionality completely as it is no longer needed with Webpack 4
buildOptions.forceTsCommonjs = false;

this.wco = { projectRoot, buildOptions, appConfig, tsConfig, supportES2015 };
}
Expand Down Expand Up @@ -80,8 +77,6 @@ export class NgCliWebpackConfig<T extends BuildOptions = BuildOptions> {

public getTargetConfig(webpackConfigOptions: WebpackConfigOptions<T>): any {
switch (webpackConfigOptions.buildOptions.target) {
case 'development':
return getDevConfig(webpackConfigOptions);
case 'production':
return getProdConfig(webpackConfigOptions);
}
Expand Down
83 changes: 35 additions & 48 deletions packages/@angular/cli/models/webpack-configs/browser.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import * as fs from 'fs';
import * as webpack from 'webpack';
import * as path from 'path';
const HtmlWebpackPlugin = require('html-webpack-plugin');
Expand All @@ -23,23 +22,23 @@ export function getBrowserConfig(wco: WebpackConfigOptions) {
...extraEntryParser(appConfig.styles, appRoot, 'styles')
]);

if (buildOptions.vendorChunk) {
// Separate modules from node_modules into a vendor chunk.
const nodeModules = path.resolve(projectRoot, 'node_modules');
// Resolves all symlink to get the actual node modules folder.
const realNodeModules = fs.realpathSync(nodeModules);
// --aot puts the generated *.ngfactory.ts in src/$$_gendir/node_modules.
const genDirNodeModules = path.resolve(appRoot, '$$_gendir', 'node_modules');

extraPlugins.push(new webpack.optimize.CommonsChunkPlugin({
name: 'vendor',
chunks: ['main'],
minChunks: (module: any) => {
return module.resource
&& ( module.resource.startsWith(nodeModules)
|| module.resource.startsWith(genDirNodeModules)
|| module.resource.startsWith(realNodeModules));
}
// TODO: Enable this once HtmlWebpackPlugin supports Webpack 4
const generateIndexHtml = false;
if (generateIndexHtml) {
extraPlugins.push(new HtmlWebpackPlugin({
template: path.resolve(appRoot, appConfig.index),
filename: path.resolve(buildOptions.outputPath, appConfig.index),
chunksSortMode: packageChunkSort(appConfig),
excludeChunks: lazyChunks,
xhtml: true,
minify: buildOptions.target === 'production' ? {
caseSensitive: true,
collapseWhitespace: true,
keepClosingSlash: true
} : false
}));
extraPlugins.push(new BaseHrefWebpackPlugin({
baseHref: buildOptions.baseHref
}));
}

Expand All @@ -62,15 +61,6 @@ export function getBrowserConfig(wco: WebpackConfigOptions) {
}
}

if (buildOptions.commonChunk) {
extraPlugins.push(new webpack.optimize.CommonsChunkPlugin({
name: 'main',
async: 'common',
children: true,
minChunks: 2
}));
}

if (buildOptions.subresourceIntegrity) {
extraPlugins.push(new SubresourceIntegrityPlugin({
hashFuncNames: ['sha384']
Expand All @@ -87,27 +77,24 @@ export function getBrowserConfig(wco: WebpackConfigOptions) {
output: {
crossOriginLoading: buildOptions.subresourceIntegrity ? 'anonymous' : false
},
plugins: [
new HtmlWebpackPlugin({
template: path.resolve(appRoot, appConfig.index),
filename: path.resolve(buildOptions.outputPath, appConfig.index),
chunksSortMode: packageChunkSort(appConfig),
excludeChunks: lazyChunks,
xhtml: true,
minify: buildOptions.target === 'production' ? {
caseSensitive: true,
collapseWhitespace: true,
keepClosingSlash: true
} : false
}),
new BaseHrefWebpackPlugin({
baseHref: buildOptions.baseHref
}),
new webpack.optimize.CommonsChunkPlugin({
minChunks: Infinity,
name: 'inline'
})
].concat(extraPlugins),
optimization: {
splitChunks: {
chunks: buildOptions.commonChunk ? 'all' : 'initial',
cacheGroups: {
vendors: false,
vendor: buildOptions.vendorChunk && {
name: 'vendor',
chunks: 'initial',
test: (module: any, chunks: Array<{name: string}>) => {
const moduleName = module.nameForCondition ? module.nameForCondition() : '';
return /[\\/]node_modules[\\/]/.test(moduleName)
&& !chunks.some(({ name }) => name === 'polyfills');
},
},
}
}
},
plugins: extraPlugins,
node: {
fs: 'empty',
global: true,
Expand Down
88 changes: 70 additions & 18 deletions packages/@angular/cli/models/webpack-configs/common.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,17 @@
import * as webpack from 'webpack';
import * as path from 'path';
import { HashedModuleIdsPlugin } from 'webpack';
import * as CopyWebpackPlugin from 'copy-webpack-plugin';
import { NamedLazyChunksWebpackPlugin } from '../../plugins/named-lazy-chunks-webpack-plugin';
import { extraEntryParser, getOutputHashFormat, AssetPattern } from './utils';
import { isDirectory } from '../../utilities/is-directory';
import { requireProjectModule } from '../../utilities/require-project-module';
import { WebpackConfigOptions } from '../webpack-config';
import { CleanCssWebpackPlugin } from '../../plugins/cleancss-webpack-plugin';
import { ScriptsWebpackPlugin } from '../../plugins/scripts-webpack-plugin';

const ProgressPlugin = require('webpack/lib/ProgressPlugin');
const CircularDependencyPlugin = require('circular-dependency-plugin');
const UglifyJSPlugin = require('uglifyjs-webpack-plugin');
const SilentError = require('silent-error');
const resolve = require('resolve');

Expand All @@ -31,7 +33,6 @@ export function getCommonConfig(wco: WebpackConfigOptions) {
const nodeModules = path.resolve(projectRoot, 'node_modules');

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

if (appConfig.main) {
Expand Down Expand Up @@ -77,6 +78,9 @@ export function getCommonConfig(wco: WebpackConfigOptions) {
});
}

// TODO: Remove this when copy-webpack-plugin supports Webpack 4
appConfig.assets = undefined;

// process asset entries
if (appConfig.assets) {
const copyWebpackPluginPatterns = appConfig.assets.map((asset: string | AssetPattern) => {
Expand Down Expand Up @@ -159,26 +163,29 @@ export function getCommonConfig(wco: WebpackConfigOptions) {

if (buildOptions.showCircularDependencies) {
extraPlugins.push(new CircularDependencyPlugin({
exclude: /(\\|\/)node_modules(\\|\/)/
exclude: /[\\\/]node_modules[\\\/]/
}));
}

let buildOptimizerUseRule;
if (buildOptions.buildOptimizer) {
// Set the cache directory to the Build Optimizer dir, so that package updates will delete it.
const buildOptimizerDir = path.dirname(
resolve.sync('@angular-devkit/build-optimizer', { basedir: projectRoot }));
const cacheDirectory = path.resolve(buildOptimizerDir, './.cache/');

extraRules.push({
test: /\.js$/,
use: [{
loader: 'cache-loader',
options: { cacheDirectory }
}, {
loader: '@angular-devkit/build-optimizer/webpack-loader',
options: { sourceMap: buildOptions.sourcemaps }
}],
});
buildOptimizerUseRule = {
use: [
{
loader: 'cache-loader',
options: { cacheDirectory }
},
{
loader: '@angular-devkit/build-optimizer/webpack-loader',
options: { sourceMap: buildOptions.sourcemaps }
},
],
};
}

if (buildOptions.namedChunks) {
Expand All @@ -204,6 +211,7 @@ export function getCommonConfig(wco: WebpackConfigOptions) {
}

return {
mode: buildOptions.target,
resolve: {
extensions: ['.ts', '.js'],
symlinks: !buildOptions.preserveSymlinks,
Expand Down Expand Up @@ -238,11 +246,55 @@ export function getCommonConfig(wco: WebpackConfigOptions) {
name: `[name]${hashFormat.file}.[ext]`,
limit: 10000
}
}
].concat(extraRules)
},
{
test: /[\/\\]@angular[\/\\].+\.js$/,
sideEffects: false,
parser: { system: true },
...buildOptimizerUseRule,
},
{
test: /\.js$/,
...buildOptimizerUseRule,
},
]
},
optimization: {
noEmitOnErrors: true,
minimizer: [
new HashedModuleIdsPlugin(),
new CleanCssWebpackPlugin({ sourceMap: buildOptions.sourcemaps }),
new UglifyJSPlugin({
sourceMap: buildOptions.sourcemaps,
parallel: true,
cache: true,
uglifyOptions: {
ecma: wco.supportES2015 ? 6 : 5,
warnings: buildOptions.verbose,
ie8: false,
mangle: {
safari10: true,
},
compress: {
// Disabled because of an issue with Mapbox GL when using the Webpack node global:
// https://github.com/mapbox/mapbox-gl-js/issues/4359#issuecomment-303880888
// https://github.com/angular/angular-cli/issues/5804
// https://github.com/angular/angular-cli/pull/7931
typeofs : false,
pure_getters: buildOptions.buildOptimizer,
// PURE comments work best with 3 passes.
// See https://github.com/webpack/webpack/issues/2899#issuecomment-317425926.
passes: buildOptions.buildOptimizer ? 3 : 1,
},
output: {
ascii_only: true,
comments: false,
webkit: true,
},
}
}),
],
},
plugins: [
new webpack.NoEmitOnErrorsPlugin()
].concat(extraPlugins)
plugins: extraPlugins,
};
}
9 changes: 0 additions & 9 deletions packages/@angular/cli/models/webpack-configs/development.ts

This file was deleted.

1 change: 0 additions & 1 deletion packages/@angular/cli/models/webpack-configs/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
export * from './browser';
export * from './common';
export * from './development';
export * from './production';
export * from './server';
export * from './styles';
Expand Down
49 changes: 1 addition & 48 deletions packages/@angular/cli/models/webpack-configs/production.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,15 @@
import * as path from 'path';
import * as webpack from 'webpack';
import * as fs from 'fs';
import * as semver from 'semver';
import { stripIndent } from 'common-tags';
import { LicenseWebpackPlugin } from 'license-webpack-plugin';
import { PurifyPlugin } from '@angular-devkit/build-optimizer';
import { BundleBudgetPlugin } from '../../plugins/bundle-budget';
import { StaticAssetPlugin } from '../../plugins/static-asset';
import { GlobCopyWebpackPlugin } from '../../plugins/glob-copy-webpack-plugin';
import { WebpackConfigOptions } from '../webpack-config';
import { resolveProjectModule } from '../../utilities/require-project-module';
import { NEW_SW_VERSION } from '../../utilities/service-worker';

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

const OLD_SW_VERSION = '>= 1.0.0-beta.5 < 2.0.0';

Expand Down Expand Up @@ -127,52 +124,8 @@ export function getProdConfig(wco: WebpackConfigOptions) {
}));
}

const uglifyCompressOptions: any = {
// Disabled because of an issue with Mapbox GL when using the Webpack node global and UglifyJS:
// https://github.com/mapbox/mapbox-gl-js/issues/4359#issuecomment-303880888
// https://github.com/angular/angular-cli/issues/5804
// https://github.com/angular/angular-cli/pull/7931
typeofs : false
};

if (buildOptions.buildOptimizer) {
// This plugin must be before webpack.optimize.UglifyJsPlugin.
extraPlugins.push(new PurifyPlugin());
uglifyCompressOptions.pure_getters = true;
// PURE comments work best with 3 passes.
// See https://github.com/webpack/webpack/issues/2899#issuecomment-317425926.
uglifyCompressOptions.passes = 3;
}

return {
entry: entryPoints,
plugins: [
new webpack.EnvironmentPlugin({
'NODE_ENV': 'production'
}),
new webpack.HashedModuleIdsPlugin(),
new webpack.optimize.ModuleConcatenationPlugin(),
...extraPlugins,
// Uglify should be the last plugin as PurifyPlugin needs to be before it.
new UglifyJSPlugin({
sourceMap: buildOptions.sourcemaps,
parallel: true,
cache: true,
uglifyOptions: {
ecma: wco.supportES2015 ? 6 : 5,
warnings: buildOptions.verbose,
ie8: false,
mangle: {
safari10: true,
},
compress: uglifyCompressOptions,
output: {
ascii_only: true,
comments: false,
webkit: true,
},
}
}),
]
plugins: extraPlugins,
};
}
Loading

0 comments on commit fabd7fd

Please sign in to comment.