前言
问题起因是因为项目需要引入服务器端的网络图片
而在编写配置时发现,Vite并不支持排除指定前缀的资源
唯一可以排外的只有 Rollup 的 external
选项可以排除外部依赖,但他只能排除外部依赖,不支持指定路径资源或指定前缀的资源,这就。。。。。
解决方法
后续通过阅读 Vite 官方配置选项发现这么一段话,官方说:可以通过插件自定义实现资源解析,于是就。。。
Vite 配置项
插件开发
Vite 使用 Rollup 插件 编译和解析模块,所以本文也是用Rollup插件,下面是插件源代码:
/**
* 忽略指定路径插件
* @param options
* @returns
*/
const ignorePathPlugin = (options: { paths: string[] }) => {
const PLUGIN_ID = "\0ignore-path",
PLUGIN_NAME = "ignore-path";
return {
name: PLUGIN_NAME,
resolveId(source: string) {
if (
options.paths.find((ignorePath) =>
picomatch(ignorePath)(source),
)
) {
return {
id: `${PLUGIN_ID}_${source}`,
meta: {
url: source,
},
};
}
return null;
},
load(id: string): string | null {
if (id.startsWith(PLUGIN_ID)) {
const info = this.getModuleInfo(id);
return `export default "${info.meta.url}";`;
}
return null;
},
};
};
插件使用方法如下:通过配置插件 的paths属性设置需要忽略的路径,由于插件使用了picomatch
依赖,所以支持正则、glob语法
export default defineConfig(({ mode }) => {
return {
plugins: [
ignorePathPlugin({
paths: ['/ignore-path/**/*'],
}),
],
};
});
实现原理
插件通过配置Rollup插件的resolveId
、load
构建钩子,忽略匹配资源
resolveId
该钩子函数,通过返回PartialResolvedId
对象或者重构后的资源导入路径,实现对模块的解析和重定义
本文通过返回PartialResolvedId
对象,实现忽略匹配资源,例如:
resolveId(source: string) {
//判断导入资源路径是否是需要忽略的地址
if (
options.paths.find((ignorePath) =>
picomatch(ignorePath)(source),
)
) {
//重构模块的id和meta信息,对资源进行标记
return {
id: `${PLUGIN_ID}_${source}`,
meta: {
url: source,
},
};
}
//如果不是需要忽略的资源,返回null,交给其他插件处理
return null;
},
具体原理可以查看官网文档和通过inspect插件
load
该钩子函数,通过传入导入资源的id,解析对应资源
本文插件在钩子函数内通过this.getModuleInfo(id)
方法获取resolveld
方法的返回值,然后获取meta
属性中的url
,实现对资源的解析,如:
load(id: string): string | null {
//判断模块的id是否是插件标记的id
if (id.startsWith(PLUGIN_ID)) {
//通过this.getModuleInfo(id)内置函数,获取模块信息
const info = this.getModuleInfo(id);
//返回解析后的模块源码,rollup通过返回的源码信息,解析和转换模块
return `export default "${info.meta.url}";`;
}
//如果不是,返回null,交给其他插件处理
return null;
},
注意
PLUGIN_ID
值前必须加上\0
,这样是为了防止其他插件转化和修改插件处理的结果,避免插件不生效问题- 因为插件功能单一,所以建议开发者使用
虚拟模块
的方式编写插件,避免资源浪费 官方文档