《vite技术揭秘、还原与实战》第7节--在svite中引入defineConfig类型辅助函数

前言

上一小节,我们发现直接引入defineConfig会导致程序报错,于是分析了产生报错的原因并查看了vite中的解决思路

本节,在svite中解决这个问题

好文推荐

源码获取

传送门

更新进度

公众号:更新至第17

博客:更新至第7

代码实现

结合上一节分析,我们知道问题出在buildBoundle函数中,并且我们已经知道了通过esbuild pluginonResolve钩子可以解决这个问题

如下,第一步我们需要对一些条件进行守卫:入口点本身、绝对路径、node内置模块

ts 复制代码
// packages\vite\src\node\config.ts
async function buildBoundle(fileName: string) {
  const result = await build({
    ...
    plugins:[{
      name: 'externalize-deps',
      setup(build) {
        build.onResolve({filter:/^[^.].*/},async ({path:id,importer,kind})=>{
            // id:导入的依赖地址,如import xxx from 'svite'语句中指的是svite
            // importer:当前正在处理的文件地址,如svite所在的文件地址为playground\config\svite.config.ts
            // kind:导入的类型,如entry-point表示导入入口点;entry-point表示导入依赖
            if (kind === "entry-point" || isAbsolute(id) || isBuiltin(id)) {
                return;
            }
            return {
                path:analizePathValue(id,importer,kind),
                external:true
            }
        })
      }
    }]
  });
  const { text } = result.outputFiles[0];
  return text;
}

当程序通过if守卫条件后,则说明命中了裸依赖,在我们的svite.config.ts文件中即指命中了svite。此时通过将钩子返回的对象的external设置为true从而将依赖从boundle中排除则能有效避免上一小节中我们遇到的报错问题:Dynamic require of "fs" is not supported

由于我们跳过了svite的处理,则最终代码里将无法找到defineConfig而引发报错,为了解决这个问题,我们要将导入的路径替换为绝对路径,这样node就能正确加载啦

因此我们的关键点就是去生成path的值来对引入模块路径做替换,即analizePathValue是如何实现的

ts 复制代码
function analizePathValue(id: string, importer: string, kind: string) {
  ...
}

想要实现这一点,我们需要从包的元数据中找相关的定义,即packages\vite\package.json中与模块引入相关的字段

json 复制代码
{
  "main": "./dist/node/index.js",
  "types": "./dist/node/index.d.ts",
  "exports": {
    ".": {
      "types": "./dist/node/index.d.ts",
      "import": "./dist/node/index.js"
    }
  }
}

vite中是自己去读取该json文件并对导出字段做比对的,且针对svite/xxx的形式也需要做额外的兼容处理。这里我们借助local-pkg来达到同样的目的

js 复制代码
pnpm i local-pkg

该包提供的resolveModule函数会自动帮我们完成路径的识别和转换工作,当然,我们要先判断对应的依赖包是否存在,当获取到路径之后,还需要通过node内置的pathToFileURL将其转换为URL路径

ts 复制代码
if (isPackageExists(id)) {
  const fileUrl = resolveModule(id);
  if (fileUrl) {
    return pathToFileURL(fileUrl).href;
  }
}

如果你是跟着笔者一起实现的话,当你运行的时候,你会得到如下的错误

txt 复制代码
Error [ERR_PACKAGE_PATH_NOT_EXPORTED]: No "exports" main defined in C:\Users\11574\Desktop\git\mini-vite\node_modules\svite\package.json

这是因为resolveModule本质上是cjs的导入方式,而我们一开始在创建项目时缺少了对require的支持,为因此,需要找到packages\vite\package.json文件的exports并增加如下代码

json 复制代码
{
  "exports": {
    ".": {
      ...
      "require":"./dist/node/index.js"
    }
  },
}

设置好后,再次启动,程序正常运行即可

总结

本小节,依据上一节的分析思路解决了svite中引入ts辅助函数的报错问题,其实就是在打包处理该配置文件时将引入排除就可以了

相关推荐
Emma歌小白14 小时前
Vite 和 Vue CLI 比较
vue.js·vite
Sahas101920 小时前
vite+vue2+elementui构建之 package.json
elementui·vue·vite
jserTang5 天前
前端构建工具漫谈:Webpack、Vite、Turbopack 与 Rspack 的终极对决
前端·webpack·vite
jaywangep6 天前
vite插件:提取项目中第三方域进行dns-prefetch预连接
性能优化·vite
wordbaby7 天前
加速 Web 应用:资源压缩详解与 Vite + Nginx 实践指南
前端·nginx·vite
huali7 天前
unplugin-https-reverse-proxy 2.0 发布:革新移动端调试体验
前端·开源·vite
sen_shan7 天前
Vue3+Vite+TypeScript+Element Plus开发-22.客制Table组件
vue.js·vue3·vite·element plus·按钮组件·表组件
是二牙7 天前
vue3+vite 多个环境配置
前端·vue3·vite
bnnnnnnnn10 天前
做了个 Vue3 上传大文件的项目,顺手搞懂了 OSS、Pinia 和断点续传
前端·javascript·vite
柚子81610 天前
用transform给vue加点功能
前端·vue.js·vite