UNPKG

vite-plugin-seo-prerender

Version:

`vite-plugin-seo-prerender` 插件是一个用于 `Vite` 构建工具的预渲染插件,它可以将你的单页面应用 (SPA) 在构建时静态预渲染为 HTML 文件,以提高首次加载速度和SEO友好性。适用于对站点少量页面生成静态HTML。支持 `Vue、React`等所有框架

10 lines (9 loc) 4.87 kB
/** * name: vite-plugin-seo-prerender * version: 1.0.0 */ import R from"child_process";import g from"path";import A from"fs";import*as U from"sass";import $ from"puppeteer";import C from"fs";import k from"path";import h from"fs";import F from"path";var u=t=>t&&t.replace(/\\/g,"/"),f=t=>{let e=F.dirname(t);h.existsSync(e)||f(e),h.existsSync(t)||h.mkdirSync(t)};import{URL as H}from"url";function T(t){return new Promise(e=>setTimeout(e,t))}var L=async t=>{let e=await $.launch(Object.assign({headless:"new"},t.puppeteer||{})),o=await e.newPage(),r="[vite-plugin-seo-prerender:routes]",s={};t.network&&(s={waitUntil:"networkidle0"});let i=new H(t.base,t.local).toString().slice(0,-1);for(let n of t.routes){let a=i+n;t.hashHistory&&(a=`${i}/#${n}`),await o.goto(a,s),await o.setViewport({width:1024,height:768}),await o.waitForSelector("body"),t.delay&&await T(t.delay);let l=await o.content();t.removeStyle!==!1&&(l=l.replace(/<style\b[^<]*(?:(?!<\/style>)<[^<]*)*<\/style>/gi,""));let c=new RegExp(t.local,"g");if(l=l.replace(c,""),t.callback&&(l=t.callback(l,n)||l),n.indexOf("?")!==-1)console.log(`${r} ${n} is error,unexpected?`);else{let d=k.join(t.outDir,n);f(d);let S=k.join(d,"index.html");C.writeFileSync(S,l),console.log(`${r} ${a.replace(t.local,"")} => ${S.replace(/\\/g,"/")} is success!`)}}await e.close(),console.log(`${r} is complete`)},x=L;import p from"fs";import m from"path";var y="",E=(t,e,o)=>{let r=p.readFileSync(m.join(t,"index.html"),"utf-8");if(e==="server"){let s=/<script[^>]*?\b\/main\b[^>]*?>.*?<\/script>/gi;return(r.match(s)||[]).join(` `)}else{let s=/<link[^>]*?rel=['|"]stylesheet['|"][^>]*?\.css[^>]*?>/gi,i=r.match(s),a=p.readFileSync(m.join(t,o||"","index.html"),"utf-8").match(s)||[],l=a;return i&&(l=a.filter(c=>!i.includes(c))),l.join(` `).replace('"./','"/')}},P=(t,e)=>t.replace(/<!--link\shref="(.*)"-->/gi,function(o,r){let s=m.join(e,r);return p.existsSync(s)?p.readFileSync(s,{encoding:"utf8"}):o}),v=(t,e,o)=>{let s=p.readFileSync(e,"utf-8").replace("</head>",`${y} </head>`);s=P(s,t),typeof o=="function"&&(s=o(s,e)||s),p.writeFileSync(e,s),console.log("[vite-plugin-seo-prerender:publicHtml] "+u(m.relative(t,e)))},j=(t,e,o,r)=>{if(!p.existsSync(t)){console.log(`${t}\u8DEF\u5F84\u4E0D\u5B58\u5728`);return}p.readdirSync(t).forEach(i=>{let n=m.join(t,i);p.statSync(n).isFile()&&m.extname(n)===".html"&&!u(n).endsWith(e)&&v(o,n,r),p.statSync(n).isDirectory()&&j(n,e,o,r)})},M=async t=>{let{mode:e,root:o,filePath:r,outDir:s=""}=t;if(y||(y=E(o,e,s)),e==="server"){let i=m.join(o,"public",r),n=p.readFileSync(i,"utf-8");return n=n.replace("</body>",`${y} </body>`),n=P(n,o),typeof t.callback=="function"&&(n=t.callback(n,r)||n),n}else if(typeof r=="boolean"){let i=m.join(o,s),n=u(m.join(s,"index.html"));j(i,n,o,t.callback)}else for(let i in r){let n=m.join(o,s,r[i]);v(o,n,t.callback)}},b=M;var w=t=>{let e=[];return typeof t=="object"&&(e=t||[]),{allUrl:e,isAllUrl:typeof t=="boolean"&&t}},D=(t,e)=>{let o=g.join(t,e.entry),r=U.compile(o),s=g.join(t,e.outDir);f(g.dirname(s)),A.writeFileSync(s,r.css),console.log(`transform scss: ${e.entry} => ${e.outDir}`)},W=t=>{let e={outDir:"",mode:"",root:"",local:"",base:"",isProduction:!1,command:""},o=t.publicHtml||!1;return{name:"vitePluginSeoPrerender",enforce:"post",configResolved(r){e.outDir=r.build.outDir,e.mode=r.mode,e.root=r.root,e.base=r.base,e.isProduction=r.isProduction,e.command=r.command},buildStart(){var r;(r=t==null?void 0:t.scss)!=null&&r.length&&t.scss.forEach(s=>{D(e.root,s)})},configureServer(r){let{allUrl:s,isAllUrl:i}=w(o);(s.length||i)&&r.middlewares.use(async(n,a,l)=>{let c=decodeURIComponent(n.url.replace(e.base,"/"));if(i&&c.endsWith(".html")||s.includes(c)){let d=await b({root:e.root,filePath:c,mode:"server",callback:t.callback});if(d){a.setHeader("Content-Type","text/html"),a.end(d);return}}l()})},handleHotUpdate({file:r,server:s}){var i;if(r.endsWith(".html")){let{allUrl:n,isAllUrl:a}=w(o);if(a||n.length){let l=g.join(e.root,"public"),c=g.relative(l,r);s.ws.send({type:"full-reload",path:"/"+u(c)})}}if((i=t==null?void 0:t.scss)!=null&&i.length&&r.endsWith(".scss")){let n=u(r);t.scss.forEach(a=>{n.includes(a.entry)&&D(e.root,a)})}},async closeBundle(){var a;if(!e.isProduction)return;let{allUrl:r,isAllUrl:s}=w(o);if((s||r.length)&&await b({root:e.root,filePath:s||r,mode:"build",outDir:e.outDir,callback:t.callback}),!((a=t==null?void 0:t.routes)!=null&&a.length))return;console.log("[vite-plugin-seo-prerender:routes] is start..");let i=R.exec("vite preview",l=>{if(l){console.error("\u6267\u884C\u547D\u4EE4\u65F6\u53D1\u751F\u9519\u8BEF\uFF1A",l);return}}),n="";i.stdout.on("data",async l=>{let c=l.match(/http:\/\/(.*?)\//g);c&&c.length&&!n&&(n=c[0].replace(/\x1B\[\d+m/g,"").slice(0,-1),console.log("Local: "+n),e.local=n,await x(Object.assign(t,e)),i.kill("SIGTERM"),process.exit(),n="")})}}},st=W;export{st as default};