ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

eslint-config-expo 使用指南:为 Expo 跨端项目定制基础 ESLint 配置

eslint-config-expo 使用指南:为 Expo 跨端项目定制基础 ESLint 配置 eslint-config-expo 使用指南为 Expo 跨端项目定制基础 ESLint 配置【免费下载链接】expoAn open-source framework for making universal native apps with React. Expo runs on Android, iOS, and the web.项目地址: https://gitcode.com/GitHub_Trending/ex/expo本篇文章围绕 Expo 官方仓库中的eslint-config-expo包package.json展开讲解它的设计定位、安装方式以及如何把它作为基础配置与你自己挑选的 lint 规则组合同时兼容新版 ESLint flat config 与旧版.eslintrc两种体系。读完你会掌握为 Expo 项目支持.android.js、.ios.js、.web.js等平台化文件与 JSX/TypeScript接入 ESLint 的标准姿势以及这一配置在底层究竟替你做了什么。这个配置的定位极简的基座而非全家桶eslint-config-expo在 README 中的自我定位非常明确它是Expo 项目的基础 ESLint 配置Base ESLint config一个保持最小化minimal的配置——只负责处理与 Expo / React Native 工程形态强相关的基础问题支持JSX 与 TypeScript的解析提供平台相关的全局变量如__DEV__让 ESLint 认识.android.js、.ios.js、.web.js这类平台扩展名文件。它的哲学是组合compose而非捆绑bundle官方把语法能力与平台常识内置好而具体的编码风格规则是 Airbnb、Standard还是你自定义的一套留给你在项目自己的 ESLint 配置中去决定。README 中的一句话点明了意图You are intended to compose this base config with the linter rules of your choice。安装步骤首先安装配置包本体官方推荐用 Yarnyarn add --dev eslint-config-expo接着需要安装 ESLint 本体二者缺一不可yarn add --dev eslint从仓库内的 package.json 可以看到该包的peerDependencies声明eslint 8.10同时它自身在开发期会同时用eslint^9.18.0与eslint8即npm:eslint^8.57.1做双版本回归测试——也就是说从 ESLint 8.10 起、到 8.x 与 9.x 系列该配置都支持。它的功能依赖由以下包提供均会被自动安装依赖用途typescript-eslint/eslint-plugin/parserTS/TSX 解析与 TS 专属规则eslint-plugin-importimport 语法检查与解析器路由eslint-plugin-reactReact / JSX 相关检查eslint-plugin-react-hooksHooks 规则推荐集eslint-plugin-expoExpo 专属规则monorepo workspace 依赖eslint-import-resolver-typescriptimport 的 TS 路径解析globals现代环境全局变量定义来源注意其中的eslint-plugin-expo在本仓库中是一个独立的子包见 packages/eslint-plugin-expo二者以 workspace 版本关联发布时会被正确带入依赖树。使用方式一flat config官方推荐ESLint 自 8.21 起引入的新配置系统即 ESLint 9 时代的默认形态使用eslint.config.js这类文件通过数组层层叠放配置对象。在仓库中flat 入口位于 flat.js真正实现则在 flat/default.js。引入方式如下// eslint.config.js const expoConfig require(eslint-config-expo/flat); const { defineConfig } require(eslint/config); module.exports defineConfig([ expoConfig, // your other config ]);要点拆解defineConfig来自eslint/configESLint 9 内置导出它只是给配置数组做类型收窄的辅助函数不传也可直接module.exports [expoConfig, ...]同样生效expoConfig本身已是一个由多个配置对象组成的数组因此要用展开spread语义把它平铺进你的数组用...expoConfig或直接传入数组字面量都行而不是包一层{ ... }再嵌套expoConfig排在最前之后追加你自己的 config后者可以按数组顺序覆盖/补充前者。flat 实现里到底包含什么查看 flat/default.js 源码可以发现 flat 版本是由core、typescript、react、expo四块配置分别对应 flat/utils/core.js、flat/utils/typescript.js、flat/utils/react.js、flat/utils/expo.js按顺序展开拼接而成随后再统一注入全局变量与文件匹配规则平台感知的全局变量直接铺开globals.browser来自globals包再叠加__DEV__: readonly以及ErrorUtils、FormData、XMLHttpRequest、alert、fetch、navigator、requestAnimationFrame、window等 RN 环境下看起来像全局的 API还有shared-node-browser: true这类 ESLint 专用标记import 解析支持平台扩展名通过settings[import/extensions]与settings[import/resolver].node.extensions注入allExtensions即下述扩展名组合全集保证 import 解析器能命中.android.tsx这类文件web 文件匹配位追加一个空规则对象{ files: [*.web.*] }作为后续你自定义规则时可直接引用的针对 web 平台文件生效的定位锚点。使用方式二legacy 配置.eslintrc 体系ESLint 会同时检查package.json与.eslintrc.*文件来定位配置两种写法等价写在 package.json 的 eslintConfig 字段{ eslintConfig: { extends: [expo] } }写在独立的 .eslintrc.jsmodule.exports { extends: [expo], };这一入口对应包根目录的 default.js它本质上由extends串联了 utils/core.js、utils/typescript.js、utils/react.js、utils/expo.js 四个子配置。legacy 与 flat 版本在规则内容上保持一致差异只在配置载体与组织方式。深入原理一平台化扩展名.android.js/.ios.js/.web.js是如何被认识的这是整个配置最核心的工程价值所在。MetroReact Native 的打包器支持按平台后缀解析文件例如Button.android.js只在 Android 生效、Button.web.js只在 Web 生效而 Expo 又额外支持.native.js原生平台通用与无后缀回退。若 ESLint 不认识这些文件名就会出现明明文件存在却报解析/导入错误的假阳性。解析逻辑见 utils/extensions.jsconst jsExtensions [.js, .jsx]; const tsExtensions [.ts, .tsx, .d.ts]; const platformSubextensions [.android, .ios, .web, .native]; function computeExpoExtensions(baseExtensions, platformSubextensions) { const expoExtensions []; for (const platform of [...platformSubextensions, ]) { for (const base of baseExtensions) { expoExtensions.push(${platform}${base}); } } return expoExtensions; }这段循环做了两层笛卡尔积基础扩展名JS 侧.js/.jsxTS 侧.ts/.tsx/.d.ts平台子扩展名.android、.ios、.web、.native外加一个空串即无平台后缀的普通文件。于是最终被 ESLint 认知的完整文件形态包含.android.js、.ios.js、.web.js、.native.js、.web.tsx、.android.tsx、.d.ts…… 等全部组合。这套全集被注入到 import 插件的extensions与 resolver 的node.extensions从而让规则报错时不会误伤平台化拆分文件。顺带一提utils/typescript.js 中还专门设置了import/parsers对*.js/*.jsx文件仍按typescript-eslint/parser路由 TS 扩展名解决 JS 文件引用 TS 模块的解析TS 侧再叠加plugin:import/typescript与eslint-import-resolver-typescript的能力。深入原理二Expo 专属规则与平台全局变量expo 插件规则的开关utils/expo.js 引入了eslint-plugin-expo并默认开启三条error 级的 Expo 专属规则规则严重度含义expo/use-dom-exportserror要求 DOM 相关的导出走正确入口SDK 52 之后 Web 通用能力迁移到expo/dom相关导出expo/no-env-var-destructuringerror禁止对process.env做解构取值expo/no-dynamic-env-varerror禁止用动态键访问环境变量这三条规则的具体实现见 packages/eslint-plugin-expo/srceslint-config-expo只是它们的启用方。它同时还做了一件很务实的事在ignorePatterns中忽略android/app/build——因为构建中间产物里会出现EXDevMenuApp.android.js这类 JS 文件源码注释也举了android/app/build/intermediates/assets/debug/EXDevMenuApp.android.js的例子不忽略的话会拖慢 lint 并产生噪声。平台全局变量与覆盖策略在 legacy 版 default.js 中直接声明了 React Native 运行时可见、但在 Node 语法环境里不属于标准全局的标识符例如__DEV__: readonly、ErrorUtils、XMLHttpRequest、fetch、navigator、requestAnimationFrame、window等同时用overrides让*.web.*文件额外获得env: { browser: true }Web 平台的浏览器环境变量。flat 版则将这套逻辑统一为globals.browser加 Expo 专属变量并把*.web.*的差异化处理留给你通过files: [*.web.*]段自行扩展。二者思路一致都是为了解决同一段代码在 iOS/Android/Web 三端全局环境不同带来的误报。深入原理三TypeScript 与 React 的解析策略TypeScript交给 tsc 的归 tscutils/typescript.js 对*.ts、*.tsx、*.d.ts启用typescript-eslint/parser并注册其规则插件其中几处刻意为之的关闭/接管很值得留意no-undef: off按 typescript-eslint 的官方建议TS 工程里未定义变量的检查应交还给编译器tsc 类型检查能覆盖包括类型在内的一切避免 ESLint 对类型语法误报no-unused-vars、no-redeclare、no-dupe-class-members、no-useless-constructor全部转交给typescript-eslint/*同名规则处理因为 TS 的语法形态如重载、接口声明合并会让原生规则误判no-useless-return: off源码注释解释得很清楚——它会与 TS 的穷尽分支检查冲突当返回类型允许return;走undefined时会出现Function lacks ending return statement的冲突typescript-eslint/no-require-imports开启但允许资源文件为了对齐 Metro 行为禁止用 CJSrequire引入代码模块同时用正则白名单放行图片、字体、媒体、json等静态资源扩展名如.png、.ttf、.mp4、.webp、.json等这正是 Expo 项目里const icon require(./icon.png)写法的合法性来源。React版本自动探测 Hooks 推荐集utils/react.js 打开jsx解析挂载react插件并继承plugin:react-hooks/recommended对 Hooks 依赖数组等给出最佳实践检查。它默认开启的规则全部围绕能确证是错误的写法展开且大多为warn级风格克制例如react/jsx-no-duplicate-props、react/jsx-no-undef这类确定性错误设为errorreact/no-direct-mutation-state、react/no-string-refs、react/no-deprecated、react/no-unknown-property、react/display-name等废弃/可疑写法设为warn特别地settings.react.version detect会让 react 插件自动探测项目安装的 React 版本以适配规则行为如新 JSX 转换下react/jsx-uses-react的实际必要性本仓库依赖中react: 19.2.3即可作为验证环境。core一组克制的基础正确性规则utils/core.js 提供语法基线ecmaVersion: 2022、sourceType: module、JSX 与隐式严格模式no-undef、use-isnan、valid-typeof、no-dupe-keys、no-duplicate-case、eqeqeq([warn,smart])、no-var: error等基础规则并挂载plugin:import/errors。这里还埋了一个对 RN 生态很关键的细节settings[import/ignore]中通过正则node_modules[\\/]?react-native忽略 react-native 相关包的解析——因为这些包的主入口是Flow 代码而非标准 JS直接解析会产生语法错误源码注释也点明了这一点。同时metro.config.js被单独赋予env: { node: true }*.d.ts中关闭import/order都属于消除平台误报的精细处理。项目内真实用例参考在 Expo 仓库内就能看到它的多种实践方式可作为你配置自己项目的活样板packages/eslint-config-expo/eslint.config.jseslint-config-expo自检自身使用的 flat 配置。它把expoConfigspread 进数组后叠加globals.node与globals.jest因为要 lint 自己的测试代码、eslint-plugin-prettier/recommended并把prettier/prettier调成warn还通过ignores排除了__tests__/fixtures/*中的故意违规样例。根目录及大量子包均使用eslint-config-expo例如 packages/expo/oxlint.config.mjs、packages/expo-image/package.json其eslintConfig段正是上文 legacy 用法等。测试目录tests中用真实文件验证行为baseline-*测试把不依赖具体规则的纯语法/平台兼容文件含web-native-*.js等平台化命名喂给配置做快照比对rules-*测试则针对fixtures/rule-*校验自定义规则的告警输出见 rules-flat-test.js其内部通过tests/tools 同时驱动 ESLint 8/9 两个版本执行 lint。如果你 fork 修改了该包运行pnpm --filter eslint-config-expo test即可跑这套快照回归。常见疑问速查我该用 flat 还是 legacy用 ESLint 9 及以上默认 flat用 ESLint 8 且既有.eslintrc体系则用 legacy。两者规则等价仓库同时对两个入口做发布与测试。它包含格式化和风格规则吗不含。它是基座配置风格规则prettier 等需自己叠加——官方仓库自检时也是手动追加eslint-plugin-prettier。我的项目没有 TypeScript还需要它吗需要。它通过overrides/files 按扩展名精确分流纯 JS/JSX 项目同样受益于平台扩展名识别、RN 全局变量与 expo 规则。想覆盖它开启的某个规则怎么办flat 模式下把带rules的新配置对象放在expoConfig之后即可legacy 模式下在rules字段直接覆盖同名规则。【免费下载链接】expoAn open-source framework for making universal native apps with React. Expo runs on Android, iOS, and the web.项目地址: https://gitcode.com/GitHub_Trending/ex/expo创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表