ESLint package.json scripts 命名规范深度解析:从 ABNF 语法到仓库实战

发布时间:2026/9/10 20:15:39
ESLint package.json scripts 命名规范深度解析:从 ABNF 语法到仓库实战 ESLint package.json scripts 命名规范深度解析从 ABNF 语法到仓库实战【免费下载链接】eslintFind and fix problems in your JavaScript code.项目地址: https://gitcode.com/GitHub_Trending/es/eslintpackage.json的scripts字段是 npm 生态中每个项目最常用的任务入口但当项目规模增长到 ESLint 这种程度——仓库内同时存在根目录、docs目录以及packages/*多个 npm 包几十个脚本名如何做到一眼可读、机器可排序、贡献者可预判ESLint 用一份贡献者约定文档 docs/src/contribute/package-json-conventions.md 给出了完整答案。本篇以该文档为骨架结合仓库中 package.json、docs/package.json、packages/eslint-config-eslint/package.json 等真实配置与 Makefile.js 的实现细节系统讲解这套命名体系读完你将掌握脚本命名的主名、修饰符、排序规则理解lint:fix:docs:js这类长名字的组成逻辑并能据此为任何 npm 项目设计一致、可扩展的脚本集。适用范围约定只作用于scripts段规范开宗明义该约定仅适用于package.json文件中的scripts部分不涉及dependencies、devDependencies、exports、files等其他字段。这意味着每个脚本名都必须符合下述命名文法脚本所执行的命令本身不受本规范约束例如eslint、prettier、webpack的具体参数写法保持自由仓库内所有 npm 包都应遵守同一套约定保证跨目录、跨包的可预期性。在 ESLint 仓库中这类被规范约束的package.json不止一份最典型的有根目录 package.jsonESLint 主包版本 10.9.1、文档站点 docs/package.jsondocs-eslint私有包、packages/eslint-config-eslint/package.json官方共享配置以及 packages/js/package.jsoneslint/js语言实现。它们的scripts都能在下面的文法框架内被完整解析。命名规范字符集、单词与 ABNF 文法允许的字符与组成部分脚本名只能由小写字母、:、-、组成且各有分工字符用途示例小写字母单词本身lint、build:分隔不同的部分partlint:fix:docs:js-在单个部分内分隔多个单词update-links分隔被影响的文件扩展名列表lint:jscjs列表需按字母序除此之外每个部分的名字part name应要么是完整的英文单词如coverage而非缩写cov要么是全小写的通用缩写initialism如wasm。这条规则的目的是让脚本名无需查文档即可被人类与搜索工具理解。ABNF 文法规范将命名规则形式化为如下 ABNF 摘要这是整份约定的语法核心name life-cycle / main target? option* :watch? life-cycle prepare / preinstall / install / postinstall / prepublish / preprepare / prepare / postprepare / prepack / postpack / prepublishOnly main build / lint :fix? / fmt :check? / release / start / test / fetch target : word (- word)* / extension ( extension)* option : word (- word)* word ALPHA extension ( ALPHA / DIGIT )逐行解读name要么是一个 npm 生命周期脚本名life-cycle这些名字由 npm 预定义、不受本约定管束见下文要么是main主名后跟可选的target、若干个option以及可选的:watch结尾。注意文法中main target? option* :watch?的顺序它同时约束了修饰符的排列次序。main是七个固定主名之一build、lint、fmt、release、start、test、fetch。其中lint内置可选:fixfmt内置可选:check这是文法层面对两个高频修饰符的特殊支持。target用:引导单词间可用-连接或者直接使用由连接的扩展名列表扩展名允许数字如js、cjs、less、css3。option与target结构相同是放不进其他修饰符的补充选项。word必须是至少一个英文字母extension允许字母或数字。一个完整的名字示例lint:fix:docs:js可以解析为main lint、option/fix fix、target docs、option js。而build:docs:update-links则是main build、target docs、option update-links。生命周期脚本唯一豁免npm 自身预定义的生命周期脚本preinstall、install、postinstall、prepublish、prepare、prepack、prepublishOnly等是命名规范的唯一例外——这些名字由 npm 强制规定项目无法自定义因此规范明确它们不要求遵守main命名。仓库中的真实案例是 packages/eslint-config-eslint/package.json 中的prepublish: npm test在发布前自动执行测试这是生命周期脚本的典型用途。排序规范字母顺序即逻辑分组scripts中的脚本名必须按字母顺序排列MUST。这份规范的设计巧妙之处在于只要每个脚本遵循上文的主名 修饰符文法字母顺序就会恰好与逻辑分组重合。原因很简单同一主名下的脚本共享前缀。以根 package.json 为例build:...系列的脚本天然聚集在一起test:...系列聚集在一起build:docs:update-links: node tools/fetch-docs-links.js, build:site: node Makefile.js gensite, build:webpack: node Makefile.js webpack, build:readme: node tools/update-readme.js, build:rules-index: node Makefile.js generateRuleIndexPage,读者扫一眼就能知道构建类脚本都在这一块。同时lint:fix排在lint:fix:docs:js之前短名先于其长变体也符合字母序与层级感的双重直觉。值得说明的是仓库中个别历史脚本在排列顺序上存在细微出入但命名文法本身在所有包中都得到了贯彻——这说明该规范是贡献者维护时的目标状态而非一次性强制校验。主脚本名七个固定前缀与它们的语义除生命周期脚本外所有脚本名必须以以下七个名字之一开头。每个主名都有明确、互斥的语义边界Build由源码/数据生成文件生成一组文件从源代码或数据的脚本名字必须以build开头。仓库中 docs/package.json 是典型代表它把文档站点的完整构建拆成了并行子任务build: npm-run-all build:sass build:postcss build:website build:minify-images, build:postcss: postcss src/assets/css -d src/assets/css, build:sass: sass src/assets/scss:src/assets/css --no-source-map, build:website: npx 11ty/eleventy, build:minify-images: imagemin _site/assets/images --out-dir_site/assets/images规则同时规定如果包内存在多个build:*脚本可以MAY提供一个聚合的build脚本其输出应SHOULD等于逐个运行各build:*的总和且必须MUST是这些脚本输出的子集。docs包中build通过npm-run-all依次执行四个子构建正是这条规则的直接应用。Fetch从外部数据/资源生成文件与build类似但数据来源是外部资源的脚本前缀必须是fetch。语义差异在于build的输入是仓库内的源码与数据fetch的输入在仓库之外远程接口、第三方站点等。同样允许存在聚合的fetch脚本输出规则与build一致SHOULD 等价、MUST 为子集。ESLint 中抓取规则文档外部链接的工具 tools/fetch-docs-links.js 被挂载在build:docs:update-links下从脚本结构上体现了命名约定在实际演进中允许的灵活性。Release具有公共副作用只要脚本会对外部世界产生公开可见的副作用——发布网站、提交 Git、推送远程、发布 npm 包等——就必须以release开头。这是区分内部构建与对外发布的硬边界。根 package.json 中的发布族脚本完整展示了这一设计release:generate:alpha: node Makefile.js generatePrerelease -- alpha, release:generate:beta: node Makefile.js generatePrerelease -- beta, release:generate:latest: node Makefile.js generateRelease -- latest, release:generate:maintenance: node Makefile.js generateRelease -- maintenance, release:generate:rc: node Makefile.js generatePrerelease -- rc, release:publish: node Makefile.js publishReleaserelease:generate:*负责生成版本打 tag、写 CHANGELOG、更新站点数据release:publish负责真正发布到 npm 并推送远程——两者共享release前缀职责却通过optiongenerate、publish与targetalpha、beta、latest、maintenance、rc进一步细分。Lint静态分析对文件进行静态分析的脚本绝大多数情况就是运行 ESLint 自身必须以lint开头。规则包含两个重要约束存在lint:*子脚本时应提供一个聚合的lint脚本且它必须运行所有lint:*各自会执行的检查的并集若修复功能可用linter 不得自动修复除非脚本名带:fix修饰符——这是检查与修复在命名上的强制性分离。根 package.json 的 lint 族对此体现得淋漓尽致lint: node Makefile.js lint, lint:docs:js: node Makefile.js lintDocsJS, lint:docs:rule-examples: node Makefile.js checkRuleExamples, lint:unused: knip, lint:fix: node Makefile.js lint -- fix, lint:fix:docs:js: node Makefile.js lintDocsJS -- fix, lint:rule-types: node tools/update-rule-type-headers.js --check, lint:types: attw --packlint聚合了主代码检查lint:docs:js与lint:docs:rule-examples分别覆盖文档目录中的 JavaScript 与规则示例lint:types用attw --pack做类型发布检查lint:unused用knip排查未使用的依赖/导出。而lint:fix与lint:fix:docs:js则是各自只检查版本的修复对——严格遵循不带:fix就不修复的原则。Fmt格式化源码格式化源代码的脚本必须以fmt开头。当存在fmt:*子脚本时应提供两个约定搭档fmt对全部源文件应用格式化修复fmt:check只校验格式、不修改任何文件一旦发现不合规就退出非零状态码。根 package.json 就是最小实现fmt: prettier --write ., fmt:check: prettier --check .注意主名是fmt而非format这是文法中固定的拼写贡献者不应改写。fmt:check的可被 CI 调用的非零退出语义使格式校验天然适合接入持续集成流水线。Start启动服务器start脚本专用于启动服务器。截至本文写作时ESLint 仓库中只有 docs/package.json 使用它——用于启动 Eleventy 本地文档服务器并监听文件变化start: npm-run-all build:sass build:postcss --parallel *:*:watch规范指出目前没有任何 ESLint 包拥有超过一个start脚本因此暂时无需为start设计修饰符若未来出现多服务器场景按文法可用:target指明启动的是哪台服务器。Test验证实际行为符合预期执行代码以验证实际行为与预期一致的脚本必须以test开头。规则要求存在test:*子脚本时应提供聚合的test脚本且它必须运行所有test:*各自测试的并集测试脚本不应包含 lint 检查检查与测试的关注点分离避免npm test与npm run lint职责混淆测试脚本应尽可能输出测试覆盖率。根 package.json 的测试族规模最大覆盖了 CLI、浏览器、模糊测试、性能、生态、类型等维度test: node Makefile.js test, test:browser: node Makefile.js cypress, test:cli: mocha, test:ecosystem: node tools/test-ecosystem/index.mjs, test:ecosystem:update: node tools/test-ecosystem/update.mjs, test:emfile: node tools/check-emfile-handling.js, test:fuzz: node Makefile.js fuzz, test:performance: node Makefile.js perf, test:pnpm: cd tests/pnpm node check.js pnpm install pnpm exec tsc, test:types: tsc -p tests/lib/types/tsconfig.json npm run test:types --workspaces --if-present, test:types:5.3: npx -p typescript5.3 -y -- tsc -p tsconfig.types-legacy.json, test:types:5.x: npx -p typescript5.x -y -- tsc -p tsconfig.types.json, test:types:7.x: npx -p typescript/native-previewlatest -y -- tsgo -p tsconfig.types.json, test:types:all: npm run test:types npm run test:types:5.3 npm run test:types:5.x npm run test:types:7.xtest:types:5.3/test:types:5.x/test:types:7.x分别针对不同 TypeScript 版本做类型检查再由test:types:all聚合——这是target/option 描述被测试对象的最佳示范types是 target版本号是 option。修饰符Fix、Check、Target、Options、Watch主名之后可以追加一个或多个修饰符。若有多个修饰符必须严格按下述顺序排列文法中main target? option* :watch?即是对此的编码例如lint:fix:js:watch合法而lint:watch:js:fix非法。Fix若 linter 能修复发现的问题应额外提供一个在原脚本名末尾追加:fix的副本该副本同时执行修复。仓库中lint:fix与lint:fix:docs:js就是lint、lint:docs:js的修复版。从实现看两者共享同一 Makefile 目标只是参数不同lint: node Makefile.js lint与lint:fix: node Makefile.js lint -- fix最终都进入 Makefile.js 的target.lint第 535 行后者通过-- fix参数将修复开关置真。Check若脚本只校验代码或产物而不做任何修改则追加:check。典型场景是格式化校验fmt:check。带:check的脚本绝不能修改任何文件或输出发现问题应以非零状态退出。仓库中lint:rule-types执行node tools/update-rule-type-headers.js --check也体现了同样语义——--check意味着只比对、不写回。Target描述动作作用的对象build脚本的 target 应标识构建产物例如build:website、build:webpack中的website、webpack后者实为产物名指向用 webpack 打出的浏览器包lint/test脚本的 target 应标识被检查/被测试的对象如lint:docs:js的docs、test:types的typesstart脚本的 target 应标识启动的服务器。target 可以是一组受影响的文件扩展名用连接多个扩展名应按字母序排列当扩展名存在变体如 CommonJS 的cjs与 ESM 的mjs时允许使用公共部分js代替逐一罗列js取代cjsjsxmjs。此外target 不应是执行动作的工具名——所以文档站点的构建脚本叫build:website而非build:eleventy尽管它实际运行的是npx 11ty/eleventy见 docs/package.json。这条规则把做什么与用什么做彻底解耦。Options放不进上述分类的补充选项用:引导。例如build:docs:update-links中的update-links、release:generate:alpha中的alpha。选项的存在让同一 target 下的多个变体脚本可以平行命名、平行扩展。Watch脚本若监听文件系统并对变化做出响应追加:watch。这是文法中唯一的尾缀。docs 站点开发是典型用例docs/package.json 中build:postcss:watch: postcss src/assets/css -d src/assets/css --watch --poll, build:sass:watch: sass --watch --poll src/assets/scss:src/assets/css --no-source-map, build:website:watch: eleventy --serve --incremental --port2023三个*:watch脚本通过start脚本里的npm-run-all ... --parallel *:*:watch一并并行拉起构成本地开发服务器——start主名 :watch修饰符的组合在这里完成了从构建到开发的语义闭环。仓库实战从 npm 脚本名到 Makefile 目标命名约定不止停留在看起来整齐它与仓库的执行层实现严格对齐。ESLint 根包的大量脚本通过node Makefile.js target [args]形式调用 Makefile.js基于 shelljs/make 的构建文件每个 npm 脚本名与文件中的target.*一一对应npm 脚本Makefile 目标实现要点Makefile.js 行号lint/lint:fixtarget.lint([fix])以--fix参数控制是否修复见 第 535 行lint:docs:js/lint:fix:docs:jstarget.lintDocsJS([fix])用 ESLint 校验 docs 目录 JS见 第 568 行lint:docs:rule-examplestarget.checkRuleExamples校验 docs 中的规则示例见 第 934 行build:sitetarget.gensite生成文档站点数据见 第 681 行build:webpacktarget.webpack打包浏览器版本见 第 742 行testtarget.test聚合 checkRuleFiles → mocha → fuzz(150) → checkLicenses见 第 674 行test:fuzztarget.fuzz模糊测试默认 1000 次见 第 583 行test:browsertarget.cypress浏览器单元测试见 第 657 行test:performancetarget.perf性能对比测试见 第 1122 行release:generate:*/release:publishtarget.generatePrerelease/target.generateRelease/target.publishRelease版本生成与发布见 第 1147-1150 行这段映射印证了规范的深层价值脚本名是做什么的声明Makefile 目标/命令是怎么做的实现两者通过一致的命名沟通。贡献者看到test:browser就能直接定位到对应实现看到release:publish就知道它必然涉及公共副作用事实也正是如此——target.publishRelease会调用ReleaseOps.publishRelease()发布 npm 包并推送 Git 与站点仓库见 第 411-451 行。另外可以观察到target.test第 674 行依次运行checkRuleFiles、mocha、fuzz({ amount: 150 })、checkLicenses没有调用任何 lint 目标——与规范中测试脚本不应包含 lint 检查的要求严格一致。给贡献者的自查清单在 ESLint 仓库或任何想借鉴这套体系的项目中新增package.json脚本时可按以下清单逐条核对主名前缀正确这个脚本是生成文件build/fetch、发布release、静态检查lint、格式化fmt、启动服务器start还是测试test字符合法只有小写字母、:、-、单词是完整英文词或全小写通用缩写。修饰符顺序正确main→target→option*→:watchfix必须位于check/target之前如lint:fix:docs:js。修复不静默linter 修复能力只暴露在带:fix的脚本里只校验不改动的脚本带:check。扩展名列表用连接并按字母序有变体时允许用公共部分。不写工具名target 描述对象不写eleventy、webpack这类工具。字母排序把新脚本放到scripts中应处的位置让同前缀脚本自然聚组。生命周期脚本豁免preinstall、prepare、prepublish等由 npm 决定名字不适用本规范。这套约定并非 ESLint 的私有发明而是一份可复用的工程模板它把脚本命名从个人风格问题转化为可由 ABNF 校验、可被排序、可被搜索的结构化约定让一个几十脚本规模的大型 npm 仓库保持长期一致的可维护性。当你下次面对一屏混乱的scripts时不妨直接照搬这套main:target:option文法重新组织一遍。【免费下载链接】eslintFind and fix problems in your JavaScript code.项目地址: https://gitcode.com/GitHub_Trending/es/eslint创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询