@rsdoctor/docs 1.5.4 → 1.5.6-canary.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -343,6 +343,112 @@ export default {
343
343
  };
344
344
  ```
345
345
 
346
+ ### [E1008] CJS Require Cannot Tree-Shake
347
+
348
+ Rule key: `cjs-require`
349
+
350
+ This rule warns when code uses a bare `require()` call (e.g. `const mod = require('module')`) to import an entire module without statically accessing its exports. This pattern prevents tree-shaking because the bundler cannot statically determine which exports are actually used, resulting in the entire module being bundled and increasing output size.
351
+
352
+ #### Common causes
353
+
354
+ - Using `const mod = require('module')` instead of `const { foo } = require('module')`.
355
+ - Dynamically composing the require argument (e.g. `require('module/' + name)`), which the bundler cannot statically analyze.
356
+ - Mixing `require()` inside ESM files, preventing the bundler from tree-shaking the module.
357
+
358
+ #### Solutions
359
+
360
+ 1. **Switch to destructured require**: Replace `const mod = require('module')` with `const { foo, bar } = require('module')` so the bundler can statically analyze which exports are used.
361
+ 2. **Migrate to ESM**: Prefer static `import { foo } from 'module'` syntax to take full advantage of bundler tree-shaking.
362
+ 3. **Avoid dynamic require**: If dynamic loading is needed, replace dynamic `require()` with dynamic `import()`.
363
+
364
+ #### Configuration
365
+
366
+ - **ignore**: Module path patterns to ignore (substring match applied to both issuer and required module paths).
367
+
368
+ ```ts
369
+ interface Config {
370
+ /** Module path fragments to ignore */
371
+ ignore: string[];
372
+ }
373
+ ```
374
+
375
+ Configuration example:
376
+
377
+ ```ts
378
+ import { RsdoctorRspackPlugin } from '@rsdoctor/rspack-plugin';
379
+
380
+ export default {
381
+ plugins: [
382
+ new RsdoctorRspackPlugin({
383
+ linter: {
384
+ rules: {
385
+ 'cjs-require': [
386
+ 'Warn',
387
+ { ignore: ['legacy-lib', 'node_modules/@internal/'] },
388
+ ],
389
+ },
390
+ },
391
+ }),
392
+ ],
393
+ };
394
+ ```
395
+
396
+ ### [E1009] ESM Import Resolved to CJS
397
+
398
+ Rule key: `esm-resolved-to-cjs`
399
+
400
+ This rule warns when a package provides both ESM and CJS formats (via the `module` field or `exports["."]["import"]` in `package.json`), but the bundler resolves an ESM `import` statement to the CJS entry instead. This prevents tree-shaking and leads to larger bundle sizes.
401
+
402
+ #### Common causes
403
+
404
+ - The `exports` field in `package.json` is misconfigured, so the `"import"` condition does not map to the correct ESM entry.
405
+ - An older bundler version that does not support `exports` conditional exports falls back to the CJS entry.
406
+ - The package's `module` field or `exports["import"]` path is incorrect or points to a non-existent file.
407
+ - The consumer's build config does not have `mainFields: ['module', ...]` or does not correctly handle `exports` conditions.
408
+
409
+ #### Solutions
410
+
411
+ 1. **Check the package's `exports` config**: Ensure the target package's `exports` field correctly defines the `"import"` condition pointing to a valid ESM entry file.
412
+ 2. **Upgrade the bundler or plugins**: Make sure you are using a bundler version that supports `exports` conditional exports (e.g. Rspack, Webpack 5+).
413
+ 3. **Report to the package author**: If the problem is a misconfigured `package.json` in a third-party package, file an issue with the package author.
414
+ 4. **Temporarily ignore**: If the package cannot be fixed for now, use the `ignore` option to skip the check for that package.
415
+
416
+ #### Configuration
417
+
418
+ - **ignore**: Package name patterns to ignore (substring match against the import request string).
419
+
420
+ ```ts
421
+ interface Config {
422
+ /**
423
+ * Package name patterns to ignore (substring match against the import request string).
424
+ * Example: ['my-legacy-pkg', '@internal/']
425
+ * @default []
426
+ */
427
+ ignore: string[];
428
+ }
429
+ ```
430
+
431
+ Configuration example:
432
+
433
+ ```ts
434
+ import { RsdoctorRspackPlugin } from '@rsdoctor/rspack-plugin';
435
+
436
+ export default {
437
+ plugins: [
438
+ new RsdoctorRspackPlugin({
439
+ linter: {
440
+ rules: {
441
+ 'esm-resolved-to-cjs': [
442
+ 'Warn',
443
+ { ignore: ['my-legacy-pkg', '@internal/'] },
444
+ ],
445
+ },
446
+ },
447
+ }),
448
+ ],
449
+ };
450
+ ```
451
+
346
452
  ## Linter type
347
453
 
348
454
  - The type definition for the `linter` field is as follows:
@@ -339,6 +339,112 @@ export default {
339
339
  };
340
340
  ```
