如何在Vite项目中处理静态资源

在前端工程化建设中,静态资源是必须处理的一个问题,前端的静态资源通常包括图片、JSON、Worker 文件、Web Assembly 文件等等。由于静态资源本身并不是一个标准意义上的模块,因此在处理静态资源和代码时是需要区别对待的。

对于资源加载问题,Vite需要处理的就是如何将静态资源解析出来并加载为一个 ES 模块;另一方面,我们还需要考虑在生产环境下,静态资源的部署问题、体积问题、网络性能等问题。本文将结合Vite自身的能力及其生态,来解决Vite项目中静态资源处理的各个疑难点。

一、图片加载

图片是前端项目中最常用的静态资源之一,本身包括的图片格式也非常的多,比如png、jpeg、webp、avif、gif、svg都是图片的范畴。本小节主要讨论的是如何加载图片,也就是说怎么让图片在页面中正常显示。

1.1 使用场景

在平时开发中,图片的加载主要有以下几种场景。

1,在HTML或者JSX中,使用img 标签来加载图片:

<img src="../../assets/a.png"/> 

2,在 CSS 文件中通过 background 属性加载图片:

background: url('../../assets/b.png') norepeat;

3,在 JavaScript 中,通过脚本的方式动态指定图片的src属性:

document.getElementById('hero-img').src = '../../assets/c.png'

1.2 在Vite中使用

接下来,我们看一下如何在Vite项目中使用图片。首先,我们需要在 Vite配置文件vite.config.ts中配置一下图片资源,比如:

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

经过上面的配置后,当遇到@assets路径的时候,Vite便会自动定位至根目录下的src/assets目录。值得注意的是,alias 别名配置不仅在 JavaScript 的 import 语句中生效,在 CSS 代码的 @import 和 url导入语句中也同样生效。

接下来,我们就可以在代码中引入assets的图片,比如:

import React, { useEffect } from 'react';
import { devDependencies } from '../../../package.json';
import styles from './index.module.scss';
// 1. 导入图片
import logoSrc from '@assets/vite.png';// 方式一
export function Header() {return (<div className={`p-20px text-center ${styles.header}`}><!-- 使用图片 --><img className="m-auto mb-4" src={logoSrc} alt="" /></div>);
}// 方式二
export function Header() {useEffect(() => {const img = document.getElementById('logo') as HTMLImageElement;img.src = logoSrc;}, []);return (<div className={`p-20px text-center ${styles.header}`}><!-- 省略前面的组件内容 --><!-- 使用图片 --><img id="logo" className="m-auto mb-4" alt="" /></div>);
}

需要说明的是,使用@assets方式引入资源文件时,需要安装一下craco插件:

npm i @craco/craco -D

接着,运行项目就可以看到效果了。

image.png

接下来,我们尝试一下在样式文件中添加background属性,看看是否能够正常显示:

.header {// 前面的样式代码省略background: url('@assets/background.png') no-repeat;
}

1.3 SVG 方式加载

除了png、jpeg、webp等常见的图片格式,svg也是开发中常见的,并且svg格式的图片具有使用灵活、不失真等特性。因此,我们望能将 svg 当做一个组件来引入,这样我们可以很方便地修改 svg 的各种属性。

默认情况下,svg格式的图片是不被支持的,如果需要在前端项目中使用svg图片,需要先安装对应的插件。不过还好社区中也已经了有了对应的插件支持:

  • Vue2:使用 vite-plugin-vue2-svg插件
  • Vue3:引入 vite-svg-loader插件
  • React:引入 vite-plugin-svgr插件

首先,我们在使用Vite构建的React项目中安装vite-plugin-svgr插件:

npm i vite-plugin-svgr -D

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

import svgr from 'vite-plugin-svgr';
{plugins: [svgr()]
}

接着,还需要要在 tsconfig.json添加如下配置,否则会有类型错误提示。

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

经过上面的处理之后,我们就可以在项目中使用 svg 格式的图片了。

import { ReactComponent as ReactLogo } from '@/assets/react.svg'
export default Demo() {return <ReactLogo />
}

1.4 Web Worker

