Skip to content

Vite 插件

看下面的示例, index.vue文件默认名称文件名称 svg引入自动转换为组件

vue
<!-- views/text/index.vue -->
<script lang="ts" setup>
import demoSvg from '~/assets/svg/demo.svg?component'

if (import.meta.hot) {
  import.meta.hot.on('yang-code', (payload) => {
    console.log(payload)
  })
}
</script>

<template>
  <div>
    <demo-svg />
  </div>
</template>
<!-- views/text/index.vue -->
<script lang="ts" setup>
import demoSvg from '~/assets/svg/demo.svg?component'

if (import.meta.hot) {
  import.meta.hot.on('yang-code', (payload) => {
    console.log(payload)
  })
}
</script>

<template>
  <div>
    <demo-svg />
  </div>
</template>

Svg转换组件

通过正则匹配文件id 使用node:fs 读入文件内容 借助于@vue/compiler-sfc compileTemplate进行编译

ts
import { basename, dirname } from 'node:path'
import { readFileSync } from 'node:fs'
import { compileTemplate } from '@vue/compiler-sfc'
import type { Plugin, ViteDevServer } from 'vite'

export default function Yang(): Plugin {
  const virtualModuleId = 'virtual:yang-module'
  const resolvedVirtualModuleId = `\0${virtualModuleId}`
  let server: ViteDevServer
  return {
    name: 'yang-plugin',
    transform(code, id) {
      if (/\.svg(\?(component))/.test(id)) {
        const filepath = id.split('?')[0]
        try {
          const context = readFileSync(filepath, { encoding: 'utf-8' })
          const { code } = compileTemplate({
            id,
            source: context,
            filename: basename(id).split('.')[0],
            transformAssetUrls: false
          })

          return `${code}\nexport default { render: render }`
        }
        catch (error) {
          console.log(error)
        }
      }
    }
  }
}
import { basename, dirname } from 'node:path'
import { readFileSync } from 'node:fs'
import { compileTemplate } from '@vue/compiler-sfc'
import type { Plugin, ViteDevServer } from 'vite'

export default function Yang(): Plugin {
  const virtualModuleId = 'virtual:yang-module'
  const resolvedVirtualModuleId = `\0${virtualModuleId}`
  let server: ViteDevServer
  return {
    name: 'yang-plugin',
    transform(code, id) {
      if (/\.svg(\?(component))/.test(id)) {
        const filepath = id.split('?')[0]
        try {
          const context = readFileSync(filepath, { encoding: 'utf-8' })
          const { code } = compileTemplate({
            id,
            source: context,
            filename: basename(id).split('.')[0],
            transformAssetUrls: false
          })

          return `${code}\nexport default { render: render }`
        }
        catch (error) {
          console.log(error)
        }
      }
    }
  }
}

组件 name 自动生成

正则匹配文件id,通过正则匹配_name 进行替换操作

ts
import { MagicString } from '@vue/compiler-sfc'
import type { Plugin, ViteDevServer } from 'vite'

export default function Yang(): Plugin {
  const virtualModuleId = 'virtual:yang-module'
  const resolvedVirtualModuleId = `\0${virtualModuleId}`
  let server: ViteDevServer
  return {
    name: 'yang-plugin',
    transform(code, id) {
      if (/index.vue$/.test(id)) {
        const _dirname = dirname(id).split('/').at(-1)
        if (_dirname) {
          server.ws.send('yang-code', code)
          const s = new MagicString(code)
          s.replace(/(?<=__name: ")\w+/, _dirname)

          return {
            id,
            code: s.toString()
          }
        }
      }
    }
  }
}
import { MagicString } from '@vue/compiler-sfc'
import type { Plugin, ViteDevServer } from 'vite'

export default function Yang(): Plugin {
  const virtualModuleId = 'virtual:yang-module'
  const resolvedVirtualModuleId = `\0${virtualModuleId}`
  let server: ViteDevServer
  return {
    name: 'yang-plugin',
    transform(code, id) {
      if (/index.vue$/.test(id)) {
        const _dirname = dirname(id).split('/').at(-1)
        if (_dirname) {
          server.ws.send('yang-code', code)
          const s = new MagicString(code)
          s.replace(/(?<=__name: ")\w+/, _dirname)

          return {
            id,
            code: s.toString()
          }
        }
      }
    }
  }
}

类型提示

解决类型提示错误 import demoSvg from '~/assets/svg/demo.svg?component'

ts
// src/env.d.ts
declare module '*?component' {
  import type { DefineComponent } from 'vue'
  const component: DefineComponent<object, object, any>
  export default component
}
// src/env.d.ts
declare module '*?component' {
  import type { DefineComponent } from 'vue'
  const component: DefineComponent<object, object, any>
  export default component
}