From 81ddf020861dd2ebcae7b40b5356cb6d8d1e834e Mon Sep 17 00:00:00 2001 From: "Braden M. Kelley" Date: Sun, 20 Aug 2017 11:30:34 -0700 Subject: [PATCH] build(@angular/cli): add option to ignore files Let the webpack dev server ignore files specified by the user as either the `--ignored` command line option or through the `defaults.build.ignored` option in the configuration file --- docs/documentation/angular-cli.md | 1 + packages/@angular/cli/commands/build.ts | 8 ++- packages/@angular/cli/custom-typings.d.ts | 1 + packages/@angular/cli/lib/config/schema.json | 14 ++++ packages/@angular/cli/models/build-options.ts | 1 + packages/@angular/cli/tasks/serve.ts | 1 + tests/e2e/tests/build/ignored.ts | 72 +++++++++++++++++++ 7 files changed, 97 insertions(+), 1 deletion(-) create mode 100644 tests/e2e/tests/build/ignored.ts diff --git a/docs/documentation/angular-cli.md b/docs/documentation/angular-cli.md index 4d836dfe714a..ca0643f4af95 100644 --- a/docs/documentation/angular-cli.md +++ b/docs/documentation/angular-cli.md @@ -82,6 +82,7 @@ - *baseHref* (`string`): Base url for the application being built. - *progress* (`boolean`): Log progress to the console while building. Default is `true`. - *poll* (`number`): Enable and define the file watching poll time period (milliseconds). + - *ignored* (`string|array`): Avoid rebuilding files when files matching this [anymatch](https://github.com/es128/anymatch) pattern fails. - *deleteOutputPath* (`boolean`): Delete output path before build. Default is `true`. - *preserveSymlinks* (`boolean`): Do not use the real path when resolving modules. Default is `false`. - *showCircularDependencies* (`boolean`): Show circular dependency warnings on builds. Default is `true`. diff --git a/packages/@angular/cli/commands/build.ts b/packages/@angular/cli/commands/build.ts index 96fcb7ceae2c..c1d668ada9b9 100644 --- a/packages/@angular/cli/commands/build.ts +++ b/packages/@angular/cli/commands/build.ts @@ -9,7 +9,7 @@ const Command = require('../ember-cli/lib/models/command'); const config = CliConfig.fromProject() || CliConfig.fromGlobal(); const buildConfigDefaults = config.getPaths('defaults.build', [ 'sourcemaps', 'baseHref', 'progress', 'poll', 'deleteOutputPath', 'preserveSymlinks', - 'showCircularDependencies', 'commonChunk', 'namedChunks' + 'showCircularDependencies', 'commonChunk', 'namedChunks', 'ignored' ]); // defaults for BuildOptions @@ -131,6 +131,12 @@ export const baseBuildCommandOptions: any = [ description: 'Enable and define the file watching poll time period (milliseconds).', default: buildConfigDefaults['poll'] }, + { + name: 'ignored', + type: String, + description: 'Avoid rebuilding files when files matching this anymatch pattern fails.', + default: buildConfigDefaults['ignored'] + }, { name: 'app', type: String, diff --git a/packages/@angular/cli/custom-typings.d.ts b/packages/@angular/cli/custom-typings.d.ts index ccd697a97ffa..1447033a5181 100644 --- a/packages/@angular/cli/custom-typings.d.ts +++ b/packages/@angular/cli/custom-typings.d.ts @@ -11,6 +11,7 @@ interface IWebpackDevServerConfigurationOptions { filename?: string; watchOptions?: { aggregateTimeout?: number; + ignored?: string | string[]; poll?: number; }; publicPath?: string; diff --git a/packages/@angular/cli/lib/config/schema.json b/packages/@angular/cli/lib/config/schema.json index 9a890308dbab..62c02f7be3b7 100644 --- a/packages/@angular/cli/lib/config/schema.json +++ b/packages/@angular/cli/lib/config/schema.json @@ -473,6 +473,20 @@ "description": "Enable and define the file watching poll time period (milliseconds).", "type": "number" }, + "ignored": { + "description": "Avoid rebuilding files when files matching this anymatch pattern fails.", + "oneOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ] + }, "deleteOutputPath": { "description": "Delete output path before build.", "type": "boolean", diff --git a/packages/@angular/cli/models/build-options.ts b/packages/@angular/cli/models/build-options.ts index 3bc2706a10ce..abf77cf89167 100644 --- a/packages/@angular/cli/models/build-options.ts +++ b/packages/@angular/cli/models/build-options.ts @@ -17,6 +17,7 @@ export interface BuildOptions { extractCss?: boolean; watch?: boolean; outputHashing?: string; + ignored?: string | string[]; poll?: number; app?: string; deleteOutputPath?: boolean; diff --git a/packages/@angular/cli/tasks/serve.ts b/packages/@angular/cli/tasks/serve.ts index 232cc0dd37a0..d8e4fc60e611 100644 --- a/packages/@angular/cli/tasks/serve.ts +++ b/packages/@angular/cli/tasks/serve.ts @@ -220,6 +220,7 @@ export default Task.extend({ proxy: proxyConfig, compress: serveTaskOptions.target === 'production', watchOptions: { + ignored: serveTaskOptions.ignored, poll: serveTaskOptions.poll }, https: serveTaskOptions.ssl, diff --git a/tests/e2e/tests/build/ignored.ts b/tests/e2e/tests/build/ignored.ts new file mode 100644 index 000000000000..bf4bb46ddc0f --- /dev/null +++ b/tests/e2e/tests/build/ignored.ts @@ -0,0 +1,72 @@ +import { + killAllProcesses, + waitForAnyProcessOutputToMatch +} from '../../utils/process'; +import { readFile, writeFile } from '../../utils/fs'; +import { expectToFail } from '../../utils/utils'; +import { ngServe, updateJsonFile, useCIDefaults } from '../../utils/project'; + +const webpackGoodRegEx = /webpack: Compiled successfully./; +const shouldCompile = () => waitForAnyProcessOutputToMatch(webpackGoodRegEx, 10000); +const shouldNotCompile = () => expectToFail(shouldCompile); + +const touch = (fileName: string) => readFile(fileName) + .then( + (content: string) => writeFile(fileName, content.concat('console.log(1);')), + error => writeFile(fileName, 'console.log(1);') + ); + +const updateIgnoredConfig = (ignored: string | string[]) => updateJsonFile( + '.angular-cli.json', + ({ defaults }) => { + const { build = {} } = defaults; + defaults.build = { ...build, ignored }; + } +); + +export default function() { + return Promise.resolve() + // Can specify an array of ignored options via the config + .then(() => updateIgnoredConfig([ '**/*~', '**/.*.sw[pon]' ]) + .then(() => ngServe()) + .then(() => touch('src/main.ts')).then(shouldCompile) + .then(() => touch('src/main.ts~')).then(shouldNotCompile) + .then(() => touch('src/.main.ts.swp')).then(shouldNotCompile) + .then(() => touch('src/.main.ts.swo')).then(shouldNotCompile) + .then(() => touch('src/.main.ts.swn')).then(shouldNotCompile) + .then(() => touch('src/main.ts')).then(shouldCompile) + .then(() => killAllProcesses()) + + // Can specify a single ignored option via the config + .then(() => updateIgnoredConfig('**/*~') + .then(() => ngServe()) + .then(() => touch('src/main.ts')).then(shouldCompile) + .then(() => touch('src/main.ts~')).then(shouldNotCompile) + .then(() => touch('src/.main.ts.swp')).then(shouldCompile) + .then(() => touch('src/.main.ts.swo')).then(shouldCompile) + .then(() => touch('src/.main.ts.swn')).then(shouldCompile) + .then(() => touch('src/main.ts')).then(shouldCompile) + .then(() => killAllProcesses()) + + // Can specify a single ignored option via the command line + .then(() => useCIDefaults()) + .then(() => ngServe('--ignored', '**/.*.sw[po]')) + .then(() => touch('src/main.ts')).then(shouldCompile) + .then(() => touch('src/main.ts~')).then(shouldCompile) + .then(() => touch('src/.main.ts.swp')).then(shouldNotCompile) + .then(() => touch('src/.main.ts.swo')).then(shouldNotCompile) + .then(() => touch('src/.main.ts.swn')).then(shouldCompile) + .then(() => touch('src/main.ts')).then(shouldCompile) + .then(() => killAllProcesses()) + + // Compiles on every file change by default + .then(() => useCIDefaults()) + .then(() => ngServe()) + .then(() => touch('src/main.ts')).then(shouldCompile) + .then(() => touch('src/main.ts~')).then(shouldCompile) + .then(() => touch('src/.main.ts.swp')).then(shouldCompile) + .then(() => touch('src/.main.ts.swo')).then(shouldCompile) + .then(() => touch('src/.main.ts.swn')).then(shouldCompile) + .then(() => touch('src/main.ts')).then(shouldCompile) + .then(() => killAllProcesses(), err => { killAllProcesses(); throw err; }); +}