Skip to content

Commit

Permalink
fix(@angular/cli): fix asset watching
Browse files Browse the repository at this point in the history
https://github.com/kevlened/copy-webpack-plugin is now used instead of the custom plugin, it has since implemented the features we needed.

Fix #7521
  • Loading branch information
filipesilva committed Sep 6, 2017
1 parent ec67c9a commit feb7d0b
Show file tree
Hide file tree
Showing 10 changed files with 187 additions and 829 deletions.
903 changes: 107 additions & 796 deletions package-lock.json

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@
"chalk": "^2.0.1",
"circular-dependency-plugin": "^3.0.0",
"common-tags": "^1.3.1",
"copy-webpack-plugin": "^4.0.1",
"core-object": "^3.1.0",
"css-loader": "^0.28.1",
"cssnano": "^3.10.0",
Expand Down Expand Up @@ -105,6 +106,7 @@
"@angular/core": "^4.0.0",
"@types/chalk": "^0.4.28",
"@types/common-tags": "^1.2.4",
"@types/copy-webpack-plugin": "^4.0.0",
"@types/denodeify": "^1.2.30",
"@types/express": "^4.0.32",
"@types/fs-extra": "^4.0.0",
Expand Down
47 changes: 41 additions & 6 deletions packages/@angular/cli/models/webpack-configs/common.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import * as webpack from 'webpack';
import * as path from 'path';
import { GlobCopyWebpackPlugin } from '../../plugins/glob-copy-webpack-plugin';
import * as CopyWebpackPlugin from '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 { extraEntryParser, getOutputHashFormat, AssetPattern } from './utils';
import { isDirectory } from '../../utilities/is-directory';
import { WebpackConfigOptions } from '../webpack-config';

