那是一个温暖宜人的下午
,温暖的阳光
洒进办公室,微风轻轻吹拂,带来阵阵清新的空气
。小羽戴着耳机坐在办公桌前,耳机里传来轻柔的音乐
,伴随着键盘清脆的敲击声
,组成了一首独特的交响曲。桌上的咖啡杯
散发出淡淡的香气
,偶尔会抬起头,望向窗外,享受片刻的安宁
。
下午的时光似乎总是流逝得特别快。阳光逐渐西斜,金色的光线透过窗户洒在地板上,形成了一道道柔和的光影。看了一眼时间,嘿嘿,马上到干饭时间了,糖醋排骨
、龙井虾仁
、宫保鸡丁
、鱼香茄子
、清蒸鲈鱼
咱们马上就来大战三百回合【擦下口水】。
突然感觉到有人轻轻拍了拍的肩膀。摘下耳机,回过头去,只见同事站在他身后,说:"唉,你写的代码有bug!
"
嗯?您确定!!!
帅哥
写的代码怎么可能有bug,不可能,绝对不可能,就算有也不承认!【手动狗头】
说是这么说,但是有问题还是得解决的,对吧。
来到同事的工位前,同事指着屏幕中的一行代码,"你看,上次你引用了一个vite插件
后,我现在这样子引用less文件
,编译就报错了"。
大概的示意图如下:
唉,这是个什么神奇的报错?(因为alias的配置是正确的,可以看到ts资源引用是正常的)
又到了掐指一算的时候了,这必定是alias
的问题,用相对路径
一定可以解决。
果然没错,可以看到换成相对路径
是正常的。
ok,问题解决。
干饭的时间到,民以食为天,目标食堂,全速前进!
但是还是无法解释用alias引用less文件会报错的问题。
这到底是为啥啊???
带着疑惑
以及浑身的不得劲
回到家中,继续排查这个问题。
在前面的报错提示中,咱们可以看到错误来源是vite-plugin-react-css-module
这个npm包中的。
那就老方法,先找到这个npm包对应的github仓库是否有对应的issue?
emmm,issues
就两个,但是不是我们想要的。
居然没人遇到这个问题?
那就只能看下代码实现了,可以发现这个vite插件是引用了一个三方的babel插件,babel-plugin-react-css-modules
。
走,咱们移步到babel-plugin-react-css-modules
的仓库中,看看能不能找到什么线索
然后发现这个其实应该是属于babel-plugin-react-css-modules
这个库的bug,但是看作者17年的说法,并不打算对alias进行支持。
啊,这。。。。
wtf,这怎么搞,作者都不打算支持了。
嘿嘿,别着急,咱们继续往下看。
说不定就能找到答案呢【手动狗头】
看,后续有大佬给出答案,可以通过babel-plugin-module-resolver
这个plugin,给css-modules插件添加alias相关的支持。
emmm,但是有一个问题,你发现了嘛
就是如果直接在babel中使用babel-plugin-module-resolver
的话,则需要维护两份alias,这对于喜欢偷懒的程序员朋友来说就非常不友好啦,但这又不属于vite-plugin-react-css-module
这个包的bug。并且这个包好像有三年没更新了,看了一眼代码,感觉还挺简单的,于是决定借鉴一下vite-plugin-react-css-module
自己新搞一个包吧。
那咱们先来写一个最简版的vite plugin,运行起来后,就可以在控制台中看到咱们写的vite插件的log输出了,如下图
这里是一些vite自定义插件相关的参数,需要用到的时候看下就好
name:
插件的名称,用于在日志中标识插件。
enforce:
用于指定插件的执行顺序。可以是
"pre"
(在其他插件之前执行)或"post"
(在其他插件之后执行)。apply:
指定插件的应用场景,可以是
"build"
(仅在构建时使用)或"serve"
(仅在开发服务器时使用)。config:
用于修改 Vite 配置。接收当前的 Vite 配置和环境变量。
configResolved:
在配置解析完成后调用,接收解析后的 Vite 配置。
configureServer:
用于配置开发服务器。在开发服务器启动时调用,接收
server
实例作为参数。transformIndexHtml:
用于转换
index.html
文件。可以对 HTML 进行操作,如注入脚本或样式。resolveId:
用于自定义模块解析逻辑。接收待解析的模块 ID 和导入模块的来源。
load:
用于自定义加载模块内容。接收模块 ID,并返回模块的代码。
transform:
用于转换模块内容。接收模块代码和模块 ID,返回转换后的代码。
handleHotUpdate:
用于处理热更新事件。接收更新的模块和
server
实例,返回需要更新的模块集合。buildStart:
在构建开始时调用,可以进行一些准备工作。
buildEnd:
在构建结束时调用,可以进行一些清理工作。
generateBundle:
在生成 bundle 文件时调用,可以对生成的文件进行操作。
writeBundle:
在 bundle 文件写入磁盘时调用。
然后就是参考原版的插件(cjs),并将其改造为esm
版本的代码。
这是原版的代码,总共60行,还是比较简单的,咱们简单的分析一下,它做了哪些操作?
好的,那咱们还有一个问题,就是怎么引入babel-plugin-module-resolver
这个插件并动态配置alias呢?
这里比较简单,直接公布答案吧
babel-plugin-module-resolver
的引入和原来的css-module插件一样,在plugin中引入既可,而alias则可以先创建一个局部的变量,然后在config钩子中将alias相关参数赋值过去,最后到transform钩子中使用就好了
下面是全部的代码:
// ts-check
import { transformSync } from "@babel/core";
import babelPluginReactCssModules from "babel-plugin-react-css-modules";
import babelPluginModuleResolver from "babel-plugin-module-resolver";
enum EEnforce {
PRE = "pre",
POST = "post",
}
function viteReactStyleName(opt) {
const { ...options } = opt;
let _alias;
return {
name: "vite-react-stylename",
enforce: EEnforce.PRE,
config(confing) {
_alias = confing.resolve.alias;
},
transform(code, id) {
// 排除不处理的文件
if (!/.(t|j)sx?$/.test(id) || id.includes("node_modules")) {
return null;
}
if (!id.endsWith("x") && !code.includes("react")) {
return null;
}
// 需要使用的解析插件
const parserPlugins = ["jsx", "importMeta"];
if (/.tsx?$/.test(id)) {
parserPlugins.push("typescript", "decorators-legacy");
}
const isReasonReact = id.endsWith(".bs.js");
const result = transformSync(code, {
babelrc: false,
configFile: false,
filename: id,
parserOpts: {
sourceType: "module",
allowAwaitOutsideFunction: true,
plugins: parserPlugins,
},
plugins: [
[
babelPluginModuleResolver,
{
alias: _alias,
extensions: [".js", ".jsx", ".tsx", ".ts"],
},
],
[
babelPluginReactCssModules,
{
autoResolveMultipleImports: true,
exclude: "node_modules",
...options,
},
],
],
ast: !isReasonReact,
sourceMaps: true,
sourceFileName: id,
});
return {
code: result.code,
map: result.map,
};
},
};
}
export default viteReactStyleName;
ps:目前这块已经单独发布了npm包,想使用的小伙伴,直接通过pnpm i vite-react-stylename -D
进行安装,使用方式和原版的插件一样~
github地址:github.com/baizeteam/b…
npm地址:www.npmjs.com/package/vit…
此时,咱们将原vite-plugin-react-css-module
的引入路径改成咱们新vite插件的路径,就可以发现使用alias引入的方式也变得正常啦。这下子才是真的搞定收工!
本文差不多就到这里啦,如果看这篇文章后,感觉有收获的小伙伴们可以点赞
+收藏
哦~
如果想和小羽
交流技术可以加下wx,也欢迎小伙伴们来和小羽唠唠嗑
,嘿嘿~