Web Worker 是 HTML5 标准的一部分,这一规范定义了一套 API,允许我们在 js 主线程之外开辟新的 Worker 线程,并将一段 js 脚本运行其中,它赋予了开发者利用 js 操作多线程的能力。

Vite 中使用 Web Worker 也非常简单,我们在新建Header/example.ts文件,代码如下:

const start = () => {let count = 0;setInterval(() => {// 给主线程传值postMessage(++count);}, 2000);
};start();

然后,在组件中引入上面的文件,引入的时候注意加上?worker后缀,相当于告诉 Vite 这是一个 Web Worker 脚本文件。

import Worker from './example.ts?worker';const worker = new Worker();
worker.addEventListener('message', (e) => {console.log(e);
});

接着,重新运行项目,然后打开浏览器的控制面板就可以看到 Worker 传给主线程的信息。

image.png

1.5 Web Assembly

Vite 对于 .wasm 文件也提供了开箱即用的支持。我们拿一个斐波拉契的 .wasm 文件(原文件已经放到Github 仓库中)来进行一下实际操作,对应的 JavaScript 原文件如下:

export function fib(n) {var a = 0,b = 1;if (n > 0) {while (--n) {let t = a + b;a = b;b = t;}return b;}return a;
}

接下来,我们在组件中导入fib.wasm文件:

import init from './fib.wasm';
type FibFunc = (num: number) => number;
init({}).then((exports) => {const fibFunc = exports.fib as FibFunc;console.log('Fib result:', fibFunc(10));
});

回到浏览器,在项目中执行上面的代码如果看到计算结果,说明 .wasm 文件已经被成功执行。

1.6 其他静态资源

除了上述的资源格式外,Vite 也对下面几类格式提供了内置的支持:

  • 媒体类文件,包括mp4、webm、ogg、mp3、wav、flac和aac。
  • 字体类文件。包括woff、woff2、eot、ttf 和 otf。
  • 文本类。包括webmanifest、pdf和txt。

也就是说,可以在 Vite 项目中将这些类型的文件当做一个 ES 模块来导入使用。如果你的项目中还存在其它格式的静态资源,也可以通过assetsInclude配置让 Vite 来支持加载。

二、生产环境

在开发环境,我们对于Vite项目进行了具体的编码实践。那对于生产环境,我们又会遇到哪些问题呢:

  • 部署域名怎么配置
  • 资源打包成单文件还是作为 Base64 格式内联
  • 图片太大了怎么处理
  • svg 请求数量太多了怎么优化

2.1 自定义域名部署

一般来说,当我们访问线上的站点时,站点里面一些静态资源的地址都包含了相应域名的前缀。

<img src="https://baidu.com/flower.png" />

其中,“https://baidu.com/”就是CDN 地址前缀。那如果要在线上环境访问这些静态的图片资源,我们需要怎么处理呢?事实上,对于Vite构建的项目来说,只需要在配置文件中指定base参数的路径即可。

// 是否为生产环境,在生产环境一般会注入 NODE_ENV 这个环境变量,见下面的环境变量文件配置
const isProduction = process.env.NODE_ENV === 'production';
// 填入项目的 CDN 域名地址
const CDN_URL = 'xxxxxx';
{base: isProduction ? CDN_URL: '/'
}
// .env.development
NODE_ENV=development
// .env.production
NODE_ENV=production

注意,为了方便读取项目的配置文件,我们在项目根目录新增的两个环境变量文件.env.development和.env.production,顾名思义,即分别在开发环境和生产环境注入一些环境变量。

当然,有时候可能项目中的某些图片需要存放到另外的存储服务,一种直接的方案是将完整地址写死到 src 属性中,如:

<img src="https://my-image-cdn.com/logo.png">

不过,显然这种方式不太灵活也不太优雅。对于这种问题,我们可以通过定义环境变量的方式来解决这个问题,在项目根目录新增.env文件。

// .env 文件
VITE_IMG_BASE_URL=https://my-image-cdn.com

然后,在src/vite-env.d.ts配置文件增加类型声明:

interface ImportMetaEnv {readonly VITE_APP_TITLE: string;// 自定义的环境变量readonly VITE_IMG_BASE_URL: string;
}interface ImportMeta {readonly env: ImportMetaEnv;
}

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

<img src={new URL('./logo.png', import.meta.env.VITE_IMG_BASE_URL).href} />

最后,当我们启动项目之后,就可以在开发环境启动项目或者生产环境打包后可以看到环境变量已经被替换。
 
image.png

2.2 单文件 or 内联

在Vite项目中,所有的静态资源都有两种构建方式,一种是打包成一个单文件,另一种是通过 base64 编码的格式内嵌到代码中。

通常,对于比较小的资源,适合内联到代码中,一方面对代码体积的影响很小,另一方面可以减少不必要的网络请求,优化网络性能。而对于比较大的资源,就推荐单独打包成一个文件,而不是内联了,否则可能导致代码体积瞬间庞大,页面加载性能直线下降。并且,Vite给出了内置的优化方案:

  • 静态资源体积 >= 4KB,则提取成单独的文件
  • 静态资源体积 < 4KB,则作为 base64 格式的字符串内联

上述的4 KB即为提取成单文件的临界值,当然,这个临界值你可以通过build.assetsInlineLimit自行配置。

{build: {// 8 KBassetsInlineLimit: 8 * 1024}
}

2.3 图片压缩

图片资源的体积在前端项目往往是项目产物体积的大头,如果能尽可能精简图片的体积,那么对项目整体打包产物体积的优化将会是非常明显的。

在 JavaScript 领域,有一个非常知名的图片压缩库imagemin,作为一个底层的压缩工具,前端的项目中经常基于它来进行图片压缩,比如 Webpack 中大名鼎鼎的image-webpack-loader就是使用的它。当然,对于Vite项目,我们也可以使用开箱即用的Vite插件——vite-plugin-imagemin。

使用前,我们需要在项目中先安装vite-plugin-imagemin插件。

npm i vite-plugin-imagemin -D

接着,在 Vite 配置文件中引入如下配置:

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}]}})]
}

