(四)vite 项目配置:vite 插件

1,158 阅读2分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第9天,点击查看活动详情

2.5 vite 插件

2.5.1 EJS 标签

vite-plugin-html 是一个针对 index.html,提供压缩和基于 ejs 模板功能的 vite 插件。通过搭配 .env 文件,可以在开发或构建项目时,对 index.html 注入动态数据,例如替换网站标题。

安装

pnpm install --save-dev vite-plugin-html

vite.config.js 添加如下配置。VITE_GLOB_APP_TITLE 在全局环境变量中配置。

import { createHtmlPlugin } from 'vite-plugin-html'

...

    plugins: [
      createHtmlPlugin({
        minify: isBuild,
        inject: {
          data: {
            title: VITE_GLOB_APP_TITLE,
          },
          // 将 app.js 文件注入到模板html中
          tags: isBuild
            ? [
                {
                  tag: 'script',
                  attrs: {
                    src: '<path/app.js>',
                  },
                },
              ]
            : [],
        },
      }),
    ],
    
...
   

index.html文件中添加代码, 就可以动态的注入网站标题啦:

<title><%= title %></title>

tags 选项,可以向 html 文件中注入一些 js 文件。

2.5.2 Tsx 支持

@vitejs/plugin-vue-jsx 提供了 tsx 支持,为我们在模板文件中写 tsx 代码提供了可能。

安装依赖:

pnpm install --save-dev @vitejs/plugin-vue-jsx

vite.config.js 中添加配置

...
plugins: [
      vueJsx(),
 ],
 ...

2.5.3 配置自定义 svg

vite-plugin-svg-icon 用于生成 svg 雪碧图,方便在项目中使用 .svg 文件。 按照文档配置好后,搭配阿里巴巴矢量图标库使用,只需把下载好的 svg 文件丢到指定目录,然后就可以项目中愉快的使用了。

安装依赖:

npm i vite-plugin-svg-icons -D

vite.config.ts 文件中做如下配置:

import path from 'path';
import { createSvgIconsPlugin } from 'vite-plugin-svg-icons'; // 版本不同引入方式不同
export default defineConfig({
  ...
  plugins: [
    ...
    createSvgIconsPlugin({
      // 指定需要缓存的图标文件夹
      iconDirs: [path.resolve(process.cwd(), 'src/assets/icons')],
      // 指定symbolId格式
      symbolId: 'icon-[dir]-[name]'
    })
  ]
});

创建文件夹,并将svg 文件放到此处,如图:

image-20220611181602504.png

components中创建 SvgIcon.vue :

<template>
  <svg :style="getStyle" aria-hidden="true" :class="[$attrs.class]" class="insudio-svg-icon">
    <use :href="symbolId" />
  </svg>
</template>

<script lang="ts">
  import type { CSSProperties } from 'vue'
  import { defineComponent, computed } from 'vue'

  export default defineComponent({
    name: 'SvgIcon',
    props: {
      prefix: {
        type: String,
        default: 'icon',
      },
      name: {
        type: String,
        required: true,
      },
      size: {
        type: [Number, String],
        default: 16,
      },
    },
    setup(props) {
      const symbolId = computed(() => `#${props.prefix}-${props.name}`)
      const getStyle = computed((): CSSProperties => {
        const { size } = props
        let s = `${size}`
        s = `${s.replace('px', '')}px`
        return {
          width: s,
          height: s,
        }
      })
      return { symbolId, getStyle }
    },
  })
</script>
<style>
  .insudio-svg-icon {
    display: inline-block;
    overflow: hidden;
    vertical-align: -0.2em;
    fill: currentColor;
  }
</style>

main.ts 引入:

// 注册所有图标
import 'virtual:svg-icons-register';  // 引入注册脚本
import SvgIcon from '@/components/SvgIcon.vue';
app.component('SvgIcon', SvgIcon);

使用:

// 自定义的svg图标
<svg-icon name="iconName" size="24"></svg-icon>

2.5.4 配置使用 windicss

安装依赖:

pnpm install vite-plugin-windicss -D

vite.config.ts 文件中做如下配置:

import windiCSS from 'vite-plugin-windicss'

export default defineConfig({
  ...
  plugins: [
    ...
    windiCSS(),
  ]
});

在根目录创建 windi.config.ts

import { defineConfig } from 'vite-plugin-windicss'

export default defineConfig({
  darkMode: 'class',
  plugins: [createEnterPlugin()],
  preflight: false,
  theme: {
    extend: {
      zIndex: {
        '-1': '-1',
      },

      screens: {
        sm: '576px',
        md: '768px',
        lg: '992px',
        xl: '1200px',
        '2xl': '1600px',
      },
    },
  },
})

/**
 * Used for animation when the element is displayed.
 * @param maxOutput The larger the maxOutput output, the larger the generated css volume.
 */
function createEnterPlugin(maxOutput = 6) {
  const createCss = (index: number, d = 'x') => {
    const upd = d.toUpperCase()
    return {
      [`*> .enter-${d}:nth-child(${index})`]: {
        transform: `translate${upd}(50px)`,
      },
      [`*> .-enter-${d}:nth-child(${index})`]: {
        transform: `translate${upd}(-50px)`,
      },
      [`* > .enter-${d}:nth-child(${index}),* > .-enter-${d}:nth-child(${index})`]: {
        'z-index': `${10 - index}`,
        opacity: '0',
        animation: `enter-${d}-animation 0.4s ease-in-out 0.3s`,
        'animation-fill-mode': 'forwards',
        'animation-delay': `${(index * 1) / 10}s`,
      },
    }
  }
  const handler = ({ addBase }) => {
    const addRawCss = {}
    for (let index = 1; index < maxOutput; index++) {
      Object.assign(addRawCss, {
        ...createCss(index, 'x'),
        ...createCss(index, 'y'),
      })
    }
    addBase({
      ...addRawCss,
      [`@keyframes enter-x-animation`]: {
        to: {
          opacity: '1',
          transform: 'translateX(0)',
        },
      },
      [`@keyframes enter-y-animation`]: {
        to: {
          opacity: '1',
          transform: 'translateY(0)',
        },
      },
      // h1: { fontSize: '2rem' },
      // h2: { fontSize: '1.5rem' },
      // h3: { fontSize: '1.17rem' },
    })
  }
  return { handler }
}