vite 插件编写及断点调试
jsonz1993 opened this issue · comments
背景
前段时间在改造旧项目的时候,发现vite不支持自定义css-module的匹配,只支持默认的 .module.css
的后缀名。关于这个问题,在 github issues 已经有好多个讨论,support custom css modules suffix ,Configure files to be processed as css-modules ,Support CSS Module configurable。
这个问题其实社区也有解决的插件,比如 vite-plugin-transform-css-modules ,但是这个插件是利用babel来处理,可能会有点重(this one uses babel for parsing so it may be a bit heavy),而且更关键的一点是,vite内部就有css plugin用于处理这些包括css module等的css处理,我们外部又重新写了一个插件去处理css module,让人觉得很别扭。
如果是从vite内部去处理,那么这个问题就变得很简单,无非是在vite加多一个配置,从 .module.css
变成用配置来获取是否需要 css module 处理。于是我火速提了一个 PR feat(css): support custom regexp of css modules 改动的代码量也很少,只是加多了 一个配置判断。
// 核心改动
function isCssModule(
modulesOptions: CSSOptions['modules'],
id: string
): boolean {
if (modulesOptions && modulesOptions.isCssModule) {
const { isCssModule } = modulesOptions
if (typeof isCssModule === 'function') {
return isCssModule(id)
} else if (
typeof isCssModule === 'string' ||
isCssModule instanceof RegExp
) {
const regexp = new RegExp(isCssModule)
return regexp.test(id)
}
}
return modulesOptions !== false && cssModuleRE.test(id)
}
不过这个pr最终没有被通过,因为官方觉得增加一个选项会导致多很多文档和维护的工作量。而且认为这种事情要么你遵循官方的 .module
后缀,要么你写个插件去处理。
于是乎我把目光转向用插件去让内置的 css plugin 处理,而不是自己再实现 css module 的编译。
开发与调试
在编写插件之前,我们先要处理开发环境,至少能在运行时打断点,方便开发与调试。
1. git clone https://github.com/vitejs/vite
2. pnpm i
3. cd packages/vite && pnpm run dev
4. vsc 新建 launch.json
5. 开始断点调试代码
// launch.json
{
// 使用 IntelliSense 了解相关属性。
// 悬停以查看现有属性的描述。
// 欲了解更多信息,请访问: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"type": "pwa-node",
"request": "launch",
"name": "cli",
"skipFiles": [
"<node_internals>/**"
],
// 传给vite 的参数
"args": ["--config", "yourDemoPath/vite.config.ts", "--debug"],
"program": "${workspaceFolder}/packages/vite/src/node/cli.ts",
"cwd": "yourDemoPath",
"sourceMaps": true,
"outFiles": [
"${workspaceFolder}/packages/vite/dist/**/*.js",
"!**/node_modules/**"
],
}
]
}
Vite 的插件和其他构件的插件基本一致,都是提供一些 hook ,然后在 hook API 中处理对应的逻辑,实现的思路就很简单了。
我这里的思路是:
首先,插件设置 enforce: pre ,这样能更快执行,因为有一些hook是 hookFirst(first non-null result is returned),比如我们要用到的 resolveId。
在 resolveId Hook,把我们要处理成 css module 的文件,返回成 xxx.module.ext
的形式,比如 basic.less
=> basic.module.less
。这样当 vite/css plugin 处理时就会以为文件名是 .module.less
,进而进行 css module 的处理。
最后因为我们这个 basic.module.less
实际是不存在的,所以需要在 load 中,如果访问的是我们虚构出来的文件,那么我们需要去读取真实的文件返回回去, fs.readFile('basic.less', 'utf-8')
。
具体代码实现可见 https://github.com/jsonz1993/vite-plugin-load-css-module