341
341
 
342
+ ### [E1008] CJS Require Cannot Tree-Shake
343
+
344
+ 规则 key: `cjs-require`
345
+
346
+ 当代码中使用裸 `require()` 调用(例如 `const mod = require('module')`)导入整个模块,而没有对导出属性做静态访问时,该规则会发出警告。这类写法会阻止打包器进行 tree-shaking,因为打包器无法静态分析实际使用了哪些导出,导致整个模块被打进产物,产物体积增大。
347
+
348
+ #### 常见原因
349
+
350
+ - 使用 `const mod = require('module')` 导入整个模块,而非 `const { foo } = require('module')`。
351
+ - 动态拼接 require 参数(如 `require('module/' + name)`),打包器无法静态分析。
352
+ - 在 ESM 文件中混用 `require()`,使打包器无法对该模块做 tree-shaking。
353
+
354
+ #### 解决方案
355
+
356
+ 1. **改用解构 require**:将 `const mod = require('module')` 改为 `const { foo, bar } = require('module')`,使打包器可以静态分析实际使用的导出。
357
+ 2. **迁移到 ESM**:优先使用 `import { foo } from 'module'` 的静态 ESM 写法,充分利用打包器的 tree-shaking 能力。
358
+ 3. **避免动态 require**:如有动态加载需求,可改用动态 `import()` 代替动态 `require()`。
359
+
360
+ #### 配置
361
+
362
+ - **ignore**:需要忽略的模块路径匹配规则(对 issuer 和被 require 的模块路径均做字符串匹配)。
363
+
364
+ ```ts
365
+ interface Config {
366
+ /** 需要忽略的模块路径片段 */
367
+ ignore: string[];
368
+ }
369
+ ```
370
+
371
+ 配置示例:
372
+
373
+ ```ts
374
+ import { RsdoctorRspackPlugin } from '@rsdoctor/rspack-plugin';
375
+
376
+ export default {
377
+ plugins: [
378
+ new RsdoctorRspackPlugin({
379
+ linter: {
380
+ rules: {
381
+ 'cjs-require': [
382
+ 'Warn',
383
+ { ignore: ['legacy-lib', 'node_modules/@internal/'] },
384
+ ],
385
+ },
386
+ },
387
+ }),
388
+ ],
389
+ };
390
+ ```
391
+
392
+ ### [E1009] ESM Import Resolved to CJS
393
+
394
+ 规则 key: `esm-resolved-to-cjs`
395
+
396
+ 当某个包同时提供了 ESM 和 CJS 两种格式(通过 `package.json` 中的 `module` 字段或 `exports["."]["import"]`),但打包器在处理 ESM `import` 语句时却解析到了 CJS 入口,该规则会发出警告。这种情况会导致 tree-shaking 失效,产物体积变大。
397
+
398
+ #### 常见原因
399
+
400
+ - `package.json` 中的 `exports` 字段配置不正确,导致 `import` 条件未能正确映射到 ESM 入口。
401
+ - 打包器版本较旧,不支持 `exports` 条件导出,退而解析到 CJS 入口。
402
+ - 包本身的 `module` 字段或 `exports["import"]` 路径指向错误,或文件不存在。
403
+ - 消费方的构建配置未开启 `mainFields: ['module', ...]` 或未正确处理 `exports` 条件。
404
+
405
+ #### 解决方案
406
+
407
+ 1. **检查 `package.json` 的 `exports` 配置**:确保目标包的 `exports` 字段正确配置了 `"import"` 条件,并指向合法的 ESM 入口文件。
408
+ 2. **升级打包器或相关插件**:确保使用支持 `exports` 条件导出的打包器版本(如 Rspack、Webpack 5+)。
409
+ 3. **联系包作者**:若问题出在第三方包的 `package.json` 配置错误,可向包作者反馈或提 issue。
410
+ 4. **临时忽略**:若该包暂无法修复,可通过 `ignore` 配置项跳过对该包的检查。
411
+
412
+ #### 配置
413
+
414
+ - **ignore**:需要忽略的包名匹配规则(对 import 请求字符串做子串匹配)。
415
+
416
+ ```ts
417
+ interface Config {
418
+ /**
419
+ * 需要忽略的包名匹配规则(子串匹配 import 请求字符串)。
420
+ * 示例:['my-legacy-pkg', '@internal/']
421
+ * @default []
422
+ */
423
+ ignore: string[];
424
+ }
425
+ ```
426
+
427
+ 配置示例:
428
+
429
+ ```ts
430
+ import { RsdoctorRspackPlugin } from '@rsdoctor/rspack-plugin';
431
+
432
+ export default {
433
+ plugins: [
434
+ new RsdoctorRspackPlugin({
435
+ linter: {
436
+ rules: {
437
+ 'esm-resolved-to-cjs': [
438
+ 'Warn',
439
+ { ignore: ['my-legacy-pkg', '@internal/'] },
440
+ ],
441
+ },
442
+ },
443
+ }),
444
+ ],
445
+ };
446
+ ```
447
+
342
448
  ## Linter 类型定义