最后,我们尝试执行npm run build进行打包,就可以看到执行了压缩:
 
image.png

2.4 svg优化

在实际的项目中,我们还会经常用到各种各样的 svg 图标,虽然 svg 文件一般体积不大,但 Vite 中对于 svg 文件会始终打包成单文件,大量的图标引入之后会导致网络请求增加,大量的 HTTP 请求会导致网络解析耗时变长,页面加载性能直接受到影响。比如,我们需要在某个页面中引入5个 svg 文件。

import Logo1 from '@assets/icons/logo-1.svg';
import Logo2 from '@assets/icons/logo-2.svg';
import Logo3 from '@assets/icons/logo-3.svg';
import Logo4 from '@assets/icons/logo-4.svg';
import Logo5 from '@assets/icons/logo-5.svg';

顺便说一句,Vite 中提供了import.meta.glob的语法糖来解决这种批量导入的问题,如上述的 import 语句可以写成下面这样。

const icons = import.meta.glob('../../assets/icons/logo-*.svg');

接下来,我们稍作解析,将 svg 应用到组件当中:

const iconUrls = Object.values(icons).map(mod => mod.default);
// 组件返回内容添加如下
{iconUrls.map((item) => (<img src={item} key={item} width="50" alt="" />
))}

重新运行项目,会发现浏览器分别发出了 5 个 svg 的请求:

image.png

那我们能不能把这些 svg 合并到一起,从而大幅减少网络请求呢?答案是可以的,通过vite-plugin-svg-icons即可实现合并请求操作。首先,我们需要安装一下这个插件:

npm i vite-plugin-svg-icons -D

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

import { createSvgIconsPlugin } from 'vite-plugin-svg-icons';
{plugins: [// 省略其它插件createSvgIconsPlugin({iconDirs: [path.join(__dirname, 'src/assets/icons')]})]
}

然后,在src/components目录下新建SvgIcon组件。

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>);
}

接着,我们在Header 组件中稍作修改。

const icons = import.meta.globEager('../../assets/icons/logo-*.svg');
const iconUrls = Object.values(icons).map((mod) => {// 如 ../../assets/icons/logo-1.svg -> logo-1const fileName = mod.default.split('/').pop();const [svgName] = fileName.split('.');return svgName;
});// 渲染 svg 组件
{iconUrls.map((item) => (<SvgIcon name={item} key={item} width="50" height="50" />
))}

