实现一个更先进的 css module 开发工具

1,269 阅读3分钟

实现一个更先进的 css module 开发工具

截止目前,css module 仍被大多数开发者所使用,几乎零上手成本的使用方式收到大多数开发者的青睐。至今已经有与之匹配的生态和工具,本次所推荐的工具,能提供给 css module 开发者们更丝滑,更优雅的开发体验(免费)。

简介

工具形式为 vscode 插件,可在插件市场搜索 css-module-typed 安装使用

动机

vscode插件市场已经有了很多css module相关的插件,但是用起来总有一种差强人意的感觉,并不能完全满足我们的使用需求,例如:

  • 需要生成生成d.ts文件,对项目侵入性极大;
  • 不支持goToDefinition,鼠标hover 类名的时候只能看见类型,但是并不能跳转到对应的样式代码位置;
  • CSS Modules created by clinyong 插件虽然支持goToDefinition,但是也只支持了部分,例如: &.class {} 这种写法就不再被支持;

功能

基于上述动机,我们在新的插件中实现了以下功能:

  • 代码自动补全
  • Go to definition
  • less/scss 缩写后的类名识别
  • 不需要生成 d.ts 文件,保持磁盘干净整洁
  • 自动标记不存在的 class name

demo 演示

功能演示:

display-after.gif

类名不存在时,提示更符合开发的心智模型:

not-exist.png

安装

方式1:vscode 插件市场搜索 css-module-typedinstall 后,重启即可

css-module-install.png

方式2:访问 marketplace.visualstudio.com/items?itemN… ,点击 install 即可

原理

增强 typescript 语言服务

由于 typescript 语言服务并不能识别 css module 文件(后缀为 .css/.scss/.sass/.less )。

因此我们实现 typescript 语言服务器插件,从 css module 文件识别为 ts 文件

// 欺骗 typescript 语言服务器
languageServiceHost.getScriptKind = (fileName) => {
      if (!info.languageServiceHost.getScriptKind) {
        return ts.ScriptKind.Unknown;
      }
      if (isCSS(fileName)) {
        return ts.ScriptKind.TS;
      }
      return info.languageServiceHost.getScriptKind(fileName);
    };

同时当 typescript 语言服务器请求读取 css module 类型时,编译 css module 文件为 d.ts 格式的内容并返回。

// 提供编译后的 d.ts 内容
languageServiceHost.getScriptSnapshot = (fileName) => {
      if (isCSS(fileName)) {
        const snapshot = getDtsSnapshot(
          ts,
          processor,
          fileName,
          options,
          logger,
          compilerOptions,
          directory,
        );
        return snapshot;
      }
      return info.languageServiceHost.getScriptSnapshot(fileName);
    };

核心库改造

实际上,上述【增强 typescript 语言服务】实现在社区已经有对应实现 typescript-plugin-css-module ,但插件仍有许多未解决的问题。因此,我们针对核心库 typescript-plugin-css-module 进行了部分改造,包括:

  • 解决大型项目的性能瓶颈
  • 支持标记错误类名为"废弃"
  • vscode 插件支持
  • 更精确的 goToDefinition

更详细的原理可以看这里:vscode 如何支持 css-module 文件跳转到类名?

vscode 插件支持

幸运的是,vscode 允许插件提供 typescript 插件 ,在 package.json - contributes 中定义插件库即可

{
  "contributes": {
    "typescriptServerPlugins": [
      {
        "name": "typescript-styled-plugin"
      }
    ]
  }
}

typescript 插件的自定义配置将由 vscode 插件进行传递,由于一些时序问题,插件放弃了使用官方提供的 configurePlugin 方式注入 typescript 配置,而是在 vscode 插件被激活时,写入临时文件配置,让 typescrip 插件能更早的拿到用户自定义配置

总结

相比于使用 typescript-plugin-css-module,使用 vscode 插件的形式给项目的 css module 文件添加类型声明可以真正降低代码的侵入性,并且不需要再为每个项目都做一遍插件的安装和配置,有效地降低了工具的使用成本。

相比于社区类似的插件 Css Modules ,除了增强了【代码自动补全】和【goToDefinition】之外,还提供了【错误 className 标记】和【less/scss 缩写支持】,从 typescript 语言层面出发,满足更多的开发场景,给予更友好的开发体验。