Vite插件:vite-aliases插件原理解析

210 阅读3分钟

背景

我们在使用vite搭建项目的时候,需要引入部分资源文件,我们如果通过相对路径../的形式来导入不同模块下的文件,这样就会存在很繁琐的问题。此时呢,vite提供了一个配置项resolve.alias来设置路径别名。

import { defineConfig } from 'vite';
import vue from '@vitejs/plugin-vue';
import ViteAlias from './src/plugins/ViteAlias';

// https://vite.dev/config/
export default defineConfig({
  plugins: [vue(), ViteAlias()],
  resolve: {
    alias: {
      '@': path.resolve(process.cwd(), './src'),
    },
  },
});

我们一般通过resolve.alias来进行配置,当然我们也可以直接使用第三方插件vite-aliases来自动实现。

vite-aliases用法

首先安装一下 pnpm i vite-aliases ,然后在vite.config.js文件中使用该插件即可,其他配置项都是默认的即可。

import { defineConfig } from 'vite';
import vue from '@vitejs/plugin-vue';
// import ViteAlias from './src/plugins/ViteAlias';
import { ViteAliases } from 'vite-aliases';

// https://vite.dev/config/
export default defineConfig({
  plugins: [vue(), ViteAliases()],
});

这样就直接完成了 别名插件的导入了,然后在项目中只要是src文件下的文件夹都可以通过@/xxx来进行识别啦。

插件原理解析

这个插件的原理其实比较简单的,就是识别当前项目src文件夹下的文件夹,然后配置一个配置项,通过插件的形式供vite源码读取并合并最终的config配置项。

在写插件过程中,需要注意vite的插件也是像vue3一样具备生命周期的,在不同的阶段提供不同的钩子函数。(插件 API | Vite 官方中文文档),为完成本节的目的,我们使用了config钩子函数进行插件的编写。

config钩子函数 是在vite处理vite.config.js文件之前进行的,这个函数返回一个对象(部分配置内容),而vite.config.js返回的也是部分内容,在vite中会将两部分内容合并然后进行处理。这个钩子函数中的config参数是vite.config.js中的内容。

// 插件都是函数哈,类似于express/koa中的中间件
// config参数:(config: UserConfig, env: { mode: string, command: string }) => UserConfig | null | void

//用法一 返回部分配置(推荐) 
const partialConfigPlugin = () => (
    {   name: 'return-partial', 
        config: () => ({ resolve: { alias: { foo: 'bar' } } }) 
    }
)

// 用法二 直接改变配置(应仅在合并不起作用时使用) 
const mutateConfigPlugin = () => (
{ 
    name: 'mutate-config', 
    config(config, { command }) { 
        if (command === 'build') { 
            config.root = 'foo' 
        } 
    } 
})

在了解了上述内容之后我们可以编写一个类似于vite-aliases的插件啦

插件复现

import fs from 'fs';
import path from 'path';

export default function ViteAlias({ aliasKey = '@', rootPath = './src' } = {}) {
  return {
    name: 'vite-alias',
    config: (config, env) => {
      console.log(config, env);
      if (env.mode === 'development') {
        const alias = {
          [aliasKey]: path.resolve(process.cwd(), rootPath),
        };
        const dirs = fs.readdirSync(alias[aliasKey]);
        dirs.forEach(dir => {
          const fileStats = fs.statSync(
            path.resolve(process.cwd(), `./src/${dir}`)
          );
          if (fileStats.isDirectory()) {
            const key = `${aliasKey}/${dir}`;
            alias[key] = path.resolve(process.cwd(), `./src/${dir}`);
          }
        });
        return {
          resolve: {
            alias,
          },
        };
      }
    },
  };
}

完成之后我们需要在vite.config.js文件中去使用该插件。核心原理就是读取文件路径然后替换,最终返回resolve.alias内容,然后vite会将插件返回的内容和配置的vite.config.js内容合并 然后进行接下来的其他处理。插件返回的配置项通常会覆盖 vite.config.js 中的相同配置项。

知识点总结

  • fs模块:
    • readdirSync函数:同步读取文件夹下得内容文件内容
    • statSync函数:读取当前文件的源信息(文件创建的时候就自带的)
  • path模块:
  • process.cwd():返回当前执行进程的目录,在写第三方插件的时候推荐用这个路径。
  • config函数:用于重写vite.config.js中的配置信息的一个钩子函数。