| 16 | } |
| 17 | |
| 18 | apply(compiler) { |
| 19 | let plugin = this |
| 20 | let cwd = this.options.cwd |
| 21 | |
| 22 | compiler.hooks.compilation.tap(PluginTitle, (compilation) => { |
| 23 | compilation.hooks.optimizeModules.tap(PluginTitle, (modules) => { |
| 24 | if (plugin.options.onStart) { |
| 25 | plugin.options.onStart({ compilation }); |
| 26 | } |
| 27 | for (let module of modules) { |
| 28 | const shouldSkip = ( |
| 29 | module.resource == null || |
| 30 | plugin.options.exclude.test(module.resource) || |
| 31 | !plugin.options.include.test(module.resource) |
| 32 | ) |
| 33 | // skip the module if it matches the exclude pattern |
| 34 | if (shouldSkip) { |
| 35 | continue |
| 36 | } |
| 37 | |
| 38 | let maybeCyclicalPathsList = this.isCyclic(module, module, {}, compilation) |
| 39 | if (maybeCyclicalPathsList) { |
| 40 | // allow consumers to override all behavior with onDetected |
| 41 | if (plugin.options.onDetected) { |
| 42 | try { |
| 43 | plugin.options.onDetected({ |
| 44 | module: module, |
| 45 | paths: maybeCyclicalPathsList, |
| 46 | compilation: compilation |
| 47 | }) |
| 48 | } catch(err) { |
| 49 | compilation.errors.push(err) |
| 50 | } |
| 51 | continue |
| 52 | } |
| 53 | |
| 54 | // mark warnings or errors on webpack compilation |
| 55 | let error = new Error(BASE_ERROR.concat(maybeCyclicalPathsList.join(' -> '))) |
| 56 | if (plugin.options.failOnError) { |
| 57 | compilation.errors.push(error) |
| 58 | } else { |
| 59 | compilation.warnings.push(error) |
| 60 | } |
| 61 | } |
| 62 | } |
| 63 | if (plugin.options.onEnd) { |
| 64 | plugin.options.onEnd({ compilation }); |
| 65 | } |
| 66 | }) |
| 67 | }) |
| 68 | } |
| 69 | |
| 70 | isCyclic(initialModule, currentModule, seenModules, compilation) { |
| 71 | let cwd = this.options.cwd |