最后,在src/main.tsx文件中添加一行代码:

import 'virtual:svg-icons-register';

回到浏览器的页面中,就可以发现svg图片已经生成,然后通过 use 属性来引用svg的对应内容即可。

image.png

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/10172.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

ChatGPT 和 Elasticsearch:OpenAI 遇见私有数据(二)

在之前的文章 “ChatGPT 和 Elasticsearch&#xff1a;OpenAI 遇见私有数据&#xff08;一&#xff09;” 中&#xff0c;我们详细描述了如何结合 ChatGPT 及 Elasticsearch 来进行搜索。它使用了如下的架构&#xff1a; 在今天的文章中&#xff0c;我们来详细描述实现这个的详…

织梦TXT批量导入TAG标签并自动匹配相关文章插件

织梦TXT批量导入TAG标签并自动匹配相关文章插件是一种非常有用的插件&#xff0c;它可以帮助网站管理员快速地将TAG标签添加到文章中&#xff0c;并自动匹配相关文章。 以下是该织梦TXT批量导入TAG标签插件的几个优点&#xff1a; 1、提高网站的SEO效果&#xff1a;TAG标签是搜…

win10 开启全局代理

1. 打开设置 2. 点击“网络和Internet” 3.设置手动代理 . 设置完成后就可以愉快的玩耍啦 转载于:https://www.cnblogs.com/amiezhang/p/11288033.html

linux设置全局代理

vim /etc/profile http_proxyhttp://127.0.0.1:9666 #代理程序地址 https_proxyhttp://127.0.0.1:9666 ftp_proxyhttp://127.0.0.1:9666 export http_proxy export ftp_proxy export https_proxysource /etc/profile这样http,https,ftp都走代理了

ubuntu配置全局系统代理

测试版本: ubuntu1604LTS 1.配置系统代理 注意:可供浏览器使用,终端需要另外配置 打开设置-->网络-->网络代理,方法选择手动,填写代理,最后点击应用到整个系统 2.配置apt代理 sudo gedit /etc/apt/apt.conf #此时还没有vim,只能用用gidit打开文件#添加内容,然后保…

手机用Postern配置socks5全局代理详细教程

以静态Socks5独享IP的单地区资源为例&#xff0c;即IP资源全部归属单一城市&#xff0c;不会变动&#xff0c;如南京区域&#xff0c;则IP全部为南京城市出口。 关于Socks5的使用有多种方案&#xff0c;可应用于PC&#xff0c;安卓&#xff0c;模拟器&#xff0c;请根据情况灵…

Linux系统设置全局代理(http代理,socks代理)

临时 export http_proxyhttp://ip:port export https_proxyhttp://ip:port 永久 vim /etc/profilehttp_proxyhttp://127.0.0.1:9666 #代理程序地址https_proxyhttp://127.0.0.1:9666ftp_proxyhttp://127.0.0.1:9666export http_proxyexport ftp_proxyexport https_proxy 代理变…

基于Android的招聘求职网站的设计与实现

毕业设计 基于Android的招聘求职网站的设计与实现 1&#xff0e;课题意义及目标 在二十一世纪求职方式跟以前是不同的&#xff0c;与在各个用人单位和招聘会上寻找理想的工作&#xff0c;基于安卓的招聘系统能够提供最好的最丰富及时的招聘信息。。 通过对该系统的研究设计&…

互联网中的web3.0和gpt有何联系?

文章目录 ⭐前言⭐web 3.0&#x1f496; web1.0-web3.0的概念 ⭐chatgpt&#x1f496; gpt的概念 ⭐总结⭐结尾 ⭐前言 大家好&#xff0c;我是yma16&#xff0c;本文分享互联网中的web3.0和gpt的关系。 互联网的发展 第一台计算机的出现 世界上第一台通用计算机“ENIAC”于…

家庭宽带在有ipv6公网环境下,配置本地tomcat服务器+域名+ssl+ddns,实现ipv6建站、搭建简易的文件服务器、搭建webdav服务器等功能

