在 Angular Universal 中内联 SVG 的最佳方式

问题描述 投票:0回答:1

我们有一个 Angular 16 Universal 项目,我们希望找到使用 SVG 图标的最佳方式。性能对于我们的网络应用程序至关重要。我们不能使用 Icomoon 等字体,因为图标是多色的,并且很难定制和维护。

首先,我们开发了一个 Angular 指令,它可以在运行时内联图标。我们尝试了以下模式:

  • 仅客户端:当应用程序在浏览器中运行时,通过 HttpClient.get() 内联图标。但是,在加载整个 main.js(包含该指令)之前,不会开始下载图标。这会导致明显的闪烁。

  • SSR + 客户端:激活 Angular Hydration 后,服务器执行 get 调用来获取图标,客户端不会重复所述调用。这解决了闪烁问题,因为返回的页面已经包含 SVG。但是,我担心在服务器端引入这些请求时会产生瓶颈。

此外,图标目前由资产服务器提供服务,我们希望能够将我们的组件作为库发送给其他团队,以便他们可以重用它们。如果这些团队从不同的主机名 (CORS) 向我们的资产服务器发出请求,这可能会产生问题。因此,提出一些建议:

  • 在构建时内联 SVG,特别是对于那些关键且必须始终显示的 SVG。这将解决我们指令的潜在问题,但会增加脚本的大小。而且,我还没有找到通过 Webpack 配置它的简单方法。将它们直接粘贴到我们的模板中似乎是一个不可取的解决方案。

  • 使用 asset 文件夹,以便在将我们的库传递给其他团队时将图标包含在 dist 文件夹中。

考虑到所有这些想法,将图标包含为 SVG 的最佳方式是什么?

angular svg icons server-side-rendering universal
1个回答
0
投票

创建一个

<svg-icon>
Web 组件,用于创建 SVG 客户端。该组件保存关键图标的所有SVG数据,首先加载,并延迟加载非关键图标(如果需要)。

<script>
((t,e={path:(t,e="")=>`<path d='${t}' ${e}/>`},r={v1:"",v2:"",v3:"",is:"",img:1,box:9,rect:"<rect width='100%' height='100%' fill='{tile}' {border}/>"
,border:"",filter:"",tile:"none",fill:"none",width:1,scale:1,opacity:1,rotate:0,stroke:"#000",xy:0,w:0,h:0,top:"",api:[t,e]})=>{
customElements.define("svg-icon",class extends HTMLElement{static get observedAttributes(){return Object.keys(r)}attributeChangedCallback(){this.svg()}svg(i=this,s=i.A||Object.keys(i.A={...r}).map((t=>Object.defineProperty(i,t,{set:e=>i.setAttribute(t,e),get:()=>i.getAttribute(t)||getComputedStyle(i).getPropertyValue("--svg-icon-"+t).replace(/"/g,"").trim()||i.A[t]},e[t]=e=>(i.A[t]=e,"")))),l,a=(t[i.is]||"").split`;`.map((t=>([s,l]=t.trim().split`:`,e[s]?e[s].apply(i,l.split`,`):t))).join``,o=i.box/2,
c=`<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 ${i.w||i.box} ${i.h||i.box}'>${i.rect}<g stroke-width='{width}' stroke='{stroke}' fill='{fill}' opacity='{opacity}' filter='{filter}' transform='translate({xy}) matrix({scale} 0 0 {scale} ${o-o*i.scale} ${o-o*i.scale}) rotate({rotate} ${o} ${o})'>${a}</g>${i.top}</svg>`.replace(/{\s?([^{}\s]*)\s?}/g,((t,e)=>i[e]))){return i.innerHTML=1==i.img?
`<img src="data:image/svg+xml,${c.replace(/#/g,"%23")}">`:c}})})(
{
   menu:"box:9;path:m1.5 2.8h6m0 2h-6m0 2h6,stroke-linecap='round'",
   settings:"box:96;<circle stroke-width='12' cx='48' cy='50' r='26'/><circle stroke-width='12' cx='48' cy='50' r='36' stroke-dasharray='14'/>",
   renew:"box:96;fill:black;path:M48 24v12l16-16-16-16v12c-18 0-32 14-32 32 0 6 2 12 5 17L27 60A23 23 0 0 1 24 48c0-13 11-24 24-24zm26 6L69 37c2 3 3 7 3 11 0 13-11 24-24 24v-12l-16 16 16 16v-12c18 0 32-14 32-32 0-6-2-12-5-16z"
});
</script>

<style>
  svg-icon {
    width: 80px;
    display: inline-block;
    background: grey;
  }
  svg-icon:hover { background: lightgrey; cursor:pointer }
</style>

<svg-icon is="menu"></svg-icon>
<svg-icon is="settings"></svg-icon>
<svg-icon is="renew" rotate=45 fill=gold stroke=white></svg-icon>

© www.soinside.com 2019 - 2024. All rights reserved.