UNPKG

@anolilab/unplugin-favicons

Version:

Generate favicons for your project with caching for blazing fast rebuilds.

7 lines (6 loc) 12.8 kB
var V=Object.defineProperty;var b=(e,t)=>V(e,"name",{value:t,configurable:!0});import{resolve as G,join as N,basename as q,parse as U}from"node:path";import{colorize as w}from"consola/utils";import z from"magic-string";import Q from"mime/lite";import{findStaticImports as X,parseStaticImport as Y}from"mlly";import{favicons as Z}from"favicons";import{consola as ee}from"consola/basic";import{readFileSync as te}from"node:fs";import ae from"fast-json-stable-stringify";import{findCacheDirSync as ne}from"@visulima/find-cache-dir";import{get as re,put as oe}from"cacache";import{fromData as se}from"ssri";import{parseFragment as ie}from"parse5";import ce from"node:module";import{findPackageJsonSync as le}from"@visulima/package";import x from"parse-author";const P="@anolilab/unplugin-favicons",ue={android:!1,appleIcon:!1,appleStartup:!1,coast:!1,favicons:!1,firefox:!1,windows:!1,yandex:!1},B={appShortName:void 0,appleStatusBarStyle:"black-translucent",background:"#fff",dir:"auto",display:"standalone",icons:{android:!0,appleIcon:!0,appleStartup:!0,favicons:!0,windows:!0,yandex:!1},lang:"en-US",loadManifestWithCredentials:!1,orientation:"any",pixel_art:!1,scope:"/",start_url:"/?homescreen=1",theme_color:"#fff",version:"1.0"},h=ee.withTag(P);var me=Object.defineProperty,F=b((e,t)=>me(e,"name",{value:t,configurable:!0}),"o$5");const S=ne(P),I=F(e=>se(e).toString(),"computeKey"),T=F(async(e,{logLabel:t})=>{if(!S)throw new Error("Unable to find a suitable cache directory.");const a=I(e),n=`cache:get${t?`:${t}`:""}`;t&&h.debug(`${n} Generated digest for ${w("green",t)}:`,a);try{const c=await re(S,a),{data:f}=c;return t&&h.debug(`${n} Cache hit for ${t}`),f}catch(c){t&&(String(c?.message).includes("No cache entry")?h.debug(`${n} ${w("yellow","Cache miss.")}`):h.error(`${n} ${c}`));return}},"get"),A=F(async(e,t,{logLabel:a})=>{if(!S)throw new Error("Unable to find a suitable cache directory.");const n=I(e);if(await oe(S,n,t),a){const c=`cache:put:${a}`;h.debug(`${c} ${w("green","Put OK.")}`)}},"put");var pe=Object.defineProperty,fe=b((e,t)=>pe(e,"name",{value:t,configurable:!0}),"o$4");const ge=fe(async e=>I(ae({...e,source:te(e.source,{encoding:"utf8"})})),"generateCacheKeyForJob");var de=Object.defineProperty,he=b((e,t)=>de(e,"name",{value:t,configurable:!0}),"c$1");const ve=he(async(e,t)=>{const a=await T(e,{logLabel:t??""});if(!a)return;const n=JSON.parse(a.toString("utf8")),c=Promise.all(n.images.map(async s=>{const d=`${e}/images/${s.name}`,i=await T(d,{logLabel:s.name});if(!i)throw new Error(`Expected cached contents for "${d}"`);return{...s,contents:i}})),f=Promise.all(n.files.map(async s=>{const d=`${e}/files/${s.name}`,i=await T(d,{logLabel:s.name});if(!i)throw new Error(`Expected cached contents for "${d}"`);return{...s,contents:i.toString("utf8")}})),[g,u]=await Promise.all([f,c]);return{...n,files:g,images:u}},"getCacheResponse");var be=Object.defineProperty,$e=b((e,t)=>be(e,"name",{value:t,configurable:!0}),"l$2");const ye=$e(async(e,t,a)=>{const n={files:[],html:[],images:[]},c=Promise.all(t.images.map(async s=>{const{contents:d,...i}=s,j=`${e}/images/${i.name}`;n.images.push(i),h.verbose(`${a??""} Caching ${w("green",i.name)}.`),await A(j,d,{logLabel:i.name})})),f=Promise.all(t.files.map(async s=>{const{contents:d,...i}=s,j=`${e}/files/${i.name}`;n.files.push(i),h.verbose(`${a??""} Caching ${w("green",i.name)}.`),await A(j,d,{logLabel:i.name})}));t.html.forEach(s=>{n.html.push(s)});const g=JSON.stringify(n),u=A(e,g,{logLabel:a??""});await Promise.all([f,c,u])},"putCacheResponse");var we=Object.defineProperty,C=b((e,t)=>we(e,"name",{value:t,configurable:!0}),"g$2");const ke=C(e=>{const{icons:t,...a}=e.favicons??{};return Object.entries(e.icons).reduce((n,[c,f])=>{const{source:g,...u}=f,s={...ue,[c]:u},d={config:{...a,icons:s},iconType:c,source:g};return[...n,d]},[])},"mapOptionsToJobs"),Pe=C(e=>e.reduce((t,a)=>(a.files.forEach(n=>{t.files.push(n)}),a.images.forEach(n=>{t.images.push(n)}),a.html.forEach(n=>{t.html.push(n)}),t),{files:[],html:[],images:[]}),"reduceResponses"),je=C(async e=>{const t=[];if(e.icons&&!e.logo)t.push(...ke(e));else{const n={...B,...e.favicons,icons:{...B.icons,...e.favicons?.icons}};e.logo=G(e.logo??N("assets","logo.png")),t.push({config:n,iconType:"logo",source:e.logo})}const a=t.map(async n=>{const c=await ge(n),{config:f,iconType:g,source:u}=n,s=q(u);if(e.cache){const i=await ve(c,g);if(i)return h.verbose(`Using cached ${w("bold",g)} assets from source ${w("green",s)}.`),i}const d=await Z(u,f);return e.cache&&ye(c,d,g).then(()=>{h.verbose(`Cached rendered ${w("bold",g)} assets from source ${w("green",s)}.`)}),d});return Pe(await Promise.all(a))},"generateFavicons");var Oe=Object.defineProperty,Ne=b((e,t)=>Oe(e,"name",{value:t,configurable:!0}),"i$2");const L=Ne((e,t)=>{const a=U(t).name;return e.find(n=>a===U(n.name).name)},"findEmittedFile");var Ee=Object.defineProperty,Se=b((e,t)=>Ee(e,"name",{value:t,configurable:!0}),"s$2");const R=Se((e,t,a="/")=>t.flatMap(n=>{const c=n;return ie(n).childNodes.map(f=>{const g=f.attrs.map(u=>{if(u.name==="href"){const s=L(e,u.value);if(s)u.value=`${a}${s.resolvedName}`;else throw new Error(`Unable to find a corresponding file for href: ${u.value}`)}return[u.name,u.value]});return{attrs:Object.fromEntries(g),fragment:c,injectTo:"head",tag:f.nodeName}}).filter(Boolean)}),"parseHtml");var Je=Object.defineProperty,De=b((e,t)=>Je(e,"name",{value:t,configurable:!0}),"s$1");const H=De((e,t)=>{const a=JSON.parse(t);return Array.isArray(a.icons)?a.icons=a.icons.map(n=>{const c=L(e,n.src);if(!c)throw new Error(`Unable to find a corresponding emitted file for manifest entry: ${n.src}`);return{...n,src:`/${c.resolvedName}`}}):typeof a.icons=="object"&&Object.keys(a.icons).length>0&&(a.icons=Object.fromEntries(Object.entries(a.icons).map(([n,c])=>{const f=L(e,c);if(!f)throw new Error(`Unable to find a corresponding emitted file for manifest entry: ${c}`);return[n,`/${f.resolvedName}`]}))),JSON.stringify(a)},"updateManifest");var Te=Object.defineProperty,Ae=b((e,t)=>Te(e,"name",{value:t,configurable:!0}),"o$2");const Le=Ae(e=>{const{compiler:{options:t}}=e,a=t.plugins.find(n=>n?.constructor?.name==="HtmlRspackPlugin")?.constructor;if(a!==void 0)return a},"findHtmlRspackPlugin");var Fe=Object.defineProperty,W=b((e,t)=>Fe(e,"name",{value:t,configurable:!0}),"o$1");const M=ce.createRequire(import.meta.url),Ie=W(()=>{try{const e=M.resolve("html-webpack-plugin/package.json"),{version:t}=M(e);return`found html-webpack-plugin ${t} at ${e}`}catch{return"html-webpack-plugin not found"}},"getHtmlWebpackPluginVersion"),_=W(e=>{const{compiler:t}=e,a=t.options.plugins.find(n=>n?.constructor?.name==="HtmlWebpackPlugin")?.constructor;if(a!==void 0){if(a.version>=5)return a;e.errors.push(new t.webpack.WebpackError(`This @anolilab/unplugin-favicons version is not compatible with your current HtmlWebpackPlugin version. Please upgrade to HtmlWebpackPlugin >= 5 ${Ie()}`))}},"findHtmlWebpackPlugin");var Ce=Object.defineProperty,Ue=b((e,t)=>Ce(e,"name",{value:t,configurable:!0}),"n");const xe=Ue(e=>{e<0&&(e=-e);const t={day:Math.floor(e/864e5),hour:Math.floor(e/36e5)%24,minute:Math.floor(e/6e4)%60,second:Math.floor(e/1e3)%60,ms:Math.floor(e)%1e3};return Object.entries(t).filter(a=>a[1]!==0).map(a=>a[0]==="ms"?`${a[1]} ${a[0]}`:`${a[1]} ${a[1]===1?a[0]:`${a[0]}s`}`).join(", ")},"formatDuration");var Be=Object.defineProperty,Re=b((e,t)=>Be(e,"name",{value:t,configurable:!0}),"a");class He{static{b(this,"o")}static{Re(this,"Oracle")}packageJson;constructor(t){try{const a=le(t);this.packageJson=a?.packageJson}catch{}}guessAppName(){return this.packageJson?.name}guessDescription(){return this.packageJson?.description}guessDeveloper(){if(this.packageJson?.author!==void 0){if(typeof this.packageJson.author=="string")return x(this.packageJson.author);if(typeof this.packageJson.author=="object"&&this.packageJson.author!==null)return{email:this.packageJson.author?.email,name:this.packageJson.author.name,url:this.packageJson.author?.url}}if(this.packageJson?.maintainers!==void 0&&Array.isArray(this.packageJson.maintainers)&&this.packageJson.maintainers.length>0){const t=this.packageJson.maintainers[0];if(typeof t=="string")return x(t);if(typeof t=="object"&&t!==null)return{email:t?.email,name:t.name,url:t?.url}}return{email:void 0,name:void 0,url:void 0}}guessVersion(){return this.packageJson?.version}}var Me=Object.defineProperty,O=b((e,t)=>Me(e,"name",{value:t,configurable:!0}),"g");const st=O((e,t)=>{const a={cache:!0,inject:!0,...e},n=new He(a?.projectRoot),c=n.guessDeveloper();let f;a.favicons={appDescription:n.guessDescription(),appName:n.guessAppName(),developerName:c.name,developerURL:c.url,version:n.guessVersion(),...a.favicons};let g="",u,s=[],d,i="ENABLED";a.inject!==!0&&(i="DISABLED"),t.framework==="esbuild"&&(g="/",h.warn("html injection in esbuild is not supported, injection was disabled."),i="NOT_SUPPORTED");const j=O((o,r)=>{const{files:m,html:p,images:k}=r,$=k.map(l=>{const v=N(a.outputPath??"",l.name);return o.emitFile({fileName:v,source:l.contents,type:"asset"}),h.debug(`emit ${w("green",String(v))}`),{name:l.name,resolvedName:v}}),y=m.map(l=>{const v=N(a.outputPath??"",l.name),D=l.name.includes("manifest")?H($,l.contents):l.contents;return o.emitFile({fileName:v,source:D,type:"asset"}),h.debug(`emit ${w("green",v)}`),{name:l.name,resolvedName:v}});s=R([...y,...$],p,g),d={files:y,images:$,metadata:s.map(l=>l.fragment).join("")}},"emitFiles"),E=new Map([]),K=O((o,r)=>{const{files:m,html:p,images:k}=r,$=k.map(l=>{const v=N(a.outputPath??"",l.name);return E.set(v,l.contents),h.debug(`serve ${w("green",String(v))}`),{name:l.name,resolvedName:v}}),y=m.map(l=>{const v=N(a.outputPath??"",l.name),D=l.name.includes("manifest")?H($,l.contents):l.contents;return E.set(v,D),h.debug(`serve ${w("green",v)}`),{name:l.name,resolvedName:v}});s=R([...y,...$],p,g),d={files:y,images:$,metadata:s.map(l=>l.fragment).join("")}},"serveFiles"),J=O((o,r)=>{r&&r.getHooks(o)?.alterAssetTags?.tapPromise(P,async m=>(m.plugin.userOptions.favicon!==!1&&m.plugin.userOptions.favicons!==!1&&m.assetTags.meta.push(...s.map(p=>({attributes:p.attrs,meta:{plugin:P},tagName:p.tag,voidTag:!0}))),m))},"injectHtmlPlugin");return{apply:O((o,r)=>(f=r.command,!0),"apply"),async buildStart(){const o=Date.now(),r=await je({...a,favicons:{...a.favicons,path:a?.favicons?.path??a.outputPath}});h.info(`Generated assets in ${xe(Date.now()-o)}.`),f===void 0||f==="build"?(j(this,r),i==="DISABLED"&&(h.info("Inject is disabled, a webapp html file will be generated."),this.emitFile({fileName:"webapp.html",source:s.map(m=>m.fragment).join(` `),type:"asset"}))):f==="serve"&&K(this,r)},name:P,order:"post",rollup:{generateBundle(o,r){i==="ENABLED"&&r["index.html"]&&typeof r["index.html"].source=="string"&&(r["index.html"].source=r["index.html"].source.replace("</head>",`${s.map(m=>m.fragment).join(` `)} </head>`))}},rspack(o){g="/",o.hooks.make.tapPromise(P,async r=>{if(i==="ENABLED"){const m=Le(r),p=_(r);m?J(r,m):p?J(r,p):(h.warn('No "@rspack/plugin-html" or "html-webpack-plugin" plugin was found, injection was disabled, currently the builtin html is not supported.'),i="NOT_SUPPORTED")}})},transform(o,r){const m=`${P}/runtime`;if(!o.includes(m))return;const p=new z(o),k=X(o).filter($=>$.specifier===m);if(k.length!==0&&(k.forEach($=>{const y=Y($),l=`const ${y.defaultImport??y.imports} = ${JSON.stringify(d)};`;p.overwrite(y.start,y.end,l)}),!!p.hasChanged()))return{code:p.toString(),map:p.generateMap({includeContent:!0,source:r})}},transformInclude(o){return o.match(/\.((c|m)?j|t)sx?$/u)},vite:{configResolved(o){g=o.base,o.plugins.forEach(r=>{u===void 0&&r.name.includes("sveltekit")?(u="sveltekit",a.outputPath="_app/immutable/assets/unplugin-favicons"):u===void 0&&r.name.includes("astro")?u="astro":u===void 0&&r.name.includes("vike")&&(u="vike",a.outputPath="assets/static")})},configureServer(o){return f==="serve"?()=>{o.middlewares.use((r,m,p)=>{const k=r.url?.slice(1);if(E.has(k)){const $=E.get(k),y=k.split(".").pop();$ instanceof Buffer&&m.setHeader("Content-Type",y?Q.getType(y):"application/octet-stream"),m.end($)}else p()})}:()=>{}},generateBundle(o,r){u==="astro"&&Object.keys(r).forEach(m=>{const p=r[m];p?.fileName?.includes(".astro")&&(p.code=p.code.replaceAll(/<link rel="icon".*?>/gu,""),p.code=p.code.replace("</head>",`${s.map(k=>k.fragment).join("")}</head>`))})},transformIndexHtml:{handler(o){return i==="ENABLED"&&u!=="vike"&&(o=o.replaceAll(/<link rel="icon".*?>/gu,""),o=o.replace("</head>",`${s.map(r=>r.fragment).join("")}</head>`)),o},order:"post"}},webpack(o){o.options.output.path?.includes(".next")?(a.outputPath="static/media/favicons/",i="NOT_SUPPORTED"):g="/",o.hooks.make.tapPromise(P,async r=>{h.info(r),i==="ENABLED"&&J(r,_(r))})}}},"unpluginFactory");export{st as M};