const ConcatPlugin = require('webpack-concat-plugin');
Expand Down Expand Up @@ -84,10 +85,44 @@ export function getCommonConfig(wco: WebpackConfigOptions) {

// process asset entries
if (appConfig.assets) {
extraPlugins.push(new GlobCopyWebpackPlugin({
patterns: appConfig.assets,
globOptions: { cwd: appRoot, dot: true, ignore: '**/.gitkeep' }
}));
const copyWebpackPluginPatterns = appConfig.assets.map((asset: string | AssetPattern) => {
// Convert all string assets to object notation.
asset = typeof asset === 'string' ? { glob: asset } : asset;
// Add defaults.
// Input is always resolved relative to the appRoot.
asset.input = path.resolve(appRoot, asset.input || '');
asset.output = asset.output || '';
asset.glob = asset.glob || '';

// Ensure trailing slash.
if (isDirectory(path.resolve(asset.input))) {
asset.input += '/';
}

// Convert dir patterns to globs.
if (isDirectory(path.resolve(asset.input, asset.glob))) {
asset.glob = asset.glob + '/**/*';
}

return {
context: asset.input,
to: asset.output,
from: {
glob: asset.glob,
dot: true
}
};
});
const copyWebpackPluginOptions = { ignore: ['.gitkeep'] };

const copyWebpackPluginInstance = new CopyWebpackPlugin(copyWebpackPluginPatterns,
copyWebpackPluginOptions);

// Save options so we can use them in eject.
(copyWebpackPluginInstance as any)['copyWebpackPluginPatterns'] = copyWebpackPluginPatterns;
(copyWebpackPluginInstance as any)['copyWebpackPluginOptions'] = copyWebpackPluginOptions;

extraPlugins.push(copyWebpackPluginInstance);
}

if (buildOptions.progress) {
Expand Down
5 changes: 5 additions & 0 deletions packages/@angular/cli/models/webpack-configs/production.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,11 @@ export const getProdConfig = function (wco: WebpackConfigOptions) {
`);
}

// CopyWebpackPlugin replaces GlobCopyWebpackPlugin, but AngularServiceWorkerPlugin depends
// on specific behaviour from latter.
// AngularServiceWorkerPlugin expects the ngsw-manifest.json to be present in the 'emit' phase
// but with CopyWebpackPlugin it's only there on 'after-emit'.
// So for now we keep it here, but if AngularServiceWorkerPlugin changes we remove it.
extraPlugins.push(new GlobCopyWebpackPlugin({
patterns: [
'ngsw-manifest.json',
Expand Down
6 changes: 6 additions & 0 deletions packages/@angular/cli/models/webpack-configs/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -87,3 +87,9 @@ export function getOutputHashFormat(option: string, length = 20): HashFormat {
/* tslint:enable:max-line-length */
return hashFormats[option] || hashFormats['none'];
}

export interface AssetPattern {
glob: string;
input?: string;
output?: string;
}
1 change: 1 addition & 0 deletions packages/@angular/cli/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
"chalk": "^2.0.1",
"circular-dependency-plugin": "^3.0.0",
"common-tags": "^1.3.1",
"copy-webpack-plugin": "^4.0.1",
"core-object": "^3.1.0",
"css-loader": "^0.28.1",
"cssnano": "^3.10.0",
Expand Down
20 changes: 4 additions & 16 deletions packages/@angular/cli/plugins/glob-copy-webpack-plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,33 +2,21 @@ import * as fs from 'fs';
import * as path from 'path';
import * as glob from 'glob';
import * as denodeify from 'denodeify';
import { AssetPattern } from '../models/webpack-configs/utils';
import { isDirectory } from '../utilities/is-directory';

const flattenDeep = require('lodash/flattenDeep');
const globPromise = <any>denodeify(glob);
const statPromise = <any>denodeify(fs.stat);

function isDirectory(path: string) {
try {
return fs.statSync(path).isDirectory();
} catch (_) {
return false;
}
}

interface Asset {
originPath: string;
destinationPath: string;
relativePath: string;
}

export interface Pattern {
glob: string;
input?: string;
output?: string;
}

export interface GlobCopyWebpackPluginOptions {
patterns: (string | Pattern)[];
patterns: (string | AssetPattern)[];
globOptions: any;
}

Expand Down Expand Up @@ -79,7 +67,7 @@ export class GlobCopyWebpackPlugin {

compiler.plugin('emit', (compilation: any, cb: any) => {
// Create an array of promises for each pattern glob
const globs = patterns.map((pattern: Pattern) => new Promise((resolve, reject) =>
const globs = patterns.map((pattern: AssetPattern) => new Promise((resolve, reject) =>
// Individual patterns can override cwd
globPromise(pattern.glob, Object.assign({}, globOptions, { cwd: pattern.input }))
// Map the results onto an Asset
Expand Down
13 changes: 3 additions & 10 deletions packages/@angular/cli/plugins/karma.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@ import * as glob from 'glob';
import * as webpack from 'webpack';
const webpackDevMiddleware = require('webpack-dev-middleware');

import { Pattern } from './glob-copy-webpack-plugin';
import { AssetPattern } from '../models/webpack-configs/utils';
import { isDirectory } from '../utilities/is-directory';
import { WebpackTestConfig, WebpackTestOptions } from '../models/webpack-test-config';
import { KarmaWebpackThrowError } from './karma-webpack-throw-error';

Expand All @@ -22,14 +23,6 @@ const getAppFromConfig = require('../utilities/app-utils').getAppFromConfig;
let blocked: any[] = [];
let isBlocked = false;

function isDirectory(path: string) {
try {
return fs.statSync(path).isDirectory();
} catch (_) {
return false;
}
}

// Add files to the Karma files array.
function addKarmaFiles(files: any[], newFiles: any[], prepend = false) {
const defaults = {
Expand Down Expand Up @@ -82,7 +75,7 @@ const init: any = (config: any, emitter: any, customFileHandlers: any) => {
// Add assets. This logic is mimics the one present in GlobCopyWebpackPlugin.
if (appConfig.assets) {
config.proxies = config.proxies || {};
appConfig.assets.forEach((pattern: Pattern) => {
appConfig.assets.forEach((pattern: AssetPattern) => {
// Convert all string patterns to Pattern type.
pattern = typeof pattern === 'string' ? { glob: pattern } : pattern;
// Add defaults.
Expand Down
10 changes: 9 additions & 1 deletion packages/@angular/cli/tasks/eject.ts
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,7 @@ class JsonWebpackSerializer {
private _pluginsReplacer(plugins: any[]) {
return plugins.map(plugin => {
let args = plugin.options || undefined;
const serializer = (args: any) => JSON.stringify(args, (k, v) => this._replacer(k, v), 2);

switch (plugin.constructor) {
case ProgressPlugin:
Expand Down Expand Up @@ -231,11 +232,17 @@ class JsonWebpackSerializer {
default:
if (plugin.constructor.name == 'AngularServiceWorkerPlugin') {
this._addImport('@angular/service-worker/build/webpack', plugin.constructor.name);
} else if (plugin['copyWebpackPluginPatterns']) {
// CopyWebpackPlugin doesn't have a constructor nor save args.
this.variableImports['copy-webpack-plugin'] = 'CopyWebpackPlugin';
const patternsSerialized = serializer(plugin['copyWebpackPluginPatterns']);
const optionsSerialized = serializer(plugin['copyWebpackPluginOptions']) || 'undefined';
return `\uFF02CopyWebpackPlugin(${patternsSerialized}, ${optionsSerialized})\uFF02`;
}
break;
}

const argsSerialized = JSON.stringify(args, (k, v) => this._replacer(k, v), 2) || '';
const argsSerialized = serializer(args) || '';
return `\uFF02${plugin.constructor.name}(${argsSerialized})\uFF02`;
});
}
Expand Down Expand Up @@ -538,6 +545,7 @@ export default Task.extend({
'url-loader',
'circular-dependency-plugin',
'webpack-concat-plugin',
'copy-webpack-plugin',
].forEach((packageName: string) => {
packageJson['devDependencies'][packageName] = ourPackageJson['dependencies'][packageName];
});
Expand Down
9 changes: 9 additions & 0 deletions packages/@angular/cli/utilities/is-directory.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import * as fs from 'fs';

export function isDirectory(path: string) {
try {
return fs.statSync(path).isDirectory();
} catch (_) {
return false;
}
}

0 comments on commit feb7d0b

Please sign in to comment.