diff --git a/examples/modern-minimal/tsconfig.json b/examples/modern-minimal/tsconfig.json index f39aeccf..658aad51 100644 --- a/examples/modern-minimal/tsconfig.json +++ b/examples/modern-minimal/tsconfig.json @@ -1,6 +1,6 @@ { "extends": "@rsdoctor/tsconfig/base", - "include": ["src"], + "include": ["src", "../webpack-minimal/src/deps"], "compilerOptions": { "outDir": "dist", "baseUrl": ".", diff --git a/examples/rspack-layers-minimal/build.ts b/examples/rspack-layers-minimal/build.ts index c9c95b10..eb502abe 100644 --- a/examples/rspack-layers-minimal/build.ts +++ b/examples/rspack-layers-minimal/build.ts @@ -13,8 +13,6 @@ function rspackBuild(config: rspack.Configuration) { throw err; } - console.log(); - if (stats) { console.log( stats.toString({ diff --git a/packages/cli/src/index.ts b/packages/cli/src/index.ts index 837a304d..4788449b 100644 --- a/packages/cli/src/index.ts +++ b/packages/cli/src/index.ts @@ -67,7 +67,6 @@ export async function execute( await action(args); } catch (error) { const { message, stack } = error as Error; - console.log(''); console.error(red(stack || message)); process.exit(1); } diff --git a/packages/components/src/utils/file.tsx b/packages/components/src/utils/file.tsx index 45e0bb41..0c100af1 100644 --- a/packages/components/src/utils/file.tsx +++ b/packages/components/src/utils/file.tsx @@ -158,7 +158,6 @@ export function readJSONByFileReader(file: unknown const reader = new FileReader(); reader.onloadend = () => { const { result } = reader; - console.log('reader result: ', result); try { const json = JSON.parse(result!.toString()); resolve(json); diff --git a/packages/core/package.json b/packages/core/package.json index 75e4d44f..b3f584d4 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -72,7 +72,9 @@ "@rsdoctor/sdk": "workspace:*", "@rsdoctor/types": "workspace:*", "@rsdoctor/utils": "workspace:*", + "@types/circular-dependency-plugin": "^5.0.8", "axios": "^1.7.9", + "circular-dependency-plugin": "^5.2.2", "enhanced-resolve": "5.12.0", "filesize": "^10.1.6", "fs-extra": "^11.1.1", diff --git a/packages/core/src/rules/rules/circular-dependency/index.ts b/packages/core/src/inner-plugins/plugins/rule-plugins/circular-dependency/index.ts similarity index 59% rename from packages/core/src/rules/rules/circular-dependency/index.ts rename to packages/core/src/inner-plugins/plugins/rule-plugins/circular-dependency/index.ts index f592ed4f..e3500d68 100644 --- a/packages/core/src/rules/rules/circular-dependency/index.ts +++ b/packages/core/src/inner-plugins/plugins/rule-plugins/circular-dependency/index.ts @@ -1,5 +1,22 @@ +import path from 'path'; +let extend = require('util')._extend; + +let BASE_ERROR = 'Circular dependency detected:\r\n' +let PluginTitle = 'CircularDependencyPlugin' + export class CircularDependencyPlugin { - constructor(options) { + options: { + exclude: RegExp; + include: RegExp; + failOnError: boolean; + allowAsyncCycles: boolean; + onDetected?: (data: { module: any; paths: string[]; compilation: any }) => void; + onStart?: (data: { compilation: any }) => void; + onEnd?: (data: { compilation: any }) => void; + cwd: string; + }; + + constructor(options: Partial) { this.options = extend({ exclude: new RegExp('$^'), include: new RegExp('.*'), @@ -7,15 +24,14 @@ export class CircularDependencyPlugin { allowAsyncCycles: false, onDetected: false, cwd: process.cwd() - }, options) + }, options); } - apply(compiler) { - let plugin = this - let cwd = this.options.cwd + apply(compiler: any) { + let plugin = this; - compiler.hooks.compilation.tap(PluginTitle, (compilation) => { - compilation.hooks.optimizeModules.tap(PluginTitle, (modules) => { + compiler.hooks.compilation.tap(PluginTitle, (compilation: any) => { + compilation.hooks.optimizeModules.tap(PluginTitle, (modules: any[]) => { if (plugin.options.onStart) { plugin.options.onStart({ compilation }); } @@ -24,54 +40,56 @@ export class CircularDependencyPlugin { module.resource == null || plugin.options.exclude.test(module.resource) || !plugin.options.include.test(module.resource) - ) + ); // skip the module if it matches the exclude pattern if (shouldSkip) { - continue + continue; } - let maybeCyclicalPathsList = this.isCyclic(module, module, {}, compilation) + let maybeCyclicalPathsList = this.isCyclic(module, module, {}, compilation); if (maybeCyclicalPathsList) { // allow consumers to override all behavior with onDetected if (plugin.options.onDetected) { try { - plugin.options.onDetected({ - module: module, - paths: maybeCyclicalPathsList, - compilation: compilation - }) + if (Array.isArray(maybeCyclicalPathsList)) { + plugin.options.onDetected({ + module: module, + paths: maybeCyclicalPathsList, + compilation: compilation + }); + } } catch(err) { - compilation.errors.push(err) + compilation.errors.push(err); } - continue + continue; } // mark warnings or errors on webpack compilation - let error = new Error(BASE_ERROR.concat(maybeCyclicalPathsList.join(' -> '))) + let error = maybeCyclicalPathsList && typeof maybeCyclicalPathsList === 'object' && maybeCyclicalPathsList.length && new Error(BASE_ERROR.concat(maybeCyclicalPathsList.join(' -> '))); if (plugin.options.failOnError) { - compilation.errors.push(error) + compilation.errors.push(error); } else { - compilation.warnings.push(error) + compilation.warnings.push(error); } } } if (plugin.options.onEnd) { plugin.options.onEnd({ compilation }); } - }) - }) + }); + }); } - isCyclic(initialModule, currentModule, seenModules, compilation) { - let cwd = this.options.cwd + isCyclic(initialModule: any, currentModule: any, seenModules: { [key: string]: boolean }, compilation: any): string[] | undefined | boolean { + let cwd = this.options.cwd; // Add the current module to the seen modules cache - seenModules[currentModule.debugId] = true + seenModules[currentModule.debugId] = true; // If the modules aren't associated to resources // it's not possible to display how they are cyclical if (!currentModule.resource || !initialModule.resource) { - return false + return false; } // Iterate over the current modules dependencies @@ -80,27 +98,27 @@ export class CircularDependencyPlugin { dependency.constructor && dependency.constructor.name === 'CommonJsSelfReferenceDependency' ) { - continue + continue; } - let depModule = null + let depModule: any = null; if (compilation.moduleGraph) { // handle getting a module for webpack 5 - depModule = compilation.moduleGraph.getModule(dependency) + depModule = compilation.moduleGraph.getModule(dependency); } else { // handle getting a module for webpack 4 - depModule = dependency.module + depModule = dependency.module; } - if (!depModule) { continue } + if (!depModule) { continue; } // ignore dependencies that don't have an associated resource - if (!depModule.resource) { continue } + if (!depModule.resource) { continue; } // ignore dependencies that are resolved asynchronously - if (this.options.allowAsyncCycles && dependency.weak) { continue } + if (this.options.allowAsyncCycles && dependency.weak) { continue; } // the dependency was resolved to the current module due to how webpack internals // setup dependencies like CommonJsSelfReferenceDependency and ModuleDecoratorDependency if (currentModule === depModule) { - continue + continue; } if (depModule.debugId in seenModules) { @@ -109,19 +127,19 @@ export class CircularDependencyPlugin { return [ path.relative(cwd, currentModule.resource), path.relative(cwd, depModule.resource) - ] + ]; } // Found a cycle, but not for this module - continue + continue; } - let maybeCyclicalPathsList = this.isCyclic(initialModule, depModule, seenModules, compilation) + let maybeCyclicalPathsList: any = this.isCyclic(initialModule, depModule, seenModules, compilation); if (maybeCyclicalPathsList) { - maybeCyclicalPathsList.unshift(path.relative(cwd, currentModule.resource)) - return maybeCyclicalPathsList + maybeCyclicalPathsList.unshift(path.relative(cwd, currentModule.resource)); + return maybeCyclicalPathsList; } } - return false + return false; } -} +} \ No newline at end of file diff --git a/packages/core/src/inner-plugins/plugins/rule-plugins/index.ts b/packages/core/src/inner-plugins/plugins/rule-plugins/index.ts new file mode 100644 index 00000000..ec76fa62 --- /dev/null +++ b/packages/core/src/inner-plugins/plugins/rule-plugins/index.ts @@ -0,0 +1,10 @@ +import { CircularDependencyPlugin } from "./circular-dependency"; + +export const circularDependencyPlugin = new CircularDependencyPlugin({ + // 在这里添加所需的选项 + exclude: /node_modules/, + include: /src/, + failOnError: true, + allowAsyncCycles: false, + cwd: process.cwd(), +}); \ No newline at end of file diff --git a/packages/core/src/inner-plugins/plugins/rules.ts b/packages/core/src/inner-plugins/plugins/rules.ts index 0a3f4f3a..78cff2d2 100644 --- a/packages/core/src/inner-plugins/plugins/rules.ts +++ b/packages/core/src/inner-plugins/plugins/rules.ts @@ -4,12 +4,16 @@ import { DevToolError } from '@rsdoctor/utils/error'; import { isArray, pull } from 'lodash'; import { Plugin } from '@rsdoctor/types'; import { WebpackError } from 'webpack'; +import { circularDependencyPlugin } from './rule-plugins'; export class InternalRulesPlugin extends InternalBasePlugin { public readonly name = 'rules'; public apply(compiler: Plugin.BaseCompiler) { compiler.hooks.done.tapPromise(this.tapPreOptions, this.done); + + // Execute rules plugins. + circularDependencyPlugin.apply(compiler); } public done = async (stats: Plugin.BaseStats): Promise => { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 7c88199e..ccc30e1d 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -690,9 +690,15 @@ importers: '@rsdoctor/utils': specifier: workspace:* version: link:../utils + '@types/circular-dependency-plugin': + specifier: ^5.0.8 + version: 5.0.8 axios: specifier: ^1.7.9 version: 1.7.9(debug@4.3.7) + circular-dependency-plugin: + specifier: ^5.2.2 + version: 5.2.2(webpack@5.95.0) enhanced-resolve: specifier: 5.12.0 version: 5.12.0 @@ -8558,6 +8564,18 @@ packages: '@types/node': 16.18.104 dev: true + /@types/circular-dependency-plugin@5.0.8: + resolution: {integrity: sha512-P9nspqZxy+9NsoS4KOG5p1JFss0n0pv8UHD8OAP7bz4lAkgtdAnOS0J0ZXlcqzekWdUtmCFwpIuW+AtOhFp8VA==} + dependencies: + '@types/node': 16.18.104 + webpack: 5.95.0 + transitivePeerDependencies: + - '@swc/core' + - esbuild + - uglify-js + - webpack-cli + dev: false + /@types/configstore@2.1.1: resolution: {integrity: sha512-YY+hm3afkDHeSM2rsFXxeZtu0garnusBWNG1+7MknmDWQHqcH2w21/xOU9arJUi8ch4qyFklidANLCu3ihhVwQ==} dev: false @@ -10342,6 +10360,15 @@ packages: safe-buffer: 5.2.1 dev: true + /circular-dependency-plugin@5.2.2(webpack@5.95.0): + resolution: {integrity: sha512-g38K9Cm5WRwlaH6g03B9OEz/0qRizI+2I7n+Gz+L5DxXJAPAiWQvwlYNm1V1jkdpUv95bOe/ASm2vfi/G560jQ==} + engines: {node: '>=6.0.0'} + peerDependencies: + webpack: '>=4.0.1' + dependencies: + webpack: 5.95.0 + dev: false + /classnames@2.5.1: resolution: {integrity: sha512-saHYOzhIQs6wy2sVxTM6bUDsQO4F50V9RQ22qBpEdCW+I+/Wmke2HOl6lS6dTpdxVhb88/I6+Hs+438c3lfUow==} @@ -20740,7 +20767,7 @@ packages: '@webassemblyjs/wasm-parser': 1.12.1 acorn: 8.12.1 acorn-import-attributes: 1.9.5(acorn@8.12.1) - browserslist: 4.24.0 + browserslist: 4.23.3 chrome-trace-event: 1.0.4 enhanced-resolve: 5.17.1 es-module-lexer: 1.5.4