《从零开始学习Vite》 第三章:静态资源处理

🍎 系列文章

在系列中,将从零学习Vite,系统梳理 Vite 本身的知识,也包括 Vite 底层所使用的 Esbuild、Rollup 双引擎、Babel 编译工具链、模块规范标准等等构建生态。

《从零开始学习Vite》 第一章:搭建前端项目

《从零开始学习Vite》 第二章:接入 CSS 工程化方案

《从零开始学习Vite》 第三章:静态资源处理

《从零开始学习Vite》第四章:自动化代码规范工具的使用

前言

静态资源处理是前端工程化经常遇到的问题,在传统的 Webpack 中,需要通过 image-loader file-loader等来加载处理:比如图片、视频、字体类文件等静态资源。而 Vite 对静态资源(除了svg)是开箱即用的,我们将从如何加载静态资源如何在生产环境中对静态资源进行优化来学习 Vite 怎么开箱即用的。

加载静态资源

图片加载

图片是最常用的静态资源之一,包括png、jpeg、webp、avif、git、svg等

路径别名的配置

Vite允许开发者通过配置路径别名来简化模块引用时的路径书写,常见的别名符号包括@#$等。在vite.config.js中通过resolve.alias配置项设置别名。

// vite.config.ts
import path from 'path';
{
    resolve: {
        //别名配置
        alias: {
            '@assets':path.join(__dirname, 'src/assets')
        }
    }
}

这样 Vite 在遇到@assets路径的时候,会自动定位至根目录下的src/assets目录。alias 别名配置不仅在 JavaScriptimport 语句中生效,在 CSS 代码的 @importurl 导入语句中也同样生效。

svg 加载

我们通常将 svg 封装成一个组件来引入,这样可以很方便地修改 svg 的各种属性了。svg 组件加载在不同的前端框架中的实现不太相同,我们需要使用对应的插件:

我们搭建的是 React 项目,所以我们以安装 vite-plugin-svgr 为例:

pnpm add -D vite-plugin-svgr

然后需要在 vite 配置文件添加这个插件:

// vite.config.ts
import svgr from'vite-plugin-svgr';
{
    plugins: [
        //其它插件省略
        svgr()
     ]
}

随后注意要在tsconfig.json添加如下配置,否则会有类型错误:

{
    "compilerOptions":{
        //省略其它配置
         "types": ["vite-plugin-svgr/client"]
     }
}

接下来让我们在项目中使用 svg 组件,引入的时候注意加上?react后缀:

import ReactLogo from '@assets/react.svg?react';

<ReactLogo />

打开浏览器,可以看到 svg 已经成功渲染:

image.png

JSON 加载

Vite 内置了对于JSON 文件的解析,底层使用@rollup/pluginutilsdataToEsm方法将 JSON 对象转换为一个包含各种具名导出的 ES 模块,使用如下:

import { version } from '../package.json'; 

<div>version: { version }</div>

image.png

Web Worker 加载

我们新建 components/WebWorker/example.ts

const workerFun = () => {
    let count = 0;
    setInterval(() => {
        // 向主线程传值
        postMessage(++count);
    }, 3000);
};

workerFun();

然后在 WebWorker 组件中引入,引入的时候注意加上 ?worker 后缀,也就是告诉 Vite 这是一个 Web Worker 脚本文件:

import Worker from'./components/WebWorker/example.ts?worker';
// 初始化Worker实例
const worker = new Worker();
// 主线程监听worker的信息
worker.addEventListener('message', (e) => {
    console.log(e);
});

在浏览器的控制面板,可以看到 Worker 每3秒向主线程传递信息:

image.png

Vite 提供了许多静态资源格式的内置支持,这里就不一一列举了,可以自行查看 静态资源处理 | Vite 官方中文文档 (vitejs.dev) Vite 除了内置支持的格式外,如果你的项目中还存在其它格式的静态资源,你可以通过 assetsInclude 配置让 Vite 来支持加载:

// vite.config.ts
{ assetsInclude: ['.gltf'] }

生产环境处理

在生产环境下,我们将对自定义部署域名、base64、图片压缩、svg雪碧图等问题进行探讨和实践

自定义部署域名

在 Vite 中我们可以自动化的来实现地址的替换,只需要在配置文件中指定base参数即可:

// vite.config.ts
// 是否为生产环境,在生产环境一般会注入NODE_ENV这个环境变量
const isProduction = process.env.NODE_ENV === 'production';
// CDN域名地址
const CDN_URL = 'https://xxx';
//具体配置
{ base: isProduction ? CDN_URL: '/' }
// .env.development
NODE_ENV=development
// .env.production
NODE_ENV=production

