JetBrains / svg-sprite-loader

Webpack loader for creating SVG sprites.
MIT License
2.01k stars 272 forks source link

How to use svg-sprite-loader with vite #434

Open llushikang opened 3 years ago

llushikang commented 3 years ago

I am using vite but vite does not seem to have webpack.

Lstmxx commented 3 years ago

by myself, i write a vite plugin to do it

https://vitejs.dev/guide/api-plugin.html

ceater ts file and write

import { Plugin } from 'vite'
import { readFileSync, readdirSync } from 'fs'

let idPerfix = ''
const svgTitle = /<svg([^>+].*?)>/
const clearHeightWidth = /(width|height)="([^>+].*?)"/g

const hasViewBox = /(viewBox="[^>+].*?")/g

const clearReturn = /(\r)|(\n)/g

function findSvgFile(dir): string[] {
  const svgRes = []
  const dirents = readdirSync(dir, {
    withFileTypes: true
  })
  for (const dirent of dirents) {
    if (dirent.isDirectory()) {
      svgRes.push(...findSvgFile(dir + dirent.name + '/'))
    } else {
      const svg = readFileSync(dir + dirent.name)
        .toString()
        .replace(clearReturn, '')
        .replace(svgTitle, ($1, $2) => {
          // console.log(++i)
          // console.log(dirent.name)
          let width = 0
          let height = 0
          let content = $2.replace(
            clearHeightWidth,
            (s1, s2, s3) => {
              if (s2 === 'width') {
                width = s3
              } else if (s2 === 'height') {
                height = s3
              }
              return ''
            }
          )
          if (!hasViewBox.test($2)) {
            content += `viewBox="0 0 ${width} ${height}"`
          }
          return `<symbol id="${idPerfix}-${dirent.name.replace(
            '.svg',
            ''
          )}" ${content}>`
        })
        .replace('</svg>', '</symbol>')
      svgRes.push(svg)
    }
  }
  return svgRes
}

export const svgBuilder = (
  path: string,
  perfix = 'icon'
): Plugin => {
  if (path === '') return
  idPerfix = perfix
  const res = findSvgFile(path)
  // console.log(res.length)
  // const res = []
  return {
    name: 'svg-transform',
    transformIndexHtml(html): string {
      return html.replace(
        '<body>',
        `
          <body>
            <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" style="position: absolute; width: 0; height: 0">
              ${res.join('')}
            </svg>
        `
      )
    }
  }
}

import this file in vite.config and add it in the plugin array

...
import { svgBuilder } from './build/svg/svgBuilder'
...
export default (
  mode: 'development' | 'production'
): UserConfig => {
  // const env = loadEnv(mode, root)
  return {
    plugins: [
      ...
      svgBuilder('./src/icons/svg/')],
  }
}
llushikang commented 3 years ago

多谢大佬!

lc11235 commented 3 years ago

多谢

Cleam commented 3 years ago

There is a plugin vite-plugin-svg-icons - Fast creating SVG sprites.

Tyh2001 commented 2 years ago

@Lstmxx svg 可以正常展示了,但是有乱码 f322ca81fb028cb6af7e052dd28e8d1

Lstmxx commented 2 years ago

@Lstmxx svg 可以正常展示了,但是有乱码 f322ca81fb028cb6af7e052dd28e8d1 问题已经解决,如果有遇到相同情况的朋友可以查看这个 https://github.com/Tyh2001/the-bug-svgBuilder/pull/1

Lstmxx commented 2 years ago

by myself, i write a vite plugin to do it

https://vitejs.dev/guide/api-plugin.html

ceater ts file and write

import { Plugin } from 'vite'
import { readFileSync, readdirSync } from 'fs'

let idPerfix = ''
const svgTitle = /<svg([^>+].*?)>/
const clearHeightWidth = /(width|height)="([^>+].*?)"/g

const hasViewBox = /(viewBox="[^>+].*?")/g

const clearReturn = /(\r)|(\n)/g

function findSvgFile(dir): string[] {
  const svgRes = []
  const dirents = readdirSync(dir, {
    withFileTypes: true
  })
  for (const dirent of dirents) {
    if (dirent.isDirectory()) {
      svgRes.push(...findSvgFile(dir + dirent.name + '/'))
    } else {
      const svg = readFileSync(dir + dirent.name)
        .toString()
        .replace(clearReturn, '')
        .replace(svgTitle, ($1, $2) => {
          // console.log(++i)
          // console.log(dirent.name)
          let width = 0
          let height = 0
          let content = $2.replace(
            clearHeightWidth,
            (s1, s2, s3) => {
              if (s2 === 'width') {
                width = s3
              } else if (s2 === 'height') {
                height = s3
              }
              return ''
            }
          )
          if (!hasViewBox.test($2)) {
            content += `viewBox="0 0 ${width} ${height}"`
          }
          return `<symbol id="${idPerfix}-${dirent.name.replace(
            '.svg',
            ''
          )}" ${content}>`
        })
        .replace('</svg>', '</symbol>')
      svgRes.push(svg)
    }
  }
  return svgRes
}

export const svgBuilder = (
  path: string,
  perfix = 'icon'
): Plugin => {
  if (path === '') return
  idPerfix = perfix
  const res = findSvgFile(path)
  // console.log(res.length)
  // const res = []
  return {
    name: 'svg-transform',
    transformIndexHtml(html): string {
      return html.replace(
        '<body>',
        `
          <body>
            <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" style="position: absolute; width: 0; height: 0">
              ${res.join('')}
            </svg>
        `
      )
    }
  }
}

import this file in vite.config and add it in the plugin array

...
import { svgBuilder } from './build/svg/svgBuilder'
...
export default (
  mode: 'development' | 'production'
): UserConfig => {
  // const env = loadEnv(mode, root)
  return {
    plugins: [
      ...
      svgBuilder('./src/icons/svg/')],
  }
}

I refactor the code and publish to https://github.com/Lstmxx/vite-svg-plugin. If you are interested, you can check the code.

koskinpark commented 1 year ago

how to use this plugin with vite with extract mode ?

StagnantIce commented 1 year ago

I found this https://github.com/StagnantIce/sveltekit_svg_sprite

wxmac commented 11 months ago

https://www.npmjs.com/package/rollup-plugin-svg-sprites 搭配vite这个可以用,但是收藏比较少,直接在vite.config.ts中


import { basename } from 'path';

plugins: [
      vue({
      reactivityTransform: true,
      }),
      // svg
      svgSprites({
        exclude: ['node_modules/**'],
        symbolId(path, query) {
        const fileName = basename(path).replace('.svg', '');
        return `icon-${fileName}`;
        },
      }),
]