343
449
 
344
450
  - `linter`字段的类型如下:
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rsdoctor/docs",
3
- "version": "1.5.4",
3
+ "version": "1.5.6-canary.0",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "https://github.com/web-infra-dev/rsdoctor",
@@ -19,7 +19,8 @@
19
19
  "registry": "https://registry.npmjs.org/"
20
20
  },
21
21
  "devDependencies": {
22
- "@rspress/plugin-algolia": "2.0.5",
22
+ "@rspress/plugin-algolia": "2.0.6",
23
+ "@rspress/plugin-client-redirects": "2.0.6",
23
24
  "@rspress/plugin-rss": "2.0.5",
24
25
  "@types/node": "^22.8.1",
25
26
  "@types/react": "^18.3.28",
@@ -34,13 +35,13 @@
34
35
  "rspress-plugin-sitemap": "^1.2.1",
35
36
  "typescript": "^5.9.2",
36
37
  "@rsbuild/plugin-sass": "^1.5.1",
37
- "@rsdoctor/types": "1.5.4"
38
+ "@rsdoctor/types": "1.5.6-canary.0"
38
39
  },
39
40
  "dependencies": {
40
- "@rstack-dev/doc-ui": "1.12.4",
41
+ "@rstack-dev/doc-ui": "1.12.5",
41
42
  "clsx": "^2.1.1",
42
43
  "react-markdown": "^9.1.0",
43
- "@rspress/core": "2.0.5"
44
+ "@rspress/core": "2.0.6"
44
45
  },
45
46
  "scripts": {
46
47
  "dev": "cross-env RSPRESS_PERSIST_CACHE=false rspress dev",