在项目根目录新增的两个环境变量文件.env.development.env.production,分别在开发环境和生产环境注入一些环境变量,这里为了区分不同环境我们加上了NODE_ENV,你也可以根据需要添加别的环境变量。打包的时候 Vite 会自动将这些环境变量替换为相应的字符串。

值得注意的是,如果某个环境变量要在 Vite 中通过 import.meta.env 访问,它必须以VITE_开头,如 VITE_IMG_URL。我们在组件中来使用这个环境变量:

<imgsrc={newURL('./vite.png', import.meta.env.VITE_IMG_URL).href} />

Base64

在 Vite 中,静态资源有两种构建方式,一种是打包成一个单文件,另一种是通过 base64 编码的格式内嵌到代码中。对于比较大的资源,就推荐单独打包成一个文件,而不是内联了。

  • 如果静态资源体积 >= 4KB,则提取成单独的文件
  • 如果静态资源体积 < 4KB,则通过 base64 格式内嵌到代码中
    可以通过 build.assetsInlineLimit 配置,如下代码:
// vite.config.ts
{ 
    build: {
        // 4 K
        BassetsInlineLimit: 4 * 1024
    }
}

svg 格式的文件不受这个配置值的影响,始终会打包成单独的文件,因为它和普通格式的图片不一样,需要动态设置一些属性

图片压缩

图片资源的大小往往是项目产物大小的大头,如果能尽可能精简图片的大小,对项目打包产物体积的优化将得到明显的提升。我们可以使用图片压缩工具来精简图片的体积,比如 Webpack 的 image-webpack-loader,Vite 插件 vite-plugin-imagemin,我们来安装Vite 插件:

pnpm add -D vite-plugin-imagemin

随后在 Vite 配置文件中引入:

// vite.config.ts
import viteImagemin from 'vite-plugin-imagemin';
{
    plugins: [
        viteImagemin({
            // 无损压缩配置,无损压缩下图片质量不会变差
            optipng: {
                optimizationLevel: 7
            },
            // 有损压缩配置,有损压缩下图片质量可能会变差
            pngquant: {
                quality: [0.8, 0.9],
            },
            // svg优化
            svgo: {
                plugins: [
                    { name: 'removeViewBox' },
                    { name: 'removeEmptyAttrs',active: false}
                ]
            }
         })
    ]
}

svg雪碧图

Vite 中对于 svg 文件始终打包成单文件,大量的图标引入会导致网络请求增加,大量的 HTTP 请求会导致网络解析耗时变长,页面加载性能受到影响。我们可以通过合并图标的方案来解决,我们通过vite-plugin-svg-icons来实现这个方案:

pnpm add -D vite-plugin-svg-icons

接着在 Vite 配置文件中增加如下内容:

// vite.config.ts
import { createSvgIconsPlugin  }from 'vite-plugin-svg-icons';

{
    plugins: [
        // 省略其它插件
        createSvgIconsPlugin({
            iconDirs: [path.join(__dirname, 'src/assets')]
        })
    ]
}

src/main.tsx文件中添加一行代码:

import 'virtual:svg-icons-register';

在src/components目录下新建SvgIcon组件:

// SvgIcon/index.tsx
export interface SvgIconProps {
    name?: string;
    prefix: string;
    color: string;
    [key: string]: string;
}
export default function SvgIcon({
    name,
    prefix = 'icon',
    color = '#333',
    ...props
}:SvgIconProps) {
    const symbolId = `#${prefix}-${name}`;
    return(
        <svg {...props} aria-hidden="true">
            <use href={symbolId} fill={color} />
        </svg>
    );
}

接着使用 SvgIcon组件:

const icons = import.meta.glob('./assets/react-*.svg');
const iconUrls = [];
for (const path in icons) {
  const module = await icons[path]()
  const fileName = module.default.split('/').pop();
  const [svgName] = fileName.split('.');
  iconUrls.push(svgName)
}
// 渲染svg组件
{
    iconUrls.map((item) => (
        <SvgIcon name={item} key={item} width="50" height="50" />
    ))
}

这样我们就能将所有的 svg 内容都内联到 HTML 中,省去了大量 svg 的网络请求。

后续

下一章

学习Vite 第四章:利用 Lint 工具链来保证代码规范的落地

  • 15
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值