ARTICLE DETAIL

资讯详情

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

VS Code 高效配置:彻底解决 node_modules 搜索刷屏与 JSX Emmet 失效

VS Code 高效配置:彻底解决 node_modules 搜索刷屏与 JSX Emmet 失效 你是不是也遇到过这种情况在 VS Code 里按 CtrlShiftF 全局搜索结果刷出来几千上万条 node_modules 里的文件真正想找的代码被淹没在海底或者在 .jsx 文件里想用 Emmet 快速敲一段结构结果 Tab 按下去毫无反应只能一个标签一个标签手打。这两个问题单个看都不大但每天都在消磨效率。我查了一下网上各种提问这类问题几乎每个月都有人在论坛上翻出来问回复里七嘴八舌什么方案都有有的让装插件有的让删 node_modules还有的让你全局改配置看得人头大。我自己从 VS Code 1.x 时代一路用到现在node_modules 搜索过滤和 JSX Emmet 配置这两件事都踩过不少坑配置完以后再也没为这种基础问题分过心。这篇文章不跟你讲那么多虚的直接给你一套能落地的配置方案和排查思路不管你是 React 党、Vue 3 JSX 党还是天天被依赖目录折磨的后端同学照着抄就行。1. 先搞清楚这两个问题烦在哪1.1 全量搜索 node_modules 为什么会这么烦人很多刚接触 VS Code 的人有一个误解以为“我把文件夹打开在资源管理器里不展开 node_modules搜索它就不会搜到里面的文件”。实际完全不是这么回事。VS Code 的搜索逻辑和资源管理器是两套体系。你在资源管理器里看到 node_modules 被折叠、被隐藏那只影响你“看”的时候的视觉体验搜索功能默认情况下是全目录扫的node_modules 里面的每一个 .js、.json、.d.ts 文件都会被索引进搜索结果里。一旦项目里的依赖多起来几十万文件是家常便饭结果就是搜索结果里充斥着 plugin、loader、babel runtime 之类的第三方源码真正关心的代码根本找不到。搜索过程变卡回车之后要等好几秒才出结果甚至直接无响应。CtrlShiftF 这个高频操作体验被彻底拖垮一天要反复忍受几十次。还有一个很隐蔽的点很多人之前被“files.exclude 能不能影响搜索”这个问题误导过。早期网上很多教程建议你把**/node_modules写进 files.exclude说这样搜索就不会带 node_modules 了。这个做法在功能上确实有效但有个副作用——它会把 node_modules 从资源管理器里也彻底隐藏掉。如果你偶尔还得手动打开依赖目录看一眼里面的结构就会觉得“文件怎么莫名其貌失踪了”特别容易引发疑惑。1.2 JSX 里 Emmet 不生效问题出在语言识别Emmet 这个功能大家都很熟写过 HTML 的人都知道输入div.containerulli*3然后按 Tab一秒生成一整套嵌套结构。但在 JSX/TSX 文件里这个老技能突然就失灵了。原因倒不难理解。VS Code 的 Emmet 是根据当前文件的语言模式来决定启用哪种语法规则的它默认只对 html、css、less、scss 这类传统前端文件启用。而 .jsx、.tsx 文件在 VS Code 里默认被识别成 javascriptreact、typescriptreact 语言Emmet 对这个语言并不认识自然不会主动给你展开缩写。另外还有一层历史包袱早期 JSX 语法和 HTML 有很多细微差别比如 HTML 里的 class 在 JSX 里必须写成 className标签属性用的是驼峰命名HTML 里可以裸写的 for 在 JSX 里要写成 htmlFor。如果粗鲁地把 Emmet 直接套到 JSX 上生成的代码有一半不能直接用开发者体验更差。所以官方默认干脆就不给 JSX 开 Emmet需要你自己在配置里明确告诉它“我就是要用”。搞清楚这两个问题的根源后面配置起来方向就不会错了。接下来分别拆解。2. 让搜索别再碰 node_modules配置逐层拆解2.1 核心配置项search.exclude 才是正主针对搜索场景VS Code 提供了一个专门的配置项叫做search.exclude。它和files.exclude是两条独立配置前者只影响搜索范围后者只影响资源管理器里的文件可见性。两者互不干扰。你需要做的就是在项目的.vscode/settings.json里加上类似下面这段配置{ search.exclude: { **/node_modules: true, **/dist: true, **/build: true, **/coverage: true, **/.git: true } }配置好以后再按 CtrlShiftF 搜索node_modules 里的文件就会被直接过滤掉搜索速度和结果质量立刻上一个台阶。dist、build、coverage 这些编译产物目录建议一并排除因为它们本质上都是机器生成的平时完全没有搜索需要。这里有个细节值得注意**/node_modules里的两个星号是 glob 通配符表示“递归匹配任意层级目录”也就是说不管 node_modules 嵌在项目里的哪个嵌套层级都能被匹配到。如果你只写/node_modules那只能排除项目根目录下的那一个在多包仓库monorepo场景下仍然会有漏网之鱼。所以**/这个前缀是必须带的这也是网上很多配置复制下来不生效的原因之一。2.2 同一个应用为什么 files.exclude 不顶用我见过太多了——把 node_modules 写进 files.exclude资源管理器里确实看不到了但一搜索照样全是依赖文件。很多人就在这个节点上卡住觉得 VS Code 是不是有 bug。实际上这是两个独立开关VS Code 的设计逻辑是files.exclude 负责文件夹树的显示过滤search.exclude 负责搜索文件的索引过滤。前者目录树里隐藏文件之后搜索范围并不会受到影响依旧会去扫真实的磁盘文件。所以如果你想彻底解决搜索刷屏问题需要专门配置 search.exclude或者在搜索时手动指定排除路径。当然files.exclude 也不是完全没有联动作用在特定版本里它会作为“默认搜索排除项”的兜底基础但依赖这个联动行为并不可靠。我的建议很简单两套都配各管各的。资源管理器里看不看得到是一回事搜索要不要搜又是另一回事。2.3 搜索框临时排除方案不想改配置时怎么操作有时候你不想动全局配置就想快速搜一次那可以用搜索框自带的“files to exclude”输入框。按 CtrlShiftF 打开搜索面板后在 excluded files 输入框里填入**/node_modules/**这时候搜索就会自动跳过所有 node_modules 目录效果和配置 search.exclude 一致。如果在 include 和 exclude 之间要同时控制还可以配合着写**/*.js !**/node_modules/**include 框里放想要包含的规则exclude 框里放要排除的规则两个输入框都支持 glob 多规则匹配用逗号或换行分隔。我自己的习惯是一次性搜索用输入框排除长期要用的排除项写进 settings.json。临时方案要的是快固定配置要的是稳定两者搭配用起来最顺手。2.4 多目录项目、团队协作时怎么处理如果你是在 monorepo 或者多包工程里开发情况会比单个项目复杂一点。根目录下的 node_modules 要排除各个子包里的 node_modules 也要排除**/node_modules已经能覆盖这个场景这一点倒不用额外担心。真正需要注意的是团队协作时配置放在哪。搜出来的结果只在你本地生效同事那边的 VS Code 该被 node_modules 刷屏还是刷屏因为你改的是用户级别的 settings.json。想让整个团队收益应该把配置写到项目根目录的.vscode/settings.json里提交到 Git这样所有人拉下代码之后配置就自动生效了。这个文件是跟着项目走的同一份配置不同人得到相同体验。如果你的项目还没有.vscode目录可以直接在根目录新建一个.vscode文件夹再在里面创建settings.json文件。VS Code 会在启动时自动加载这个目录下的配置不需要额外操作。2.5 顺带解决资源管理器也想隐藏 node_modules 怎么办搜索问题解决以后可能你还想在资源管理器侧边栏里把 node_modules 折叠掉毕竟几十个大写字母开头的目录堆在文件树里实在碍眼。这时候用 files.exclude{ files.exclude: { **/node_modules: true, **/.git: true, **/dist: true } }这个配置不影响搜索纯粹是视觉整理。如果你既想隐藏又想在搜索时跳过那就 files.exclude 和 search.exclude 一起上。这里有一个很多人忽略的小细节如果你发现配置之后资源管理器里隐藏了 node_modules但在打开文件时输入路径比如 CtrlP 里输入node_modules/...仍然能打开里面的文件这是正常的。files.exclude 只是从文件树里“藏起来”不是真正删除也不影响文件访问。不要因为这个再花时间去搜“为什么文件还在”它其实一直就在那儿。3. 激活 JSX 里的 EmmetincludeLanguages 的正确姿势3.1 Emmet 在 JSX 里的工作逻辑先做个最基本的科普Emmet 的“缩写展开”机制是把你输入的简短表达式比如ul.navli.item*3解析成一段结构化的 HTML 字符串。解析过程中它依赖一套专门针对 HTML 语法的规则包括标签名、属性名、嵌套关系、重复次数。到了 JSX 里这套解析逻辑表面上还能用因为 JSX 的标签结构长得和 HTML 非常像div就对应 JSX 里的div。但 JSX 又增加了很多 HTML 没有的规则最典型的就是表达式插值{}像{items.map(...)}里的大括号包裹的 JS 表达式Emmet 不知道该不该展开它也不知道怎么处理它。所以 VS Code 官方对“非 HTML 语言里是否自动展开 Emmet”持保守态度默认只给 html 语言开绿灯。不过官方留了一个后门emmet.includeLanguages配置项允许你手动把某种语言映射成 Emmet 支持的语法模式。把 javascriptreact 映射成 html就能让 JSX 文件里的 Emmet 生效。3.2 实测有效的完整配置直接给你我目前在用的配置React 和 Vue 3 JSX 都能覆盖{ emmet.includeLanguages: { javascript: javascriptreact, javascriptreact: html, typescript: typescriptreact, typescriptreact: html } }这段配置到底做了什么呢逐行解释一下javascript: javascriptreact让普通 .js 文件在 Emmet 场景下被当作 JSX 语法对待。这一步主要是为了兼容那些在 .js 里写 JSX 的老项目工厂模式常见于某些 React 脚手架配置。javascriptreact: html让 .jsx 文件里的 Emmet 使用 HTML 语法规则展开这是 React 项目里最核心的一条。typescript: typescriptreact让 .ts 文件里的 JSX 代码也能识别。typescriptreact: html让 .tsx 文件里的 Emmet 生效。配置完以后重启 VS Code 或者手动执行命令面板里的 Reload Window然后在 .jsx 文件里试一下div.container输入完按 Tab应该会立刻生成div classNamecontainer/div注意这里有个关键差异Emmet 解释 class 属性时会替换成 JSX 需要的 className。这就是为什么 emmet 官方在支持 JSX 时做了特殊处理否则生成的代码直接就是classcontainerReact 里会报 warningVue 3 JSX 里也不符合规范。3.3 触发姿势Tab 不生效时先检查这个很多人在配置完 includeLanguages 之后发现还是不能展开。这时候先别急着怀疑配置对不对多半是触发姿势的问题。Emmet 缩写展开的默认触发键是 Tab但 VS Code 默认的emmet.triggerExpansionOnTab是 false也就是说按 Tab 并不会直接触发展开。需要手动判断如果你输入div.container之后不按任何快捷键而是等它自己弹提示那大概率不会出现 Emmet 的展开建议。解决办法是把 Tab 触发打开{ emmet.triggerExpansionOnTab: true }设置好之后输入div.container然后直接按 Tab就能看到展开结果。如果还是不行在命令面板CtrlShiftP里输入Emmet: Expand Abbreviation手动执行一次。这个时候如果展开结果正常说明配置没问题纯粹是 Tab 触发没打开如果手动执行也报错或者没反应那问题可能出在 includeLanguages 映射上。还有一个容易被忽略的点Emmet 展开要求“光标后面没有其他内容”。比如你把光标放在字符中间两边都有字母Emmet 会默认这不是一个完整的缩写不会展开。先把光标移到行尾、或者让缩写前后都有空格试一下就会正常。3.4 React 外的变种Vue 3 里用 JSX 的经验讲完 React再说说 Vue 3。Vue 3 支持用 JSX 写组件常见的编辑器配置和 React 类似。但有一个需要注意的地方Vue 单文件组件.vue里的 template 区域VS Code 默认会交给 Vetur 或 Volar 扩展去处理你平时写 template 的时候模板语法识别为 htmlEmmet 默认是生效的但是 template 里的 JSX 写法需要额外覆盖。实际上如果你用的是 Volar 扩展并且项目里启用了 Vue 3 的 JSX 模式Volar 会扮演一个比较“霸道”的角色自己接管 .vue 文件的语法高亮和代码补全Emmet 在 .vue 文件的 script 段里的表现不一定受 includeLanguages 控制。我的建议是Vue 3 项目里如果主要写 .vue 文件就交给 Volar不需要折腾 includeLanguages只有在写独立的 .tsx/.jsx 文件时才需要这份配置。React 项目则直接按上面的配置来。3.5 其他顺手就能优化的 Emmet 设置IncludeLanguages 之外还有几个相关配置我习惯顺手一起设了避免以后又被某个细节卡住{ emmet.includeLanguages: { javascript: javascriptreact, javascriptreact: html, typescript: typescriptreact, typescriptreact: html }, emmet.triggerExpansionOnTab: true, emmet.showExpansionAbbreviation: always, emmet.syntaxProfiles: { javascriptreact: { inline_break: 2 } } }emmet.showExpansionAbbreviation控制是否总是显示缩写展开的预览提示设置成 always 可以在输入过程中直接看到预览。emmet.syntaxProfiles调整生成代码的具体输出格式比如属性换行长度等。不追求完美的话前三项配置已经够用了后面两项是锦上添花。4. 把两个问题一起收进 settings.json完整配置与排坑4.1 一份能直接复制使用的完整配置说了这么多直接给一份我目前在用的成品配置。新建一个项目或者打开现有项目在.vscode/settings.json里粘进去{ search.exclude: { **/node_modules: true, **/dist: true, **/build: true, **/coverage: true, **/.git: true }, files.exclude: { **/node_modules: true, **/.git: true }, emmet.includeLanguages: { javascript: javascriptreact, javascriptreact: html, typescript: typescriptreact, typescriptreact: html }, emmet.triggerExpansionOnTab: true, emmet.showExpansionAbbreviation: always }粘贴完成后保存再按 CtrlShiftF 搜索一个只在业务代码里出现的词比如组件名、函数名你会明显感觉到搜索结果干净了一大截。然后打开一个 .tsx 文件输入div.box按 Tab看看能不能一键展开。两项都通了说明配置生效了。如果你希望配置在所有项目里都生效而不是只作用于当前项目把这一段配置合并到用户级 settings.json 里命令面板里搜 Preferences: Open User Settings (JSON)打开的就是用户级配置。我个人的建议是node_modules 排除这种“谁都不想搜依赖目录”的规则放用户级Emmet 映射这种和具体语言栈相关的规则放项目级。原因在于用户级配置会影响到你所有项目万一某个项目里你故意想搜 node_modules比如排查某个老依赖的源码全局排除之后就搜不到了还得临时改配置比较麻烦。4.2 搜索问题常见排查速查用表格整理一下搜索相关的常见问题方便你对号入座现象原因处理方式搜索仍然包含 node_modules只配了 files.exclude没配 search.exclude补上 search.exclude两套分开配置搜索时 exclude 输入框填**/node_modules没作用glob 路径写法有误改成**/node_modules/**或者在 exclude 框里直接写!**/node_modules/**排除后搜索速度还是很慢有其他大目录没排除比如 .git、dist把 .git、dist、coverage 等一并加进 search.exclude团队其他人依然被 node_modules 刷屏配置写在本地用户级未同步把配置提交到项目.vscode/settings.json搜索不到某个源码文件了之前把源码目录误加进了 search.exclude检查 search.exclude 里是否包含**/src之类的路径移除4.3 Emmet 配置常见问题速查Emmet 相关的排查我也整理成表格节省你到处翻答案的时间现象原因处理方式JSX 文件里按 Tab 不展开includeLanguages 未配置配置javascriptreact: html配置了 includeLanguages 还是没反应triggerExpansionOnTab 未开启或光标不是位于缩写末尾开启 triggerExpansionOnTab或把光标移到末尾展开结果里是class而不是classNameEmmet 没识别出 JSX 语法走的是 HTML 规则检查 includeLanguages 是否正确映射到了 javascriptreact/typescriptreact打开 .vue 文件时 script 里 Emmet 不生效Volar/Vetur 接管了语法解析使用组件库模板或直接在 .tsx/.jsx 里写函数式组件大写标签或带 namespace 的标签如MyComponent无法展开Emmet 不支持自定义组件名的自动补全手动输入组件名或利用 Snippets 自行定义片段4.4 踩坑记录几个真实项目里的教训最后分享几个在真实项目里遇到的坑都是网上搜不到现成答案、只能自己一行行试出来的。第一个坑是 monorepo 项目里 search.exclude 的路径问题。某个仓库同时管理 Web 端、小程序端、服务端三个子项目其中一个小程序项目里有自己的miniprogram_npm依赖目录名字不叫 node_modules。一开始我只排除了**/node_modules结果搜索时那个小程序依赖目录照样刷屏排查了半天才发现是另外这个目录。后来的做法是直接把所有依赖类目录都写进 search.exclude包括**/miniprogram_npm、**/.pnpm-storepnpm 的全局存储、**/vendor这种常见第三方目录一劳永逸。第二个坑是 pnpm 项目。pnpm 的 node_modules 结构和 npm/yarn 完全不一样它是符号链接组织起来的看起来干干净净但搜索的时候照样会扫到 link 指向的真实文件导致结果里出现node_modules/.pnpm/...这种很诡异的路径。处理方式没有捷径还是在 search.exclude 里把**/node_modules加上另外**/.pnpm-store也建议排除不然会把你磁盘上所有项目的依赖全扫一遍搜索卡到怀疑人生。第三个坑比较隐蔽关于 TypeScript 项目的emmet.syntaxProfiles。我在某个 React TS 项目里配置了 inline_break 为 2结果 .tsx 文件里生成的代码每一行都特别长有点不符合团队 lint 规范。后来才知道 Emmet 的 profile 会影响属性换行策略和 prettier 的 printWidth 可能互相冲突。现在我的建议是除非明确知道自己在干什么否则不要改 syntaxProfiles默认输出交给格式化工具统一处理就好。4.5 关于这些配置的适用范围我上面写的 search.exclude 配置不仅对普通项目有效对任何基于 VS Code 的远程开发场景比如 Remote-SSH、容器开发同样有效因为配置本身只影响编辑器行为不依赖具体的项目目录结构。Emmet 的 includeLanguages 配置则只影响编辑器内的展开功能不影响 ESLint、Prettier、TS 编译器等任何工具链不用担心配置完以后项目构建出错。最后再分享一个使用习惯上的小建议node_modules 过滤配置完成之后通常就不再需要主动去看那些目录里面的文件了真要看的时候直接用 CtrlP 输入路径跳转不必在资源管理器里一层层展开。JSX Emmet 配置完以后写组件模板的速度肉眼可见地提升那种“拍一下 Tab 就生成一整套结构”的爽快感用过一次就回不去了。这两个问题看着小但优化完之后的体验差异真的只有每天坐在编辑器前的人才能体会得到。
返回列表