luykin-vite-plugin-seo-prerender
Version:
`vite-plugin-seo-prerender` 插件是一个用于 `Vite` 构建工具的预渲染插件,它可以将你的单页面应用 (SPA) 在构建时静态预渲染为 HTML 文件,以提高首次加载速度和SEO友好性。适用于对站点少量页面生成静态HTML。支持 `Vue、React`等所有框架
10 lines (9 loc) • 5.04 kB
JavaScript
/**
* name: luykin-vite-plugin-seo-prerender
* version: 0.11.0
*/
import L from"child_process";import m from"path";import M from"fs";import*as D from"sass";import U from"puppeteer";import C from"fs";import S from"path";import y from"fs";import F from"path";var f=t=>t&&t.replace(/\\/g,"/"),u=t=>{let e=F.dirname(t);y.existsSync(e)||u(e),y.existsSync(t)||y.mkdirSync(t)};function $(t){return new Promise(e=>setTimeout(e,t))}var T=async config=>{let browser=await U.launch(Object.assign({headless:"new"},config.puppeteer||{})),page=await browser.newPage(),logTip="[vite-plugin-seo-prerender:routes]",network={};config.network&&(network={waitUntil:"networkidle0"}),config.injectScript&&await page.evaluateOnNewDocument(scriptContent=>{eval(scriptContent)},config.injectScript);for(let t of config.routes){let e=config.local+t;config.hashHistory&&(e=`${config.local}/#${t}`),await page.goto(e,network),await page.setViewport({width:1024,height:768}),await page.waitForSelector("body"),config.delay&&await $(config.delay);let o=await page.content();config.removeStyle!==!1&&(o=o.replace(/<style\b[^<]*(?:(?!<\/style>)<[^<]*)*<\/style>/gi,""));let n=new RegExp(config.local,"g");if(o=o.replace(n,""),config.callback&&(o=config.callback(o,t)||o),t.indexOf("?")!==-1)console.log(`${logTip} ${t} is error, unexpected ?`);else{let r=S.join(config.outDir,t);u(r);let s=S.join(r,"index.html");C.writeFileSync(s,o),console.log(`${logTip} ${s.replace(/\\/g,"/")} is success!`)}}await browser.close(),console.log(`${logTip} is complete`)},k=T;import p from"fs";import g from"path";var d="",H=(t,e,o)=>{let n=p.readFileSync(g.join(t,"index.html"),"utf-8");if(e==="server"){let r=/<script[^>]*?\b\/main\b[^>]*?>.*?<\/script>/gi;return(n.match(r)||[]).join(`
`)}else{let r=/<link[^>]*?rel=['|"]stylesheet['|"][^>]*?\.css[^>]*?>/gi,s=n.match(r),l=p.readFileSync(g.join(t,o||"","index.html"),"utf-8").match(r)||[],c=l;return s&&(c=l.filter(a=>!s.includes(a))),c.join(`
`).replace('"./','"/')}},x=(t,e)=>t.replace(/<!--link\shref="(.*)"-->/gi,function(o,n){let r=g.join(e,n);return p.existsSync(r)?p.readFileSync(r,{encoding:"utf8"}):o}),P=(t,e,o)=>{let r=p.readFileSync(e,"utf-8").replace("</head>",`${d}
</head>`);r=x(r,t),typeof o=="function"&&(r=o(r,e)||r),p.writeFileSync(e,r),console.log("[vite-plugin-seo-prerender:publicHtml] "+f(g.relative(t,e)))},j=(t,e,o,n)=>{if(!p.existsSync(t)){console.log(`${t}\u8DEF\u5F84\u4E0D\u5B58\u5728`);return}p.readdirSync(t).forEach(s=>{let i=g.join(t,s);p.statSync(i).isFile()&&g.extname(i)===".html"&&!f(i).endsWith(e)&&P(o,i,n),p.statSync(i).isDirectory()&&j(i,e,o,n)})},E=async t=>{let{mode:e,root:o,filePath:n,outDir:r=""}=t;if(d||(d=H(o,e,r)),e==="server"){let s=g.join(o,"public",n),i=p.readFileSync(s,"utf-8");return i=i.replace("</body>",`${d}
</body>`),i=x(i,o),typeof t.callback=="function"&&(i=t.callback(i,n)||i),i}else if(typeof n=="boolean"){let s=g.join(o,r),i=f(g.join(r,"index.html"));j(s,i,o,t.callback)}else for(let s in n){let i=g.join(o,r,n[s]);P(o,i,t.callback)}},h=E;var b=t=>{let e=[];return typeof t=="object"&&(e=t||[]),{allUrl:e,isAllUrl:typeof t=="boolean"&&t}},v=(t,e)=>{let o=m.join(t,e.entry),n=D.compile(o),r=m.join(t,e.outDir);u(m.dirname(r)),M.writeFileSync(r,n.css),console.log(`transform scss: ${e.entry} => ${e.outDir}`)},A=t=>{let e={outDir:"",mode:"",root:"",local:"",base:"",isProduction:!1,command:""},o=t.publicHtml||!1;return{name:"vitePluginSeoPrerender",enforce:"post",configResolved(n){e.outDir=n.build.outDir,e.mode=n.mode,e.root=n.root,e.base=n.base,e.isProduction=n.isProduction,e.command=n.command},buildStart(){var n;(n=t==null?void 0:t.scss)!=null&&n.length&&t.scss.forEach(r=>{v(e.root,r)})},configureServer(n){let{allUrl:r,isAllUrl:s}=b(o);(r.length||s)&&n.middlewares.use(async(i,l,c)=>{let a=decodeURIComponent(i.url.replace(e.base,"/"));if(s&&a.endsWith(".html")||r.includes(a)){let w=await h({root:e.root,filePath:a,mode:"server",callback:t.callback});if(w){l.setHeader("Content-Type","text/html"),l.end(w);return}}c()})},handleHotUpdate({file:n,server:r}){var s;if(n.endsWith(".html")){let{allUrl:i,isAllUrl:l}=b(o);if(l||i.length){let c=m.join(e.root,"public"),a=m.relative(c,n);r.ws.send({type:"full-reload",path:"/"+f(a)})}}if((s=t==null?void 0:t.scss)!=null&&s.length&&n.endsWith(".scss")){let i=f(n);t.scss.forEach(l=>{i.includes(l.entry)&&v(e.root,l)})}},async closeBundle(){var l;if(!e.isProduction)return;let{allUrl:n,isAllUrl:r}=b(o);if((r||n.length)&&await h({root:e.root,filePath:r||n,mode:"build",outDir:e.outDir,callback:t.callback}),!((l=t==null?void 0:t.routes)!=null&&l.length))return;console.log("[vite-plugin-seo-prerender:routes] is start..");let s=L.exec("vite preview",c=>{if(c){console.error("\u6267\u884C\u547D\u4EE4\u65F6\u53D1\u751F\u9519\u8BEF\uFF1A",c);return}}),i="";s.stdout.on("data",async c=>{let a=c.match(/http:\/\/(.*?)\//g);a&&a.length&&!i&&(i=a[0].replace(/\x1B\[\d+m/g,"").slice(0,-1),console.log("Local: "+i),e.local=i,await k(Object.assign(t,e)),s.kill("SIGTERM"),process.exit(),i="")})}}},et=A;export{et as default};