必备条件&#xff1a; 宽带运营商提供了ipv6 光猫拨号改为路由器拨号且路由器开启了ipv6 运营商未屏蔽ipv6的80/443端口&#xff08;如果屏蔽了常用端口&#xff0c;那么可以尝试高一点的端口号。端口号范围&#xff1a;1 - 65535&#xff09; 目录 一、阿里云申请域名&s…

开源游戏区块链项目分享:Unity开发的独立区块链

Arouse Blockchain [Unity独立区块链] ❗️千万别被误导&#xff0c;上图内容虽然都在项目中可寻&#xff0c;但与目前区块链的业务代码关联不大&#xff0c;仅供宣传作用(总得放些图看着好看)。之所以有以上内容是项目有个目标功能是希望每个用户在区块链上都有一个独一无二的…

和ChatGPT对比,文心一言的表现已经是中国之光了

网络上各种测评满天飞&#xff0c;这里就不展开说了&#xff0c;针对“chatgpt”这项技术的难点&#xff0c;是十分巨大的。当你对文心一言以及其他国产AI软件存在不满的时候&#xff0c;你可以简单对着chatgpt或者文心一言搜索&#xff01; ChatGPT技术难点 通俗来讲难度&…

【24fall】计算机免考留学申请,背景提升方向

文章目录 &#x1f4a1;1、学业绩点GPA1.1 部分学校绩点要求&#xff08;23fall&#xff09;1.2 关于打备注说明的情况1.3 关于换个算法提高绩点 &#x1f4a1;2、英语语言成绩2.0 部分学校留学费用清单&#xff08;23fall&#xff09;2.1 部分学校语言成绩要求&#xff08;23f…

Flask框架基础1

最基本框架代码 from flask import Flask实现Flask基本程序 步骤&#xff1a;1 导入Flask类2 创建Flask类的实例对象3 定义路由和视图函数4 启动服务器 appFlask(__name__)app.route("/") def hello():return hello worldif __name____main__:app.run() 运行结果&a…

独立app开发和运行(使用篇)

1.概述 bcos支持动态加载APP任务到内存中执行,用户应用程序只要调用bcos提供的系统调用就可以实现自己的APP功能。当然,APP的开发需要遵循一些bcos自己的规则。 2.创建工程 keil按照你熟悉的方式创建一个空的工程,按照下面配置: C/C++页面,按照红框中的字符串配置,主要…

开发一个看番app[樱花动漫移动端app]

使用react-native开发&#xff0c;功能&#xff1a; 支持看番支持历史记录浏览支持追番 项目地址: https://github.com/HGGshiwo/Sakura 界面&#xff1a; 首页分类用户界面播放界面历史记录搜索界面全部动漫追番

科研人体验gpt

https://greengpt.app/ 安利一下这个非官方网站&#xff0c;内地可以免费访问使用GPT。免费并且不需要翻Q。 本篇主要介绍第一次体验GPT的感受&#xff0c;首要想法是做markdown&#xff0c;便于之后复习查阅。 首先&#xff0c;查阅了相关资料&#xff0c;官方渠道需要注册。找…

硬编码支持情况(一)

硬编码支持情况&#xff08;一&#xff09; 图片信息原文链接&#xff1a;http://trac.ffmpeg.org/wiki/HWAccelIntro 截个图&#xff1a; 注&#xff1a; &#xff08;一&#xff09;&#xff1a;Intel 平台 1&#xff1a;Intel 平台的Quick Sync Video(qsv)是对于音视频编…

宏景eHr 手机App应用二次开发(图文)

应用宏景eHr软件&#xff0c;其中将hr与通达OA进行了组织结构和人员信息的数据同步开发。 在后续的使用过程中&#xff0c;需要使用到手机App&#xff0c;但是宏景的app是完全按照应用的用户数来计费&#xff0c;这样算下来如果使用员工自助的话会是一笔不小的费用。 通过对系…

技巧|你的微信|QQ授权了多少网站与APP?查完吓一跳啊!

编辑&#xff5c;排版&#xff5c; 宅哥技术转载请联系商务合作给你开白名单来源&#xff1a;宅哥技术&#xff08;zg_jishu&#xff09; ---------♥--------- 前言 相信很多朋友都有在用QQ或者微信快捷登录某些应用或网站&#xff0c;每次的授权我们都没在意&#xff0c;但是…