@fchc8/vite-plugin-multi-page 2.1.0 → 2.2.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/build-config-TPFCXXIR.mjs +2 -0
- package/dist/chunk-3Q23JRUZ.mjs +2 -0
- package/dist/cli.mjs +28 -0
- package/dist/config-loader-5G3KL6TE.mjs +2 -0
- package/dist/defaults-A5TQPXKR.mjs +2 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +2 -2
- package/dist/index.mjs.map +1 -1
- package/package.json +2 -2
- package/dist/cli.js +0 -28
- package/dist/index.d.mts +0 -74
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import{mergeConfig as A}from"vite";import{glob as j}from"glob";import*as u from"path";import*as C from"fs";import*as x from"path";function $(r,e,l,i){let n=[],f=new Map,g=e.replace(/\/\*.*$/,"");(!g||g===e)&&(g=x.dirname(e.split("*")[0]));let o=[];for(let t of r){if(l.includes(t))continue;let c=t.replace(/\\/g,"/"),m=g.replace(/\\/g,"/"),P=x.posix.relative(m,c).split("/");if(P.length===1){let s=P[0],d=x.posix.basename(s,x.posix.extname(s));o.push({name:d,file:t,priority:1})}else if(P.length>=2){let s=x.posix.basename(c,x.posix.extname(c)),d=P[0];s==="main"&&o.push({name:d,file:t,priority:2})}}for(let t of o){let c=f.get(t.name);c?t.priority>c.priority&&f.set(t.name,{file:t.file,priority:t.priority}):f.set(t.name,{file:t.file,priority:t.priority})}for(let[t,{file:c}]of f.entries())n.push({name:t,file:c});return n}function v(r,e,l){if(!r)return null;if(typeof r=="function")return r(e);for(let[i,n]of Object.entries(r)){if(i===e.pageName)return l(`\u7CBE\u786E\u5339\u914D\u9875\u9762 ${e.pageName}:`,n),n;if(n.match&&(Array.isArray(n.match)?n.match:[n.match]).some(o=>O(o,e.pageName)||O(o,e.relativePath)||O(o,e.filePath)))return l(`\u6A21\u5F0F\u5339\u914D\u9875\u9762 ${e.pageName} (\u6A21\u5F0F: ${n.match}):`,n),{...n,match:void 0};if(O(i,e.pageName))return l(`Glob\u5339\u914D\u9875\u9762 ${e.pageName} (\u6A21\u5F0F: ${i}):`,n),n}return null}function O(r,e){let l=r.replace(/\*\*/g,"__DOUBLE_STAR__").replace(/\*/g,"[^/]*").replace(/__DOUBLE_STAR__/g,".*");return new RegExp(`^${l}$`).test(e)}function F(r){return(...e)=>{r&&console.log("[vite-plugin-multi-page]",...e)}}async function q(r){let{entry:e="src/pages/*/main.{ts,js}",exclude:l=[],template:i="index.html",placeholder:n="<!--VITE_MULTI_PAGE_ENTRY-->",strategies:f={},pageConfigs:g={},forceBuildStrategy:o}=r,t=F(!0),c={};try{let m=j.sync(e,{cwd:process.cwd()}),p=$(m,e,l,t);if(p.length===0)return t("\u8B66\u544A: \u672A\u627E\u5230\u5339\u914D\u7684\u5165\u53E3\u6587\u4EF6"),{};let P=new Map,s=new Map;for(let a of p){let h={pageName:a.name,filePath:a.file,relativePath:u.relative(process.cwd(),a.file)},y=v(g,h,t)?.strategy||"default";P.set(a.name,y),s.has(y)||s.set(y,[]),s.get(y)?.push(a.name)}if(t(`\u{1F4C4} \u53D1\u73B0 ${p.length} \u4E2A\u9875\u9762: ${p.map(a=>a.name).join(", ")}`),o){let a=s.get(o)||[];if(a.length===0)return t(`\u8B66\u544A: \u7B56\u7565 "${o}" \u4E0B\u6CA1\u6709\u9875\u9762`),{};t(`\u5F3A\u5236\u6784\u5EFA\u7B56\u7565: ${o}, \u9875\u9762: ${a.join(", ")}`);let h=await _(o,a,p,f[o],g,i,n,t);return c[o]=h,c}for(let[a,h]of s){if(h.length===0)continue;let w=f[a]||{},y=await _(a,h,p,w,g,i,n,t);c[a]=y}if(Object.keys(c).length===0){t("\u8B66\u544A: \u672A\u751F\u6210\u4EFB\u4F55\u6784\u5EFA\u914D\u7F6E\uFF0C\u521B\u5EFA\u9ED8\u8BA4\u914D\u7F6E");let a=p.map(w=>w.name),h=await _("default",a,p,{},g,i,n,t);c.default=h}let d=Object.keys(c);return t(`\u{1F4E6} \u6784\u5EFA\u7B56\u7565: ${d.join(", ")}`),c}catch(m){throw t("\u751F\u6210\u6784\u5EFA\u914D\u7F6E\u5931\u8D25:",m),m}}async function _(r,e,l,i,n,f,g,o){let t={},c=[],m={};for(let d of e){let a=l.find(S=>S.name===d);if(!a)continue;let h={pageName:d,filePath:a.file,relativePath:u.relative(process.cwd(),a.file),strategy:r},w=v(n,h,o);w?.define&&Object.assign(m,w.define);let y=f,R=`${d}.html`;C.existsSync(u.resolve(process.cwd(),R))?y=R:w?.template&&(y=w.template);let U=u.resolve(process.cwd(),y);if(!C.existsSync(U)){o(`\u8B66\u544A: \u6A21\u677F\u6587\u4EF6\u4E0D\u5B58\u5728: ${y}`);continue}let b=C.readFileSync(U,"utf-8");if(b.includes(g)){let S=`./${a.file}`;b=b.replace(new RegExp(g.replace(/[.*+?^${}()|[\]\\]/g,"\\$&"),"g"),S)}let N=u.resolve(process.cwd(),`.temp.mp.${d}.html`);C.writeFileSync(N,b),c.push(N),t[d]=N}let p={input:t,output:{entryFileNames:"assets/[name]-[hash].js",chunkFileNames:"assets/[name]-[hash].js",assetFileNames:"assets/[name]-[hash][extname]"}},P={base:"./",build:{outDir:`dist/${r}`,rollupOptions:p,rolldownOptions:p,emptyOutDir:!1},define:{}},s=P;return i&&(s=A(P,i)),Object.keys(m).length>0&&(s.define={...s.define,...m}),s.build||(s.build={}),s.build.rollupOptions||(s.build.rollupOptions={}),s.build.rolldownOptions||(s.build.rolldownOptions={}),s.build.rollupOptions.input=t,s.build.rolldownOptions.input=t,s.build.emptyOutDir=!1,o(`\u7B56\u7565 "${r}" - ${e.length} \u4E2A\u9875\u9762`),s}function M(r=[]){let e=r.findIndex(i=>i==="--outDir");if(e!==-1&&e+1<r.length){let i=r[e+1];return u.resolve(process.cwd(),i)}let l=r.find(i=>i.startsWith("--outDir="));if(l){let i=l.split("=")[1];return u.resolve(process.cwd(),i)}return u.resolve(process.cwd(),"dist")}function J(r=[]){let e=M(r),l=F(!0);try{C.existsSync(e)&&(C.rmSync(e,{recursive:!0,force:!0}),l(`\u{1F9F9} \u6E05\u7406\u8F93\u51FA\u76EE\u5F55: ${u.relative(process.cwd(),e)}`))}catch(i){l(`\u26A0\uFE0F \u6E05\u7406\u8F93\u51FA\u76EE\u5F55\u5931\u8D25: ${e}`,i)}}function K(r){let{entry:e="src/pages/*/main.{ts,js}",exclude:l=[]}=r,i=F(!0);try{let n=j.sync(e,{cwd:process.cwd()});return $(n,e,l,i)}catch(n){throw i("\u53D1\u73B0\u9875\u9762\u5931\u8D25:",n),n}}function Q(r){let{entry:e="src/pages/*/main.{ts,js}",exclude:l=[],pageConfigs:i={}}=r,n=F(!1),f=new Set,g=j.sync(e,{cwd:process.cwd()}),o=$(g,e,l,n);if(o.length===0)throw new Error(`\u672A\u627E\u5230\u5339\u914D\u7684\u5165\u53E3\u6587\u4EF6: ${e}`);try{for(let t of o){let c={pageName:t.name,filePath:t.file,relativePath:u.relative(process.cwd(),t.file)},p=v(i,c,n)?.strategy||"default";f.add(p)}return Array.from(f).sort()}catch(t){return n("\u83B7\u53D6\u53EF\u7528\u7B56\u7565\u5931\u8D25:",t),["default"]}}export{q as a,M as b,J as c,K as d,Q as e};
|
package/dist/cli.mjs
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import{b as x}from"./chunk-3Q23JRUZ.mjs";import{spawn as D}from"child_process";import*as s from"fs";import*as i from"path";import*as S from"glob";import{fileURLToPath as F}from"url";function C(){let c=process.argv.slice(2),h=[],t=!1,l,u,m=3,d=!0;for(let a=0;a<c.length;a++){let e=c[a];if(e==="--debug")t=!0;else if(e==="--cwd")l=c[++a];else if(e==="--strategy")u=c[++a].split(",").map(f=>f.trim());else if(e==="--concurrency"){let o=c[++a];m=parseInt(o,10),(isNaN(m)||m<1)&&(console.error("\u274C \u5E76\u53D1\u6570\u5FC5\u987B\u662F\u5927\u4E8E0\u7684\u6574\u6570"),process.exit(1))}else e==="--flatten"?d=!0:e==="--no-flatten"?d=!1:e==="--help"||e==="-h"?(console.log(`
|
|
3
|
+
\u4F7F\u7528\u65B9\u6CD5: vite-mp [\u9009\u9879]
|
|
4
|
+
|
|
5
|
+
\u9009\u9879:
|
|
6
|
+
--debug \u542F\u7528\u8C03\u8BD5\u6A21\u5F0F
|
|
7
|
+
--cwd <dir> \u6307\u5B9A\u5DE5\u4F5C\u76EE\u5F55
|
|
8
|
+
--strategy <list> \u6307\u5B9A\u6784\u5EFA\u7B56\u7565\uFF0C\u652F\u6301\u9017\u53F7\u5206\u9694\u591A\u4E2A\u7B56\u7565
|
|
9
|
+
--concurrency <num> \u5E76\u53D1\u6784\u5EFA\u6570\uFF08\u9ED8\u8BA4\uFF1A3\uFF09
|
|
10
|
+
--flatten \u6241\u5E73\u5316\u8F93\u51FA\u7ED3\u6784\uFF08\u9ED8\u8BA4\u542F\u7528\uFF09
|
|
11
|
+
--no-flatten \u7981\u7528\u6241\u5E73\u5316\u8F93\u51FA\u7ED3\u6784
|
|
12
|
+
--help, -h \u663E\u793A\u5E2E\u52A9\u4FE1\u606F
|
|
13
|
+
|
|
14
|
+
\u5176\u4ED6\u6240\u6709\u53C2\u6570\u5C06\u4F20\u9012\u7ED9 vite build \u547D\u4EE4
|
|
15
|
+
|
|
16
|
+
\u793A\u4F8B:
|
|
17
|
+
vite-mp # \u6784\u5EFA\u6240\u6709\u7B56\u7565\uFF08\u9ED8\u8BA4\u6241\u5E73\u5316\uFF09
|
|
18
|
+
vite-mp --strategy mobile # \u53EA\u6784\u5EFAmobile\u7B56\u7565
|
|
19
|
+
vite-mp --strategy mobile,tablet # \u6784\u5EFAmobile\u548Ctablet\u7B56\u7565
|
|
20
|
+
vite-mp --no-flatten # \u7981\u7528\u6241\u5E73\u5316\u8F93\u51FA\u7ED3\u6784
|
|
21
|
+
vite-mp --concurrency 2 # \u8BBE\u7F6E\u5E76\u53D1\u6570\u4E3A2
|
|
22
|
+
vite-mp --debug # \u542F\u7528\u8C03\u8BD5\u6A21\u5F0F
|
|
23
|
+
vite-mp --cwd example # \u5728example\u76EE\u5F55\u8FD0\u884C
|
|
24
|
+
vite-mp --mode production --debug # \u4F20\u9012\u989D\u5916\u53C2\u6570\u7ED9vite
|
|
25
|
+
`),process.exit(0)):e!=="build"&&h.push(e)}return{viteBuildArgs:h,debug:t,cwd:l,strategies:u,concurrency:m,flatten:d}}async function T(){let{loadUserConfig:c,hasCustomConfig:h}=await import("./config-loader-5G3KL6TE.mjs"),{mergeWithDefaults:t}=await import("./defaults-A5TQPXKR.mjs"),l=null;return h()&&(l=await c({mode:"production",command:"build",isCLI:!0}),l||console.log("\u274C \u914D\u7F6E\u6587\u4EF6\u52A0\u8F7D\u5931\u8D25")),t(l)}function A(c,h,t){return new Promise(l=>{let u=t?console.log.bind(console,`[${c}]`):()=>{},m={...process.env,VITE_MULTI_PAGE_STRATEGY:c},d=["build",...h],a=D("npx",["vite",...d],{stdio:t?"inherit":"pipe",env:m,cwd:process.cwd(),shell:process.platform==="win32"}),e="";t||a.stderr?.on("data",o=>{e+=o.toString()}),a.on("close",o=>{let f=o===0,r=i.resolve(process.cwd(),"dist",c);if(f)try{if(s.existsSync(r)){let p=s.readdirSync(r);for(let g of p)if(g.startsWith(".temp.mp.")&&g.endsWith(".html")){let n=i.resolve(r,g),v=`${g.replace(/^\.temp\.mp\./,"").replace(/\.html$/,"")}.html`,$=i.resolve(r,v);s.renameSync(n,$)}}}catch(p){u("\u91CD\u547D\u540DHTML\u6587\u4EF6\u5931\u8D25:",p)}else!t&&e&&console.error(`\u7B56\u7565 ${c} \u9519\u8BEF\u8F93\u51FA:`,e);l({strategy:c,success:f,error:f?void 0:e||`\u6784\u5EFA\u5931\u8D25\uFF0C\u9000\u51FA\u7801: ${o}`,outputDir:r})}),a.on("error",o=>{u(`\u274C \u7B56\u7565 ${c} \u6784\u5EFA\u51FA\u9519:`,o.message);let f=x(h);l({strategy:c,success:!1,error:o.message,outputDir:f})})})}async function E(c){let h=S.sync(".temp.mp.*.html",{cwd:process.cwd()});for(let t of h){let l=i.resolve(process.cwd(),t);try{s.unlinkSync(l)}catch{}}}async function N(c,h){let t=h?console.log.bind(console,"[flatten]"):()=>{},l=i.resolve(process.cwd(),"dist");if(!s.existsSync(l))return;t("\u5F00\u59CB\u6241\u5E73\u5316\u8F93\u51FA\u7ED3\u6784...");let u=[];for(let e of c){let o=i.resolve(l,e);if(s.existsSync(o)){let f=s.readdirSync(o);for(let r of f)if(r.endsWith(".html")){let p=i.resolve(o,r),g=i.resolve(l,r),n=s.existsSync(g)?i.resolve(l,`${e}-${r}`):g;s.renameSync(p,n),u.push(i.basename(n)),t(`\u79FB\u52A8HTML: ${e}/${r} -> ${i.basename(n)}`)}}}let m=i.resolve(l,"assets");if(s.existsSync(m)){let e=i.resolve(l,"assets-backup");s.existsSync(e)&&s.rmSync(e,{recursive:!0}),s.renameSync(m,e)}s.mkdirSync(m,{recursive:!0});let d=new Set;for(let e of c){let o=i.resolve(l,e);if(s.existsSync(o)){let f=i.resolve(o,"assets");if(s.existsSync(f)){let r=s.readdirSync(f);for(let p of r){let g=i.resolve(f,p),n=i.resolve(m,p);if(!d.has(p))s.renameSync(g,n),d.add(p),t(`\u79FB\u52A8\u8D44\u6E90: ${e}/assets/${p} -> assets/${p}`);else{let y=s.readFileSync(g),v=s.readFileSync(n);if(y.equals(v))s.unlinkSync(g),t(`\u5220\u9664\u91CD\u590D\u8D44\u6E90: ${e}/assets/${p} (\u5185\u5BB9\u76F8\u540C)`);else{let $=i.parse(p).name,b=i.parse(p).ext,w=`${$}-${e}${b}`,P=i.resolve(m,w);s.renameSync(g,P),t(`\u79FB\u52A8\u8D44\u6E90: ${e}/assets/${p} -> assets/${w} (\u5185\u5BB9\u4E0D\u540C)`)}}}}}}let a=new Set;for(let e of c){let o=i.resolve(l,e);if(s.existsSync(o)){let f=s.readdirSync(o);for(let r of f)if(!r.endsWith(".html")&&r!=="assets"){let p=i.resolve(o,r),g=i.resolve(l,r);s.statSync(p).isDirectory()?a.has(r)?(s.rmSync(p,{recursive:!0}),t(`\u5220\u9664\u91CD\u590D\u76EE\u5F55: ${e}/${r}`)):(s.existsSync(g)&&s.rmSync(g,{recursive:!0}),s.renameSync(p,g),a.add(r),t(`\u79FB\u52A8\u76EE\u5F55: ${e}/${r} -> ${r}`)):a.has(r)?(s.unlinkSync(p),t(`\u5220\u9664\u91CD\u590D\u6587\u4EF6: ${e}/${r}`)):(s.renameSync(p,g),a.add(r),t(`\u79FB\u52A8\u6587\u4EF6: ${e}/${r} -> ${r}`))}}}for(let e of u){let o=i.resolve(l,e);if(s.existsSync(o)){let f=s.readFileSync(o,"utf-8"),r="default";e==="mobile.html"?r="mobile":e==="tablet.html"?r="tablet":e.startsWith("mobile-")?r="mobile":e.startsWith("tablet-")&&(r="tablet");let p=i.resolve(l,"assets");if(s.existsSync(p)){let g=s.readdirSync(p);for(let n of g)if(n.includes(`-${r}`)){let v=n.replace(`-${r}`,"").replace(/[.*+?^${}()|[\]\\]/g,"\\$&"),$=new RegExp(`\\./assets/${v}(?=\\s|>|"|')`,"g");f=f.replace($,`./assets/${n}`)}}s.writeFileSync(o,f),t(`\u66F4\u65B0\u8D44\u6E90\u8DEF\u5F84: ${e} -> assets/`)}}for(let e of c){let o=i.resolve(l,e);if(s.existsSync(o))try{s.rmSync(o,{recursive:!0}),t(`\u5220\u9664\u7B56\u7565\u76EE\u5F55: ${e}`)}catch(f){t(`\u5220\u9664\u7B56\u7565\u76EE\u5F55\u5931\u8D25: ${e}`,f)}}t("\u6241\u5E73\u5316\u5B8C\u6210")}async function O(c,h){let t=h?console.log.bind(console,"[cleanup]"):()=>{},l=S.sync(".temp.mp.*.html",{cwd:process.cwd()});for(let u of l){let m=i.resolve(process.cwd(),u);try{s.unlinkSync(m)}catch(d){t(`\u5220\u9664\u6839\u76EE\u5F55\u4E34\u65F6\u6587\u4EF6\u5931\u8D25: ${u}`,d)}}for(let u of c){let m=i.resolve(process.cwd(),"dist",u);if(s.existsSync(m)){let d=S.sync("*.mp.temp.html",{cwd:m});for(let a of d){let e=i.resolve(m,a);try{s.unlinkSync(e)}catch(o){t(`\u5220\u9664\u7B56\u7565\u76EE\u5F55\u4E34\u65F6\u6587\u4EF6\u5931\u8D25: ${u}/${a}`,o)}}}}}async function R(){let{viteBuildArgs:c,debug:h,cwd:t,strategies:l,concurrency:u,flatten:m}=C(),d=h?console.log.bind(console,"[main]"):()=>{};if(t){let a=i.resolve(process.cwd(),t);s.existsSync(a)||(console.error(`\u274C \u6307\u5B9A\u7684\u76EE\u5F55\u4E0D\u5B58\u5728: ${a}`),process.exit(1)),process.chdir(a),d(`\u5207\u6362\u5DE5\u4F5C\u76EE\u5F55\u5230: ${a}`)}try{let a=await T(),{cleanViteOutputDirectory:e}=await import("./build-config-TPFCXXIR.mjs");e(c),await W(a,c,h,l,u,m)}catch(a){console.error("\u274C \u6784\u5EFA\u5931\u8D25:",a instanceof Error?a.message:a),process.exit(1)}}async function W(c,h,t,l,u=3,m=!1){let d=t?console.log.bind(console,"[strategy-mode]"):()=>{},{getAvailableStrategies:a}=await import("./build-config-TPFCXXIR.mjs"),e=a({entry:c.entry||"src/pages/*/main.{ts,js}",exclude:c.exclude||[],template:c.template||"index.html",placeholder:c.placeholder||"{{ENTRY_FILE}}",pageConfigs:c.pageConfigs||{},strategies:c.strategies||{}});if(e.length===0)throw new Error("\u672A\u627E\u5230\u4EFB\u4F55\u6784\u5EFA\u7B56\u7565");let o;if(l&&l.length>0){let n=l.filter(y=>!e.includes(y));if(n.length>0)throw new Error(`\u6307\u5B9A\u7684\u7B56\u7565\u4E0D\u5B58\u5728: ${n.join(", ")}
|
|
26
|
+
\u53EF\u7528\u7B56\u7565: ${e.join(", ")}`);o=l}else o=e;d(`\u{1F680} \u5F00\u59CB\u6784\u5EFA\u7B56\u7565: ${o.join(", ")} (\u5E76\u53D1\u6570: ${u})`);let f=[];for(let n=0;n<o.length;n+=u){let y=o.slice(n,n+u),v=y.map(b=>A(b,h,t)),$=await Promise.all(v);f.push(...$),t&&d(`\u6279\u6B21 ${Math.floor(n/u)+1} \u5B8C\u6210: ${y.join(", ")}`)}let r=f.filter(n=>n.success).length;f.length-r>0&&(console.log(`
|
|
27
|
+
\u274C \u6784\u5EFA\u5931\u8D25:`),f.filter(n=>!n.success).forEach(n=>{console.log(` - ${n.strategy}: ${n.error}`)}),await E(t),process.exit(1)),m&&await N(o,t),await O(o,t);let g=f.filter(n=>n.success);if(console.log(`
|
|
28
|
+
\u{1F389} \u6784\u5EFA\u6210\u529F\uFF01`),console.log(`\u{1F4E6} \u7B56\u7565: ${g.map(n=>n.strategy).join(", ")}`),m){console.log("\u{1F4C1} \u8F93\u51FA\u7ED3\u6784: \u6241\u5E73\u5316");let n=i.resolve(process.cwd(),"dist");if(s.existsSync(n)){let y=s.readdirSync(n).filter(v=>v.endsWith(".html"));console.log(` - HTML\u6587\u4EF6: ${y.join(", ")}`)}}else for(let n of g){let y=i.resolve(process.cwd(),"dist",n.strategy);if(s.existsSync(y)){let v=s.readdirSync(y).filter($=>$.endsWith(".html"));console.log(` - ${n.strategy}: ${v.join(", ")}`)}}}var j=F(import.meta.url);j===i.resolve(process.argv[1])&&R().catch(c=>{console.error("\u274C \u672A\u5904\u7406\u7684\u9519\u8BEF:",c),process.exit(1)});export{R as buildAll};
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import*as i from"fs";import*as r from"path";import{pathToFileURL as f}from"url";import{createJiti as u}from"jiti";var c=["multipage.config.ts","multipage.config.js","multipage.config.mjs"];function d(){for(let o of c){let t=r.resolve(process.cwd(),o);if(i.existsSync(t))return!0}return!1}async function y(o){let t=await l();if(t){let n=t(o);return n||{}}return null}async function a(o){if(o.endsWith(".ts"))return u(import.meta.url,{interopDefault:!0}).import(o);if(o.endsWith(".js")||o.endsWith(".mjs"))return import(`${f(o).href}?t=${Date.now()}`);throw new Error(`\u4E0D\u652F\u6301\u7684\u914D\u7F6E\u6587\u4EF6\u7C7B\u578B: ${o}`)}async function l(){let o=process.cwd();for(let t of c){let n=r.resolve(o,t);if(i.existsSync(n))try{let e=await a(n),s=e.default||e;if(typeof s=="function")return s;console.warn(`\u914D\u7F6E\u6587\u4EF6 ${t} \u5FC5\u987B\u9ED8\u8BA4\u5BFC\u51FA\u4E00\u4E2A\u51FD\u6570`)}catch(e){console.error(`\u52A0\u8F7D\u914D\u7F6E\u6587\u4EF6 ${t} \u5931\u8D25:`,e)}}return null}export{d as hasCustomConfig,y as loadUserConfig};
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
var t={entry:"src/pages/**/*.{ts,js}",exclude:[],template:"index.html",placeholder:"{{ENTRY_FILE}}",debug:!1,strategies:{default:{}},pageConfigs:{}};function p(e){if(!e)return{...t};let a=e.strategies??e.buildStrategies??t.strategies;return{entry:e.entry??t.entry,exclude:e.exclude??t.exclude,template:e.template??t.template,placeholder:e.placeholder??t.placeholder,debug:e.debug??t.debug,strategies:a,pageConfigs:e.pageConfigs??t.pageConfigs,__forceBuildStrategy:e.__forceBuildStrategy}}function g(e){if(Object.keys(e).length===0)return!0;let a=e.entry&&e.entry!==t.entry,l=e.strategies&&Object.keys(e.strategies).length>0||e.buildStrategies&&Object.keys(e.buildStrategies).length>0,s=e.pageConfigs&&(typeof e.pageConfigs=="function"||Object.keys(e.pageConfigs).length>0);return!a&&!l&&!s}export{t as DEFAULT_CONFIG,g as isEmptyConfig,p as mergeWithDefaults};
|
package/dist/index.d.ts
CHANGED
|
@@ -52,7 +52,7 @@ declare function defineConfigTransform(transform: ConfigTransformFunction): Conf
|
|
|
52
52
|
* 构建时配置生成器
|
|
53
53
|
* 根据策略和页面配置生成多页面构建配置
|
|
54
54
|
*/
|
|
55
|
-
declare function generateBuildConfig(options: BuildConfigOptions): Record<string, UserConfig
|
|
55
|
+
declare function generateBuildConfig(options: BuildConfigOptions): Promise<Record<string, UserConfig>>;
|
|
56
56
|
/**
|
|
57
57
|
* 获取Vite配置的输出目录
|
|
58
58
|
* 需要传入已解析的Vite配置或命令行参数
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
"use strict";var ae=Object.create;var
|
|
1
|
+
"use strict";var ae=Object.create;var j=Object.defineProperty;var ge=Object.getOwnPropertyDescriptor;var le=Object.getOwnPropertyNames;var ce=Object.getPrototypeOf,pe=Object.prototype.hasOwnProperty;var fe=(t,e)=>{for(var r in e)j(t,r,{get:e[r],enumerable:!0})},z=(t,e,r,o)=>{if(e&&typeof e=="object"||typeof e=="function")for(let i of le(e))!pe.call(t,i)&&i!==r&&j(t,i,{get:()=>e[i],enumerable:!(o=ge(e,i))||o.enumerable});return t};var w=(t,e,r)=>(r=t!=null?ae(ce(t)):{},z(e||!t||!t.__esModule?j(r,"default",{value:t,enumerable:!0}):r,t)),de=t=>z(j({},"__esModule",{value:!0}),t);var Pe={};fe(Pe,{cleanViteOutputDirectory:()=>X,default:()=>be,defineConfig:()=>ie,defineConfigTransform:()=>re,generateBuildConfig:()=>D,getAvailableStrategies:()=>Z,getViteOutputDirectory:()=>k,mergeWithDefaults:()=>_,viteMultiPage:()=>se});module.exports=de(Pe);var ue=()=>typeof document>"u"?new URL(`file:${__filename}`).href:document.currentScript&&document.currentScript.src||new URL("main.js",document.baseURI).href,x=ue();var oe=require("vite");var b=w(require("path")),E=w(require("fs")),q=require("glob");var S=w(require("path"));function F(t,e,r,o){let i=[],l=new Map,g=e.replace(/\/\*.*$/,"");(!g||g===e)&&(g=S.dirname(e.split("*")[0]));let s=[];for(let n of t){if(r.includes(n))continue;let a=n.replace(/\\/g,"/"),c=g.replace(/\\/g,"/"),u=S.posix.relative(c,a).split("/");if(u.length===1){let p=u[0],m=S.posix.basename(p,S.posix.extname(p));s.push({name:m,file:n,priority:1})}else if(u.length>=2){let p=S.posix.basename(a,S.posix.extname(a)),m=u[0];p==="main"&&s.push({name:m,file:n,priority:2})}}for(let n of s){let a=l.get(n.name);a?n.priority>a.priority&&l.set(n.name,{file:n.file,priority:n.priority}):l.set(n.name,{file:n.file,priority:n.priority})}for(let[n,{file:a}]of l.entries())i.push({name:n,file:a});return i}function J(t){return t.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}function R(t){return(...e)=>{t&&console.log("[vite-plugin-multi-page]",...e)}}function O(t,e,r){if(!t)return null;if(typeof t=="function")return t(e);for(let[o,i]of Object.entries(t)){if(o===e.pageName)return r(`\u7CBE\u786E\u5339\u914D\u9875\u9762 ${e.pageName}:`,i),i;if(i.match&&(Array.isArray(i.match)?i.match:[i.match]).some(s=>I(s,e.pageName)||I(s,e.relativePath)||I(s,e.filePath)))return r(`\u6A21\u5F0F\u5339\u914D\u9875\u9762 ${e.pageName} (\u6A21\u5F0F: ${i.match}):`,i),{...i,match:void 0};if(I(o,e.pageName))return r(`Glob\u5339\u914D\u9875\u9762 ${e.pageName} (\u6A21\u5F0F: ${o}):`,i),i}return null}function I(t,e){let r=t.replace(/\*\*/g,"__DOUBLE_STAR__").replace(/\*/g,"[^/]*").replace(/__DOUBLE_STAR__/g,".*");return new RegExp(`^${r}$`).test(e)}function me(t,e,r){try{let o=q.glob.sync(e.entry,{cwd:process.cwd()}),i=F(o,e.entry,e.exclude,r);if(i.length===0){r("\u8B66\u544A: \u672A\u627E\u5230\u5339\u914D\u7684\u5165\u53E3\u6587\u4EF6");return}let l=e.devStrategy||t.config.__cliStrategy||t.config.strategy;l&&(r(`\u5F00\u53D1\u670D\u52A1\u5668\u4F7F\u7528\u6307\u5B9A\u7684\u7B56\u7565: ${l}`),i=i.filter(g=>{let s={pageName:g.name,filePath:g.file,relativePath:b.relative(process.cwd(),g.file),strategy:void 0,isMatched:!1},a=O(e.pageConfigs,s,r)?.strategy||"default";return l==="default"?a==="default":a===l}),r(`\u7B56\u7565 "${l}" \u4E0B\u53EF\u7528\u7684\u9875\u9762: ${i.map(g=>g.name).join(", ")||"\u65E0"}`)),r("\u5F00\u53D1\u670D\u52A1\u5668\u5E94\u7528\u7684\u5165\u53E3\u6587\u4EF6:",i),t.middlewares.use(async(g,s,n)=>{try{let c=(g.url||"").split("?")[0];if(c==="/"){let p=he(i,e,r);s.statusCode=200,s.setHeader("Content-Type","text/html"),s.end(p);return}if(c.match(/\.(js|css|png|jpg|jpeg|gif|svg|ico|woff|woff2|ttf|eot|map)$/)&&!c.endsWith(".html")||c.startsWith("/@")||c.includes("__vite")||c.startsWith("/node_modules"))return n();let d="";if(c.endsWith(".html"))d=b.basename(c,".html");else if(c.startsWith("/")){let p=c.substring(1);if(i.find(m=>m.name===p))d=p;else{let m=p.split("/");if(m.length>1){let f=m[0];i.find(y=>y.name===f)&&(d=f,r(`History \u8DEF\u7531\u5339\u914D: ${c} -> ${f}`))}}}if(!d)return n();let u=i.find(p=>p.name===d);return u?ye(s,u,e,r):n()}catch(a){r(`\u5F00\u53D1\u670D\u52A1\u5668\u5904\u7406\u8BF7\u6C42\u5931\u8D25: ${a}`),n(a)}}),r("\u5F00\u53D1\u670D\u52A1\u5668\u914D\u7F6E\u5B8C\u6210")}catch(o){throw r(`\u914D\u7F6E\u5F00\u53D1\u670D\u52A1\u5668\u5931\u8D25: ${o}`),o}}function ye(t,e,r,o){let i={pageName:e.name,filePath:e.file,relativePath:b.relative(process.cwd(),e.file),strategy:void 0,isMatched:!1},l=O(r.pageConfigs,i,o);if(l?.strategy)i.strategy=l.strategy;else if(r.appliedStrategies?.has(e.name)){let c=r.appliedStrategies.get(e.name);c&&(i.strategy=c)}let g="",s=b.resolve(process.cwd(),`${e.name}.html`);if(E.existsSync(s)?g=s:l?.template?g=b.resolve(process.cwd(),l.template):g=b.resolve(process.cwd(),r.template),!E.existsSync(g)){t.statusCode=404,t.end("Template not found");return}let n=E.readFileSync(g,"utf-8");if(n.includes(r.placeholder)){let c=n;if(n=n.split(r.placeholder).join(`/${e.file}`),n===c){let d=J(r.placeholder),u=new RegExp(d,"g");n=c.replace(u,`/${e.file}`),n===c&&(n=c.replace(/\{\{ENTRY_FILE\}\}/g,`/${e.file}`))}}if(l?.define){let c=Object.entries(l.define).map(([d,u])=>{let p=typeof u=="string"?`"${u}"`:JSON.stringify(u);return`window.${d} = ${p};`}).join(`
|
|
2
2
|
`);c&&(n=n.replace(/<\/head>/i,`<script type="text/javascript">
|
|
3
3
|
${c}
|
|
4
4
|
</script>
|
|
@@ -98,7 +98,7 @@ ${c}
|
|
|
98
98
|
<p>${o}</p>
|
|
99
99
|
</body>
|
|
100
100
|
</html>
|
|
101
|
-
`}}var K=require("vite"),A=require("glob"),h=
|
|
101
|
+
`}}var K=require("vite"),A=require("glob"),h=w(require("path")),P=w(require("fs"));async function D(t){let{entry:e="src/pages/*/main.{ts,js}",exclude:r=[],template:o="index.html",placeholder:i="<!--VITE_MULTI_PAGE_ENTRY-->",strategies:l={},pageConfigs:g={},forceBuildStrategy:s}=t,n=R(!0),a={};try{let c=A.glob.sync(e,{cwd:process.cwd()}),d=F(c,e,r,n);if(d.length===0)return n("\u8B66\u544A: \u672A\u627E\u5230\u5339\u914D\u7684\u5165\u53E3\u6587\u4EF6"),{};let u=new Map,p=new Map;for(let f of d){let y={pageName:f.name,filePath:f.file,relativePath:h.relative(process.cwd(),f.file)},C=O(g,y,n)?.strategy||"default";u.set(f.name,C),p.has(C)||p.set(C,[]),p.get(C)?.push(f.name)}if(n(`\u{1F4C4} \u53D1\u73B0 ${d.length} \u4E2A\u9875\u9762: ${d.map(f=>f.name).join(", ")}`),s){let f=p.get(s)||[];if(f.length===0)return n(`\u8B66\u544A: \u7B56\u7565 "${s}" \u4E0B\u6CA1\u6709\u9875\u9762`),{};n(`\u5F3A\u5236\u6784\u5EFA\u7B56\u7565: ${s}, \u9875\u9762: ${f.join(", ")}`);let y=await L(s,f,d,l[s],g,o,i,n);return a[s]=y,a}for(let[f,y]of p){if(y.length===0)continue;let v=l[f]||{},C=await L(f,y,d,v,g,o,i,n);a[f]=C}if(Object.keys(a).length===0){n("\u8B66\u544A: \u672A\u751F\u6210\u4EFB\u4F55\u6784\u5EFA\u914D\u7F6E\uFF0C\u521B\u5EFA\u9ED8\u8BA4\u914D\u7F6E");let f=d.map(v=>v.name),y=await L("default",f,d,{},g,o,i,n);a.default=y}let m=Object.keys(a);return n(`\u{1F4E6} \u6784\u5EFA\u7B56\u7565: ${m.join(", ")}`),a}catch(c){throw n("\u751F\u6210\u6784\u5EFA\u914D\u7F6E\u5931\u8D25:",c),c}}async function L(t,e,r,o,i,l,g,s){let n={},a=[],c={};for(let m of e){let f=r.find(U=>U.name===m);if(!f)continue;let y={pageName:m,filePath:f.file,relativePath:h.relative(process.cwd(),f.file),strategy:t},v=O(i,y,s);v?.define&&Object.assign(c,v.define);let C=l,Y=`${m}.html`;P.existsSync(h.resolve(process.cwd(),Y))?C=Y:v?.template&&(C=v.template);let H=h.resolve(process.cwd(),C);if(!P.existsSync(H)){s(`\u8B66\u544A: \u6A21\u677F\u6587\u4EF6\u4E0D\u5B58\u5728: ${C}`);continue}let T=P.readFileSync(H,"utf-8");if(T.includes(g)){let U=`./${f.file}`;T=T.replace(new RegExp(g.replace(/[.*+?^${}()|[\]\\]/g,"\\$&"),"g"),U)}let N=h.resolve(process.cwd(),`.temp.mp.${m}.html`);P.writeFileSync(N,T),a.push(N),n[m]=N}let d={input:n,output:{entryFileNames:"assets/[name]-[hash].js",chunkFileNames:"assets/[name]-[hash].js",assetFileNames:"assets/[name]-[hash][extname]"}},u={base:"./",build:{outDir:`dist/${t}`,rollupOptions:d,rolldownOptions:d,emptyOutDir:!1},define:{}},p=u;return o&&(p=(0,K.mergeConfig)(u,o)),Object.keys(c).length>0&&(p.define={...p.define,...c}),p.build||(p.build={}),p.build.rollupOptions||(p.build.rollupOptions={}),p.build.rolldownOptions||(p.build.rolldownOptions={}),p.build.rollupOptions.input=n,p.build.rolldownOptions.input=n,p.build.emptyOutDir=!1,s(`\u7B56\u7565 "${t}" - ${e.length} \u4E2A\u9875\u9762`),p}function k(t=[]){let e=t.findIndex(o=>o==="--outDir");if(e!==-1&&e+1<t.length){let o=t[e+1];return h.resolve(process.cwd(),o)}let r=t.find(o=>o.startsWith("--outDir="));if(r){let o=r.split("=")[1];return h.resolve(process.cwd(),o)}return h.resolve(process.cwd(),"dist")}function X(t=[]){let e=k(t),r=R(!0);try{P.existsSync(e)&&(P.rmSync(e,{recursive:!0,force:!0}),r(`\u{1F9F9} \u6E05\u7406\u8F93\u51FA\u76EE\u5F55: ${h.relative(process.cwd(),e)}`))}catch(o){r(`\u26A0\uFE0F \u6E05\u7406\u8F93\u51FA\u76EE\u5F55\u5931\u8D25: ${e}`,o)}}function Z(t){let{entry:e="src/pages/*/main.{ts,js}",exclude:r=[],pageConfigs:o={}}=t,i=R(!1),l=new Set,g=A.glob.sync(e,{cwd:process.cwd()}),s=F(g,e,r,i);if(s.length===0)throw new Error(`\u672A\u627E\u5230\u5339\u914D\u7684\u5165\u53E3\u6587\u4EF6: ${e}`);try{for(let n of s){let a={pageName:n.name,filePath:n.file,relativePath:h.relative(process.cwd(),n.file)},d=O(o,a,i)?.strategy||"default";l.add(d)}return Array.from(l).sort()}catch(n){return i("\u83B7\u53D6\u53EF\u7528\u7B56\u7565\u5931\u8D25:",n),["default"]}}var B=w(require("fs")),V=w(require("path")),ee=require("url"),te=require("jiti"),ne=["multipage.config.ts","multipage.config.js","multipage.config.mjs"];function G(){for(let t of ne){let e=V.resolve(process.cwd(),t);if(B.existsSync(e))return!0}return!1}async function W(t){let e=await xe();if(e){let r=e(t);return r||{}}return null}async function Ce(t){if(t.endsWith(".ts"))return(0,te.createJiti)(x,{interopDefault:!0}).import(t);if(t.endsWith(".js")||t.endsWith(".mjs"))return import(`${(0,ee.pathToFileURL)(t).href}?t=${Date.now()}`);throw new Error(`\u4E0D\u652F\u6301\u7684\u914D\u7F6E\u6587\u4EF6\u7C7B\u578B: ${t}`)}async function xe(){let t=process.cwd();for(let e of ne){let r=V.resolve(t,e);if(B.existsSync(r))try{let o=await Ce(r),i=o.default||o;if(typeof i=="function")return i;console.warn(`\u914D\u7F6E\u6587\u4EF6 ${e} \u5FC5\u987B\u9ED8\u8BA4\u5BFC\u51FA\u4E00\u4E2A\u51FD\u6570`)}catch(o){console.error(`\u52A0\u8F7D\u914D\u7F6E\u6587\u4EF6 ${e} \u5931\u8D25:`,o)}}return null}var $={entry:"src/pages/**/*.{ts,js}",exclude:[],template:"index.html",placeholder:"{{ENTRY_FILE}}",debug:!1,strategies:{default:{}},pageConfigs:{}};function _(t){if(!t)return{...$};let e=t.strategies??t.buildStrategies??$.strategies;return{entry:t.entry??$.entry,exclude:t.exclude??$.exclude,template:t.template??$.template,placeholder:t.placeholder??$.placeholder,debug:t.debug??$.debug,strategies:e,pageConfigs:t.pageConfigs??$.pageConfigs,__forceBuildStrategy:t.__forceBuildStrategy}}var M=w(require("fs"));function ie(t){return typeof t=="function"?t:()=>t}function re(t){return t}function se(t){let e,r=[],o=()=>{};return{name:"vite-multi-page",async configResolved(i){let l=null;G()&&(l=await W({mode:i.command==="serve"?"development":"production",command:i.command,isCLI:!1}));let g=_(l);e=t?t(g,{mode:i.command==="serve"?"development":"production",command:i.command,isCLI:!1}):g,o=e.debug??!1?console.log.bind(console,"[vite-multi-page]"):()=>{},o("Vite\u914D\u7F6E\u5DF2\u89E3\u6790, \u4F7F\u7528\u914D\u7F6E:",{strategies:Object.keys(e.strategies||{}),entry:e.entry})},async config(i,{command:l}){if(l==="serve"){let g=process.argv,s=g.find(n=>n.startsWith("--strategy="));if(s){let n=s.split("=")[1];n&&(process.env.VITE_MULTI_PAGE_STRATEGY=n)}else{let n=g.findIndex(a=>a==="--strategy");if(n!==-1&&n+1<g.length){let a=g[n+1];process.env.VITE_MULTI_PAGE_STRATEGY=a}}process.env.VITE_MULTI_PAGE_STRATEGY||(process.env.VITE_MULTI_PAGE_STRATEGY="default")}if(l==="build"){if(!e){let a=null;G()&&(a=await W({mode:"production",command:"build",isCLI:!1}));let c=_(a);e=t?t(c,{mode:"production",command:"build",isCLI:!1}):c,o=e.debug??!1?console.log.bind(console,"[vite-multi-page]"):()=>{}}o("\u914D\u7F6E\u6784\u5EFA\u6A21\u5F0F");let g=process.env.VITE_MULTI_PAGE_STRATEGY,s=await D({entry:e.entry||"src/pages/**/*.{ts,js}",exclude:e.exclude||[],template:e.template||"index.html",placeholder:e.placeholder||"{{ENTRY_FILE}}",strategies:e.strategies||{},pageConfigs:e.pageConfigs||{},forceBuildStrategy:g}),n=Object.keys(s)[0];if(n&&s[n]){o(`\u5E94\u7528\u6784\u5EFA\u7B56\u7565: ${n}`);let a=s[n],c=(0,oe.mergeConfig)(i,a);Object.assign(i,c),o(`\u5DF2\u5E94\u7528\u7B56\u7565 "${n}" \u7684\u914D\u7F6E:`,{build:!!a.build,define:!!a.define,plugins:a.plugins?.length||0})}else throw o("\u672A\u627E\u5230\u53EF\u7528\u7684\u6784\u5EFA\u7B56\u7565\uFF0C\u4F7F\u7528\u9ED8\u8BA4\u914D\u7F6E"),new Error(`\u274C \u6784\u5EFA\u5931\u8D25: \u672A\u627E\u5230\u4EFB\u4F55\u6784\u5EFA\u7B56\u7565
|
|
102
102
|
|
|
103
103
|
\u53EF\u80FD\u7684\u539F\u56E0\uFF1A
|
|
104
104
|
1. \u914D\u7F6E\u6587\u4EF6\u8FD4\u56DE\u7A7A\u5BF9\u8C61 {}
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../node_modules/.pnpm/tsup@8.5.1_jiti@2.7.0_typescript@5.9.3/node_modules/tsup/assets/cjs_shims.js","../src/dev-server.ts","../src/file-filter.ts","../src/utils.ts","../src/page-config.ts","../src/build-config.ts","../src/config-loader.ts","../src/defaults.ts","../src/types.ts"],"sourcesContent":["import type { Plugin } from 'vite';\nimport { mergeConfig } from 'vite';\nimport { setupDevMiddleware } from './dev-server';\nimport { generateBuildConfig } from './build-config';\nimport { loadUserConfig, hasCustomConfig } from './config-loader';\nimport { mergeWithDefaults } from './defaults';\nimport type { Options, ConfigTransformFunction } from './types';\nimport * as fs from 'fs';\n\n// 导出类型和工具函数\nexport { defineConfig, defineConfigTransform } from './types';\nexport type {\n ConfigFunction,\n ConfigTransformFunction,\n PluginContext,\n PageContext,\n PageConfig,\n} from './types';\n\nexport function viteMultiPage(transform?: ConfigTransformFunction): Plugin {\n let resolvedOptions: Options;\n const tempFiles: string[] = [];\n let log: (...args: any[]) => void = () => {}; // 默认为空函数\n\n return {\n name: 'vite-multi-page',\n\n async configResolved(config) {\n // 加载用户配置文件(如果存在)\n let userConfig: Options | null = null;\n\n if (hasCustomConfig()) {\n userConfig = await loadUserConfig({\n mode: config.command === 'serve' ? 'development' : 'production',\n command: config.command,\n isCLI: false,\n });\n }\n\n // 合并用户配置和默认配置\n const mergedConfig = mergeWithDefaults(userConfig);\n\n // 应用配置变换函数(如果提供)\n resolvedOptions = transform\n ? transform(mergedConfig, {\n mode: config.command === 'serve' ? 'development' : 'production',\n command: config.command,\n isCLI: false,\n })\n : mergedConfig;\n\n // 设置debug日志\n const debug = resolvedOptions.debug ?? false;\n log = debug ? console.log.bind(console, '[vite-multi-page]') : () => {};\n\n log('Vite配置已解析, 使用配置:', {\n strategies: Object.keys(resolvedOptions.strategies || {}),\n entry: resolvedOptions.entry,\n });\n },\n\n async config(config, { command }) {\n // 处理开发模式下的策略参数\n if (command === 'serve') {\n // 检查命令行参数中的策略设置\n const args = process.argv;\n\n // 查找 --strategy=value 格式的参数\n const strategyArg = args.find(arg => arg.startsWith('--strategy='));\n if (strategyArg) {\n const strategy = strategyArg.split('=')[1];\n if (strategy) {\n process.env.VITE_MULTI_PAGE_STRATEGY = strategy;\n }\n }\n // 查找 --strategy value 格式的参数\n else {\n const strategyIndex = args.findIndex(arg => arg === '--strategy');\n if (strategyIndex !== -1 && strategyIndex + 1 < args.length) {\n const strategy = args[strategyIndex + 1];\n process.env.VITE_MULTI_PAGE_STRATEGY = strategy;\n }\n }\n\n // 确保有默认策略\n if (!process.env.VITE_MULTI_PAGE_STRATEGY) {\n process.env.VITE_MULTI_PAGE_STRATEGY = 'default';\n }\n }\n if (command === 'build') {\n // 在config钩子中临时加载配置,因为configResolved还没运行\n if (!resolvedOptions) {\n // 加载用户配置文件(如果存在)\n let userConfig: Options | null = null;\n\n if (hasCustomConfig()) {\n userConfig = await loadUserConfig({\n mode: 'production',\n command: 'build',\n isCLI: false,\n });\n }\n\n // 合并用户配置和默认配置\n const mergedConfig = mergeWithDefaults(userConfig);\n\n // 应用配置变换函数(如果提供)\n resolvedOptions = transform\n ? transform(mergedConfig, {\n mode: 'production',\n command: 'build',\n isCLI: false,\n })\n : mergedConfig;\n const debug = resolvedOptions.debug ?? false;\n log = debug ? console.log.bind(console, '[vite-multi-page]') : () => {};\n }\n\n log('配置构建模式');\n\n // 策略构建模式:生成构建配置\n const forceBuildStrategy = process.env.VITE_MULTI_PAGE_STRATEGY;\n const buildConfigs = generateBuildConfig({\n entry: resolvedOptions.entry || 'src/pages/**/*.{ts,js}',\n exclude: resolvedOptions.exclude || [],\n template: resolvedOptions.template || 'index.html',\n placeholder: resolvedOptions.placeholder || '{{ENTRY_FILE}}',\n strategies: resolvedOptions.strategies || {},\n pageConfigs: resolvedOptions.pageConfigs || {},\n forceBuildStrategy,\n });\n\n // 应用构建配置中的策略(如果有forceBuildStrategy,buildConfigs只会包含该策略)\n const targetStrategy = Object.keys(buildConfigs)[0];\n\n if (targetStrategy && buildConfigs[targetStrategy]) {\n log(`应用构建策略: ${targetStrategy}`);\n const strategyConfig = buildConfigs[targetStrategy];\n\n // 使用Vite的mergeConfig进行智能深度合并\n const mergedConfig = mergeConfig(config, strategyConfig);\n\n // 将合并结果复制回config对象\n Object.assign(config, mergedConfig);\n\n log(`已应用策略 \"${targetStrategy}\" 的配置:`, {\n build: !!strategyConfig.build,\n define: !!strategyConfig.define,\n plugins: strategyConfig.plugins?.length || 0,\n });\n } else {\n log('未找到可用的构建策略,使用默认配置');\n\n throw new Error(\n '❌ 构建失败: 未找到任何构建策略\\n\\n' +\n '可能的原因:\\n' +\n ' 1. 配置文件返回空对象 {}\\n' +\n ' 2. 未找到匹配的入口文件\\n' +\n ' 3. 模板文件不存在\\n' +\n ' 4. 未配置 strategies 对象\\n\\n' +\n '最小配置示例:\\n' +\n 'export default () => ({\\n' +\n ' entry: \"src/pages/**/*.{ts,js}\",\\n' +\n ' template: \"index.html\",\\n' +\n ' strategies: {\\n' +\n ' default: {}\\n' +\n ' }\\n' +\n '});'\n );\n }\n }\n },\n\n configureServer(server) {\n if (server.config.command === 'serve') {\n log('配置开发服务器');\n\n // 处理开发模式下的策略参数\n // 从环境变量中获取策略,默认为 default\n const devStrategy = process.env.VITE_MULTI_PAGE_STRATEGY || 'default';\n\n log(`开发模式策略: ${devStrategy}`);\n\n setupDevMiddleware(\n server,\n {\n entry: resolvedOptions.entry || 'src/pages/**/*.{ts,js}',\n exclude: resolvedOptions.exclude || [],\n template: resolvedOptions.template || 'index.html',\n placeholder: resolvedOptions.placeholder || '{{ENTRY_FILE}}',\n strategies: resolvedOptions.strategies || {},\n pageConfigs: resolvedOptions.pageConfigs || {},\n devStrategy: devStrategy, // 传递策略给开发服务器\n },\n log\n );\n }\n },\n\n writeBundle() {\n // 构建完成,无需额外处理\n // 每个策略已经直接输出到对应的目录\n },\n\n buildEnd() {\n // 清理临时文件\n if (tempFiles.length > 0) {\n log(`清理 ${tempFiles.length} 个临时文件`);\n tempFiles.forEach(file => {\n try {\n if (fs.existsSync(file)) {\n fs.unlinkSync(file);\n log(`删除临时文件: ${file}`);\n }\n } catch (error) {\n log(`删除临时文件失败: ${file}`, error);\n }\n });\n tempFiles.length = 0;\n }\n },\n };\n}\n\nexport default viteMultiPage;\nexport type { Options } from './types';\nexport {\n generateBuildConfig,\n getAvailableStrategies,\n getViteOutputDirectory,\n cleanViteOutputDirectory,\n} from './build-config';\nexport { mergeWithDefaults } from './defaults';\n","// Shim globals in cjs bundle\n// There's a weird bug that esbuild will always inject importMetaUrl\n// if we export it as `const importMetaUrl = ... __filename ...`\n// But using a function will not cause this issue\n\nconst getImportMetaUrl = () => \n typeof document === \"undefined\" \n ? new URL(`file:${__filename}`).href \n : (document.currentScript && document.currentScript.tagName.toUpperCase() === 'SCRIPT') \n ? document.currentScript.src \n : new URL(\"main.js\", document.baseURI).href;\n\nexport const importMetaUrl = /* @__PURE__ */ getImportMetaUrl()\n","import type { ViteDevServer } from 'vite';\nimport * as path from 'node:path';\nimport * as fs from 'node:fs';\nimport { glob } from 'glob';\nimport { filterEntryFiles } from './file-filter';\nimport { escapeRegExp } from './utils';\nimport { DevServerOptions, PageConfigContext } from './types';\nimport { getPageConfig } from './page-config';\n\nexport function configureDevServer(\n server: ViteDevServer,\n options: DevServerOptions,\n log: (...args: any[]) => void\n) {\n try {\n const allFiles = glob.sync(options.entry, { cwd: process.cwd() });\n let entryFiles = filterEntryFiles(allFiles, options.entry, options.exclude, log);\n\n if (entryFiles.length === 0) {\n log('警告: 未找到匹配的入口文件');\n return;\n }\n\n // 获取指定的策略,优先使用开发模式传入的策略\n const cliStrategy =\n options.devStrategy ||\n (((server.config as any).__cliStrategy || (server.config as any).strategy) as\n | string\n | undefined);\n\n // 如果指定了策略,则只显示该策略下的页面或没有指定策略的默认页面\n if (cliStrategy) {\n log(`开发服务器使用指定的策略: ${cliStrategy}`);\n\n // 过滤入口文件,只保留匹配策略的页面\n entryFiles = entryFiles.filter(file => {\n // 动态获取页面策略\n const pageContext = {\n pageName: file.name,\n filePath: file.file,\n relativePath: path.relative(process.cwd(), file.file),\n strategy: undefined,\n isMatched: false,\n } as PageConfigContext;\n\n const pageConfig = getPageConfig(options.pageConfigs, pageContext, log);\n const pageStrategy = pageConfig?.strategy || 'default';\n\n // 在指定策略为default时,包含所有没有指定策略的页面\n if (cliStrategy === 'default') {\n return pageStrategy === 'default';\n }\n\n // 其他策略,只包含匹配的页面\n return pageStrategy === cliStrategy;\n });\n\n log(`策略 \"${cliStrategy}\" 下可用的页面: ${entryFiles.map(f => f.name).join(', ') || '无'}`);\n }\n\n log('开发服务器应用的入口文件:', entryFiles);\n\n // 修改中间件来处理HTML请求\n server.middlewares.use(async (req, res, next) => {\n try {\n const url = req.url || '';\n const pathWithoutQuery = url.split('?')[0];\n\n // 处理根路径请求 - 显示所有页面的索引\n if (pathWithoutQuery === '/') {\n const indexHtml = generateIndexHtml(entryFiles, options, log);\n res.statusCode = 200;\n res.setHeader('Content-Type', 'text/html');\n res.end(indexHtml);\n return;\n }\n\n // 跳过明显的静态资源请求\n if (\n pathWithoutQuery.match(/\\.(js|css|png|jpg|jpeg|gif|svg|ico|woff|woff2|ttf|eot|map)$/) &&\n !pathWithoutQuery.endsWith('.html')\n ) {\n return next();\n }\n\n // 跳过以@开头的特殊路径(如Vite的特殊路径)\n if (pathWithoutQuery.startsWith('/@')) {\n return next();\n }\n\n // 跳过 __vite_ping 和其他 Vite 内部路径\n if (pathWithoutQuery.includes('__vite') || pathWithoutQuery.startsWith('/node_modules')) {\n return next();\n }\n\n // 提取页面名称,支持 history 路由\n let pageName = '';\n\n // 1. 处理带 .html 后缀的请求\n if (pathWithoutQuery.endsWith('.html')) {\n pageName = path.basename(pathWithoutQuery, '.html');\n }\n // 2. 处理精确匹配的页面路径,如 /mobile\n else if (pathWithoutQuery.startsWith('/')) {\n const cleanPath = pathWithoutQuery.substring(1); // 移除开头的斜杠\n\n // 首先尝试精确匹配\n if (entryFiles.find(file => file.name === cleanPath)) {\n pageName = cleanPath;\n }\n // 然后尝试 history 路由匹配,如 /home/login -> home\n else {\n const segments = cleanPath.split('/');\n if (segments.length > 1) {\n const possiblePageName = segments[0];\n if (entryFiles.find(file => file.name === possiblePageName)) {\n pageName = possiblePageName;\n log(`History 路由匹配: ${pathWithoutQuery} -> ${possiblePageName}`);\n }\n }\n }\n }\n\n if (!pageName) {\n return next();\n }\n\n const matchedFile = entryFiles.find(file => file.name === pageName);\n\n if (!matchedFile) {\n return next();\n }\n\n return servePageHtml(res, matchedFile, options, log);\n } catch (error) {\n log(`开发服务器处理请求失败: ${error}`);\n next(error);\n }\n });\n\n log('开发服务器配置完成');\n } catch (error) {\n log(`配置开发服务器失败: ${error}`);\n throw error;\n }\n}\n\n// 提取页面HTML服务逻辑\nfunction servePageHtml(\n res: any,\n matchedFile: { name: string; file: string },\n options: DevServerOptions,\n log: (...args: any[]) => void\n) {\n // 获取页面配置\n const pageContext = {\n pageName: matchedFile.name,\n filePath: matchedFile.file,\n relativePath: path.relative(process.cwd(), matchedFile.file),\n strategy: undefined,\n isMatched: false,\n } as PageConfigContext;\n\n const pageConfig = getPageConfig(options.pageConfigs, pageContext, log);\n\n // 应用配置策略\n if (pageConfig?.strategy) {\n pageContext.strategy = pageConfig.strategy;\n } else if (options.appliedStrategies?.has(matchedFile.name)) {\n // 使用缓存的策略信息\n const strategyName = options.appliedStrategies.get(matchedFile.name);\n if (strategyName) {\n pageContext.strategy = strategyName;\n }\n }\n\n // 获取模板文件路径\n // 首先检查是否有页面特定的模板(例如mobile.html对应mobile页面)\n let templatePath = '';\n\n // 尝试以页面名称查找匹配的模板\n const pageSpecificTemplate = path.resolve(process.cwd(), `${matchedFile.name}.html`);\n if (fs.existsSync(pageSpecificTemplate)) {\n templatePath = pageSpecificTemplate;\n }\n // 然后尝试使用页面配置中指定的模板\n else if (pageConfig?.template) {\n templatePath = path.resolve(process.cwd(), pageConfig.template);\n }\n // 最后使用默认模板\n else {\n templatePath = path.resolve(process.cwd(), options.template);\n }\n\n if (!fs.existsSync(templatePath)) {\n res.statusCode = 404;\n res.end('Template not found');\n return;\n }\n\n // 读取并修改模板\n let html = fs.readFileSync(templatePath, 'utf-8');\n\n // 检查模板中是否包含占位符\n const containsPlaceholder = html.includes(options.placeholder);\n\n // 替换占位符为入口文件路径\n if (containsPlaceholder) {\n const originalHtml = html;\n\n // 方式1: 直接字符串替换\n html = html.split(options.placeholder).join(`/${matchedFile.file}`);\n\n // 检查替换结果\n if (html === originalHtml) {\n // 方式2: 正则表达式替换\n const escapedPlaceholder = escapeRegExp(options.placeholder);\n const placeholderRegex = new RegExp(escapedPlaceholder, 'g');\n html = originalHtml.replace(placeholderRegex, `/${matchedFile.file}`);\n\n // 检查替换结果\n if (html === originalHtml) {\n // 方式3: 硬编码替换具体的占位符格式\n html = originalHtml.replace(/\\{\\{ENTRY_FILE\\}\\}/g, `/${matchedFile.file}`);\n }\n }\n }\n\n // 添加页面级define变量\n if (pageConfig?.define) {\n const defineScript = Object.entries(pageConfig.define)\n .map(([key, value]) => {\n const stringValue = typeof value === 'string' ? `\"${value}\"` : JSON.stringify(value);\n return `window.${key} = ${stringValue};`;\n })\n .join('\\n');\n\n if (defineScript) {\n // 注入到head标签底部\n html = html.replace(\n /<\\/head>/i,\n `<script type=\"text/javascript\">\\n${defineScript}\\n</script>\\n</head>`\n );\n }\n }\n\n // 发送响应\n res.statusCode = 200;\n res.setHeader('Content-Type', 'text/html');\n res.end(html);\n}\n\n// 为了兼容性,导出setupDevMiddleware作为configureDevServer的别名\nexport const setupDevMiddleware = configureDevServer;\n\n// 生成索引页面HTML\nfunction generateIndexHtml(\n entryFiles: { name: string; file: string }[],\n options: DevServerOptions,\n log: (...args: any[]) => void\n): string {\n try {\n const pageItems = entryFiles\n .map(file => {\n // 获取页面配置和策略\n const pageContext = {\n pageName: file.name,\n filePath: file.file,\n relativePath: path.relative(process.cwd(), file.file),\n strategy: undefined,\n isMatched: false,\n };\n\n const pageConfig = getPageConfig(options.pageConfigs, pageContext, log);\n\n // 确定策略\n let strategy = 'default';\n if (pageConfig?.strategy) {\n strategy = pageConfig.strategy;\n } else if (options.appliedStrategies?.has(file.name)) {\n const strategyName = options.appliedStrategies.get(file.name);\n if (strategyName) {\n strategy = strategyName;\n }\n }\n\n const strategyBadge =\n strategy !== 'default' ? `<span class=\"badge\">${strategy}</span>` : '';\n\n return `\n <div class=\"page-item\">\n <a href=\"${file.name}.html\" class=\"page-link\">\n ${file.name}${strategyBadge}\n </a>\n <div class=\"page-path\">${file.file}</div>\n </div>`;\n })\n .join('');\n\n return `\n <!DOCTYPE html>\n <html lang=\"en\">\n <head>\n <meta charset=\"UTF-8\">\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n <title>多页面应用索引</title>\n <style>\n body {\n font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, Helvetica, Arial, sans-serif;\n line-height: 1.6;\n color: #333;\n max-width: 1200px;\n margin: 0 auto;\n padding: 20px;\n background-color: #f5f5f7;\n }\n h1 {\n font-size: 24px;\n margin-bottom: 20px;\n color: #111;\n }\n .page-list {\n display: grid;\n grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));\n gap: 16px;\n }\n .page-item {\n background-color: white;\n border-radius: 8px;\n padding: 16px;\n box-shadow: 0 1px 3px rgba(0,0,0,0.1);\n transition: transform 0.2s, box-shadow 0.2s;\n }\n .page-item:hover {\n transform: translateY(-2px);\n box-shadow: 0 4px 8px rgba(0,0,0,0.1);\n }\n .page-link {\n display: flex;\n align-items: center;\n justify-content: space-between;\n font-size: 18px;\n font-weight: 500;\n color: #0066cc;\n text-decoration: none;\n margin-bottom: 8px;\n }\n .page-path {\n font-size: 14px;\n color: #666;\n word-break: break-all;\n }\n .badge {\n display: inline-block;\n font-size: 12px;\n padding: 2px 8px;\n border-radius: 12px;\n background-color: #e6f2ff;\n color: #0066cc;\n margin-left: 8px;\n }\n .stats {\n margin-bottom: 20px;\n font-size: 14px;\n color: #666;\n }\n </style>\n </head>\n <body>\n <h1>多页面应用索引</h1>\n <div class=\"stats\">\n 找到 ${entryFiles.length} 个页面\n </div>\n <div class=\"page-list\">\n ${pageItems}\n </div>\n </body>\n </html>\n `;\n } catch (error) {\n log(`生成索引页失败: ${error}`);\n return `\n <!DOCTYPE html>\n <html>\n <head>\n <title>错误</title>\n </head>\n <body>\n <h1>生成索引页时发生错误</h1>\n <p>${error}</p>\n </body>\n </html>\n `;\n }\n}\n","import * as path from 'node:path';\nimport type { EntryFile, CandidateFile } from './types';\n\nexport function filterEntryFiles(\n files: string[],\n entry: string,\n exclude: string[],\n _log: (...args: any[]) => void\n): EntryFile[] {\n const result: EntryFile[] = [];\n const nameToFile = new Map<string, { file: string; priority: number }>();\n\n // 从entry模式中提取基础目录\n let basePattern = entry.replace(/\\/\\*.*$/, ''); // 去掉glob部分\n // 如果基础模式为空或不合理,使用默认处理\n if (!basePattern || basePattern === entry) {\n basePattern = path.dirname(entry.split('*')[0]);\n }\n const candidateFiles: CandidateFile[] = [];\n\n for (const file of files) {\n if (exclude.includes(file)) {\n continue;\n }\n\n // 统一使用正斜杠处理路径,确保Windows兼容性\n const normalizedFile = file.replace(/\\\\/g, '/');\n const normalizedBasePattern = basePattern.replace(/\\\\/g, '/');\n\n const relativePath = path.posix.relative(normalizedBasePattern, normalizedFile);\n const pathParts = relativePath.split('/'); // 使用正斜杠分割\n\n if (pathParts.length === 1) {\n // 第一级文件:src/pages/about.js -> /about.html\n const fileName = pathParts[0];\n const name = path.posix.basename(fileName, path.posix.extname(fileName));\n candidateFiles.push({ name, file, priority: 1 });\n } else if (pathParts.length >= 2) {\n // 目录下的文件\n const fileName = path.posix.basename(normalizedFile, path.posix.extname(normalizedFile));\n const dirName = pathParts[0];\n\n if (fileName === 'main') {\n // 目录下的main文件:src/pages/mobile/main.ts -> /mobile.html\n candidateFiles.push({ name: dirName, file, priority: 2 });\n }\n }\n }\n\n // 按照优先级处理冲突:目录优先覆盖文件(优先级2 > 优先级1)\n for (const candidate of candidateFiles) {\n const existing = nameToFile.get(candidate.name);\n\n if (!existing) {\n nameToFile.set(candidate.name, { file: candidate.file, priority: candidate.priority });\n } else {\n if (candidate.priority > existing.priority) {\n nameToFile.set(candidate.name, { file: candidate.file, priority: candidate.priority });\n }\n }\n }\n\n for (const [name, { file }] of nameToFile.entries()) {\n result.push({ name, file });\n }\n\n return result;\n}\n","export function escapeRegExp(string: string): string {\n return string.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n}\n\nexport function createLogger(debug: boolean) {\n return (...args: any[]) => {\n if (debug) {\n console.log('[vite-plugin-multi-page]', ...args);\n }\n };\n}\n","import type { PageConfig, PageConfigFunction, PageConfigContext } from './types';\n\n/**\n * 根据页面上下文获取页面配置\n */\nexport function getPageConfig(\n pageConfigs: Record<string, PageConfig> | PageConfigFunction | undefined,\n context: PageConfigContext,\n log: (...args: any[]) => void\n): PageConfig | null {\n if (!pageConfigs) return null;\n\n // 如果是函数,直接调用\n if (typeof pageConfigs === 'function') {\n const result = pageConfigs(context);\n return result;\n }\n\n // 对象配置:支持精确匹配和模式匹配\n for (const [key, config] of Object.entries(pageConfigs)) {\n // 精确匹配页面名称\n if (key === context.pageName) {\n log(`精确匹配页面 ${context.pageName}:`, config);\n return config;\n }\n\n // 模式匹配\n if (config.match) {\n const patterns = Array.isArray(config.match) ? config.match : [config.match];\n const isMatched = patterns.some(\n pattern =>\n simpleMatch(pattern, context.pageName) ||\n simpleMatch(pattern, context.relativePath) ||\n simpleMatch(pattern, context.filePath)\n );\n\n if (isMatched) {\n log(`模式匹配页面 ${context.pageName} (模式: ${config.match}):`, config);\n return { ...config, match: undefined };\n }\n }\n\n // glob 模式匹配页面名称\n if (simpleMatch(key, context.pageName)) {\n log(`Glob匹配页面 ${context.pageName} (模式: ${key}):`, config);\n return config;\n }\n }\n\n return null;\n}\n\n/**\n * 简单的模式匹配函数\n */\nfunction simpleMatch(pattern: string, text: string): boolean {\n const regexPattern = pattern\n .replace(/\\*\\*/g, '__DOUBLE_STAR__')\n .replace(/\\*/g, '[^/]*')\n .replace(/__DOUBLE_STAR__/g, '.*');\n const regex = new RegExp(`^${regexPattern}$`);\n return regex.test(text);\n}\n","import type { UserConfig } from 'vite';\nimport { mergeConfig } from 'vite';\nimport { glob } from 'glob';\nimport * as path from 'node:path';\nimport * as fs from 'node:fs';\nimport { filterEntryFiles } from './file-filter';\nimport { getPageConfig } from './page-config';\nimport type { BuildConfigOptions, PageConfigContext, ConfigStrategy } from './types';\nimport { createLogger } from './utils';\n\n/**\n * 构建时配置生成器\n * 根据策略和页面配置生成多页面构建配置\n */\nexport function generateBuildConfig(options: BuildConfigOptions): Record<string, UserConfig> {\n const {\n entry = 'src/pages/*/main.{ts,js}',\n exclude = [],\n template = 'index.html',\n placeholder = '<!--VITE_MULTI_PAGE_ENTRY-->',\n strategies = {},\n pageConfigs = {},\n forceBuildStrategy,\n } = options;\n\n const log = createLogger(true);\n const buildConfigs: Record<string, UserConfig> = {};\n\n try {\n // 1. 发现所有页面入口文件\n const allFiles = glob.sync(entry, { cwd: process.cwd() });\n const entryFiles = filterEntryFiles(allFiles, entry, exclude, log);\n\n if (entryFiles.length === 0) {\n log('警告: 未找到匹配的入口文件');\n return {};\n }\n\n // 2. 为每个页面分析配置和策略\n const pageStrategies = new Map<string, string>();\n const strategyPages = new Map<string, string[]>();\n\n for (const entryFile of entryFiles) {\n const pageContext = {\n pageName: entryFile.name,\n filePath: entryFile.file,\n relativePath: path.relative(process.cwd(), entryFile.file),\n } as PageConfigContext;\n\n // 获取页面配置\n const pageConfig = getPageConfig(pageConfigs, pageContext, log);\n const strategyName = pageConfig?.strategy || 'default';\n\n pageStrategies.set(entryFile.name, strategyName);\n\n if (!strategyPages.has(strategyName)) {\n strategyPages.set(strategyName, []);\n }\n strategyPages.get(strategyName)?.push(entryFile.name);\n }\n\n log(`📄 发现 ${entryFiles.length} 个页面: ${entryFiles.map(f => f.name).join(', ')}`);\n\n // 3. 如果指定了强制策略,只构建该策略的页面\n if (forceBuildStrategy) {\n const targetPages = strategyPages.get(forceBuildStrategy) || [];\n if (targetPages.length === 0) {\n log(`警告: 策略 \"${forceBuildStrategy}\" 下没有页面`);\n return {};\n }\n\n log(`强制构建策略: ${forceBuildStrategy}, 页面: ${targetPages.join(', ')}`);\n\n const config = generateStrategyConfig(\n forceBuildStrategy,\n targetPages,\n entryFiles,\n strategies[forceBuildStrategy],\n pageConfigs,\n template,\n placeholder,\n log\n );\n\n buildConfigs[forceBuildStrategy] = config;\n return buildConfigs;\n }\n\n // 4. 为每个策略生成构建配置\n for (const [strategyName, pages] of strategyPages) {\n if (pages.length === 0) continue;\n\n // 获取策略配置,如果没有定义则使用空配置(允许默认策略)\n const strategyConfig = strategies[strategyName] || {};\n const config = generateStrategyConfig(\n strategyName,\n pages,\n entryFiles,\n strategyConfig,\n pageConfigs,\n template,\n placeholder,\n log\n );\n\n buildConfigs[strategyName] = config;\n }\n\n // 确保至少有一个构建配置\n if (Object.keys(buildConfigs).length === 0) {\n log('警告: 未生成任何构建配置,创建默认配置');\n\n // 如果没有任何策略,创建一个默认策略包含所有页面\n const allPageNames = entryFiles.map(f => f.name);\n const defaultConfig = generateStrategyConfig(\n 'default',\n allPageNames,\n entryFiles,\n {},\n pageConfigs,\n template,\n placeholder,\n log\n );\n\n buildConfigs['default'] = defaultConfig;\n }\n\n const strategyNames = Object.keys(buildConfigs);\n log(`📦 构建策略: ${strategyNames.join(', ')}`);\n return buildConfigs;\n } catch (error) {\n log('生成构建配置失败:', error);\n throw error;\n }\n}\n\n/**\n * 为特定策略生成构建配置\n */\nfunction generateStrategyConfig(\n strategyName: string,\n pages: string[],\n entryFiles: Array<{ name: string; file: string }>,\n strategyConfig: ConfigStrategy | undefined,\n pageConfigs: any,\n defaultTemplate: string,\n placeholder: string,\n log: (...args: any[]) => void\n): UserConfig {\n const htmlInputs: Record<string, string> = {};\n const tempFiles: string[] = [];\n\n // 收集所有页面的 define 变量\n const allPageDefines: Record<string, any> = {};\n\n // 为每个页面确定使用的HTML模板并创建临时文件\n for (const pageName of pages) {\n const entryFile = entryFiles.find(f => f.name === pageName);\n if (!entryFile) continue;\n\n // 获取页面配置\n const pageContext = {\n pageName,\n filePath: entryFile.file,\n relativePath: path.relative(process.cwd(), entryFile.file),\n strategy: strategyName,\n } as PageConfigContext;\n\n const pageConfig = getPageConfig(pageConfigs, pageContext, log);\n\n // 收集页面级 define 变量\n if (pageConfig?.define) {\n Object.assign(allPageDefines, pageConfig.define);\n }\n\n // 确定HTML模板\n let templatePath = defaultTemplate;\n\n // 1. 页面特定模板(如 mobile.html 对应 mobile 页面)\n const pageSpecificTemplate = `${pageName}.html`;\n if (fs.existsSync(path.resolve(process.cwd(), pageSpecificTemplate))) {\n templatePath = pageSpecificTemplate;\n }\n // 2. 页面配置中指定的模板\n else if (pageConfig?.template) {\n templatePath = pageConfig.template;\n }\n\n // 读取模板内容\n const templateFullPath = path.resolve(process.cwd(), templatePath);\n if (!fs.existsSync(templateFullPath)) {\n log(`警告: 模板文件不存在: ${templatePath}`);\n continue;\n }\n\n let templateContent = fs.readFileSync(templateFullPath, 'utf-8');\n\n // 替换占位符\n if (templateContent.includes(placeholder)) {\n // 临时HTML在项目根目录中,使用相对路径\n const entryPath = `./${entryFile.file}`;\n templateContent = templateContent.replace(\n new RegExp(placeholder.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&'), 'g'),\n entryPath\n );\n }\n\n // 创建临时HTML文件,使用新的命名规则:.temp.mp.[name].html\n const tempHtmlPath = path.resolve(process.cwd(), `.temp.mp.${pageName}.html`);\n fs.writeFileSync(tempHtmlPath, templateContent);\n tempFiles.push(tempHtmlPath);\n\n htmlInputs[pageName] = tempHtmlPath;\n }\n\n const buildOptions: Record<string, any> = {\n input: htmlInputs,\n output: {\n entryFileNames: 'assets/[name]-[hash].js',\n chunkFileNames: 'assets/[name]-[hash].js',\n assetFileNames: 'assets/[name]-[hash][extname]',\n },\n };\n\n const baseConfig: UserConfig = {\n base: './',\n build: {\n outDir: `dist/${strategyName}`,\n rollupOptions: buildOptions,\n rolldownOptions: buildOptions,\n emptyOutDir: false,\n },\n define: {},\n };\n\n let config: UserConfig = baseConfig;\n\n if (strategyConfig) {\n config = mergeConfig(baseConfig, strategyConfig);\n }\n\n if (Object.keys(allPageDefines).length > 0) {\n config.define = {\n ...config.define,\n ...allPageDefines,\n };\n }\n\n if (!config.build) config.build = {};\n if (!config.build.rollupOptions) config.build.rollupOptions = {};\n if (!(config.build as any).rolldownOptions) (config.build as any).rolldownOptions = {};\n\n config.build.rollupOptions.input = htmlInputs;\n (config.build as any).rolldownOptions.input = htmlInputs;\n config.build.emptyOutDir = false;\n\n // 简化日志输出\n log(`策略 \"${strategyName}\" - ${pages.length} 个页面`);\n\n return config;\n}\n\n/**\n * 获取Vite配置的输出目录\n * 需要传入已解析的Vite配置或命令行参数\n */\nexport function getViteOutputDirectory(viteBuildArgs: string[] = []): string {\n // 1. 首先检查命令行参数中的 --outDir\n const outDirIndex = viteBuildArgs.findIndex(arg => arg === '--outDir');\n if (outDirIndex !== -1 && outDirIndex + 1 < viteBuildArgs.length) {\n const outDir = viteBuildArgs[outDirIndex + 1];\n return path.resolve(process.cwd(), outDir);\n }\n\n // 2. 检查 --outDir=value 格式\n const outDirArg = viteBuildArgs.find(arg => arg.startsWith('--outDir='));\n if (outDirArg) {\n const outDir = outDirArg.split('=')[1];\n return path.resolve(process.cwd(), outDir);\n }\n\n // 3. 如果没有命令行参数,使用 Vite 默认值\n // 注意:如果用户在 vite.config.ts 中配置了 build.outDir,\n // Vite 会自动使用该配置,我们这里只处理命令行参数的情况\n return path.resolve(process.cwd(), 'dist');\n}\n\n/**\n * 清理Vite配置的输出目录\n */\nexport function cleanViteOutputDirectory(viteBuildArgs: string[] = []): void {\n const outputDir = getViteOutputDirectory(viteBuildArgs);\n const log = createLogger(true);\n\n try {\n if (fs.existsSync(outputDir)) {\n fs.rmSync(outputDir, { recursive: true, force: true });\n log(`🧹 清理输出目录: ${path.relative(process.cwd(), outputDir)}`);\n }\n } catch (error) {\n log(`⚠️ 清理输出目录失败: ${outputDir}`, error);\n }\n}\n\n/**\n * 获取所有可用的构建策略\n */\nexport function discoverPages(options: BuildConfigOptions): Array<{ name: string; file: string }> {\n const { entry = 'src/pages/*/main.{ts,js}', exclude = [] } = options;\n\n const log = createLogger(true);\n\n try {\n // 发现所有页面入口文件\n const allFiles = glob.sync(entry, { cwd: process.cwd() });\n const entryFiles = filterEntryFiles(allFiles, entry, exclude, log);\n\n return entryFiles;\n } catch (error) {\n log('发现页面失败:', error);\n throw error;\n }\n}\n\nexport function getAvailableStrategies(options: BuildConfigOptions): string[] {\n const { entry = 'src/pages/*/main.{ts,js}', exclude = [], pageConfigs = {} } = options;\n\n const log = createLogger(false); // 静默模式\n const strategySet = new Set<string>();\n\n // 发现所有页面入口文件\n const allFiles = glob.sync(entry, { cwd: process.cwd() });\n const entryFiles = filterEntryFiles(allFiles, entry, exclude, log);\n\n if (entryFiles.length === 0) {\n throw new Error(`未找到匹配的入口文件: ${entry}`);\n }\n\n try {\n // 分析每个页面的策略\n for (const entryFile of entryFiles) {\n const pageContext = {\n pageName: entryFile.name,\n filePath: entryFile.file,\n relativePath: path.relative(process.cwd(), entryFile.file),\n } as PageConfigContext;\n\n const pageConfig = getPageConfig(pageConfigs, pageContext, log);\n const strategyName = pageConfig?.strategy || 'default';\n strategySet.add(strategyName);\n }\n\n // 只返回实际有页面的策略,不添加空策略\n return Array.from(strategySet).sort();\n } catch (error) {\n log('获取可用策略失败:', error);\n return ['default'];\n }\n}\n","import * as fs from 'node:fs';\nimport * as path from 'node:path';\nimport { pathToFileURL } from 'node:url';\nimport { createJiti } from 'jiti';\nimport type { Options } from './types';\n\nexport interface ConfigContext {\n mode: 'development' | 'production';\n command: 'serve' | 'build';\n isCLI?: boolean;\n}\n\nexport type ConfigFunction = (context: ConfigContext) => Options;\n\nconst CONFIG_FILES = [\n 'multipage.config.ts',\n 'multipage.config.js',\n 'multipage.config.mjs',\n] as const;\n\nexport function hasCustomConfig(): boolean {\n for (const filename of CONFIG_FILES) {\n const configPath = path.resolve(process.cwd(), filename);\n if (fs.existsSync(configPath)) {\n return true;\n }\n }\n return false;\n}\n\nexport async function loadUserConfig(context: ConfigContext): Promise<Options | null> {\n const customConfig = await loadCustomConfig();\n\n if (customConfig) {\n const result = customConfig(context);\n\n if (!result) {\n return {};\n }\n\n return result;\n }\n\n return null;\n}\n\nasync function loadConfigFile(filePath: string): Promise<any> {\n if (filePath.endsWith('.ts')) {\n const jiti = createJiti(import.meta.url, { interopDefault: true });\n return jiti.import(filePath);\n }\n\n if (filePath.endsWith('.js') || filePath.endsWith('.mjs')) {\n const fileUrl = pathToFileURL(filePath).href;\n return import(`${fileUrl}?t=${Date.now()}`);\n }\n\n throw new Error(`不支持的配置文件类型: ${filePath}`);\n}\n\nasync function loadCustomConfig(): Promise<ConfigFunction | null> {\n const cwd = process.cwd();\n\n for (const configFile of CONFIG_FILES) {\n const configPath = path.resolve(cwd, configFile);\n\n if (fs.existsSync(configPath)) {\n try {\n const configModule = await loadConfigFile(configPath);\n const configFunction = configModule.default || configModule;\n\n if (typeof configFunction === 'function') {\n return configFunction;\n } else {\n console.warn(`配置文件 ${configFile} 必须默认导出一个函数`);\n }\n } catch (error) {\n console.error(`加载配置文件 ${configFile} 失败:`, error);\n }\n }\n }\n\n return null;\n}\n","import type { MultiPageOptions } from './types';\n\n/**\n * 默认配置选项\n */\nexport const DEFAULT_CONFIG: Required<\n Omit<MultiPageOptions, '__forceBuildStrategy' | 'buildStrategies'>\n> = {\n entry: 'src/pages/**/*.{ts,js}',\n exclude: [],\n template: 'index.html',\n placeholder: '{{ENTRY_FILE}}',\n debug: false,\n strategies: {\n default: {},\n },\n pageConfigs: {},\n};\n\n/**\n * 合并用户配置和默认配置\n */\nexport function mergeWithDefaults(\n userConfig: MultiPageOptions | null | undefined\n): MultiPageOptions {\n if (!userConfig) {\n return { ...DEFAULT_CONFIG };\n }\n\n // 处理 buildStrategies 别名\n const strategies =\n userConfig.strategies ?? userConfig.buildStrategies ?? DEFAULT_CONFIG.strategies;\n\n return {\n entry: userConfig.entry ?? DEFAULT_CONFIG.entry,\n exclude: userConfig.exclude ?? DEFAULT_CONFIG.exclude,\n template: userConfig.template ?? DEFAULT_CONFIG.template,\n placeholder: userConfig.placeholder ?? DEFAULT_CONFIG.placeholder,\n debug: userConfig.debug ?? DEFAULT_CONFIG.debug,\n strategies,\n pageConfigs: userConfig.pageConfigs ?? DEFAULT_CONFIG.pageConfigs,\n __forceBuildStrategy: userConfig.__forceBuildStrategy,\n };\n}\n\n/**\n * 检查配置是否为空或无效\n */\nexport function isEmptyConfig(config: MultiPageOptions): boolean {\n // 检查是否是完全空的对象\n if (Object.keys(config).length === 0) {\n return true;\n }\n\n // 检查是否只有默认值或无效值\n const hasValidEntry = config.entry && config.entry !== DEFAULT_CONFIG.entry;\n const hasValidStrategies =\n (config.strategies && Object.keys(config.strategies).length > 0) ||\n (config.buildStrategies && Object.keys(config.buildStrategies).length > 0);\n const hasValidPageConfigs =\n config.pageConfigs &&\n (typeof config.pageConfigs === 'function' || Object.keys(config.pageConfigs).length > 0);\n\n return !hasValidEntry && !hasValidStrategies && !hasValidPageConfigs;\n}\n","import type { UserConfig } from 'vite';\n\n// 核心配置选项\nexport interface MultiPageOptions {\n entry?: string;\n exclude?: string[];\n template?: string;\n placeholder?: string;\n debug?: boolean;\n strategies?: Record<string, ConfigStrategy>;\n buildStrategies?: Record<string, ConfigStrategy>; // 别名,等同于 strategies\n pageConfigs?: Record<string, PageConfig> | PageConfigFunction;\n __forceBuildStrategy?: string;\n}\n\n// 主要导出类型\nexport type Options = MultiPageOptions;\n\n// 开发服务器选项\nexport interface DevServerOptions {\n entry: string;\n exclude: string[];\n template: string;\n placeholder: string;\n strategies?: Record<string, ConfigStrategy>;\n pageConfigs?: Record<string, PageConfig> | PageConfigFunction;\n appliedStrategies?: Map<string, string>;\n devStrategy?: string; // 开发模式下指定的策略\n}\n\n// 构建配置选项\nexport interface BuildConfigOptions {\n entry: string;\n exclude: string[];\n template: string;\n placeholder: string;\n strategies?: Record<string, ConfigStrategy>;\n pageConfigs?: Record<string, PageConfig> | PageConfigFunction;\n forceBuildStrategy?: string;\n}\n\n// 策略配置\nexport type ConfigStrategy = Omit<UserConfig, 'plugins'>;\n\n// 页面配置\nexport interface PageConfig {\n strategy?: string;\n define?: Record<string, any>;\n template?: string;\n viteConfig?: UserConfig;\n match?: string;\n}\n\n// 页面上下文\nexport interface PageContext {\n pageName: string;\n filePath: string;\n relativePath: string;\n fullPath?: string;\n strategy?: string;\n isMatched?: boolean;\n}\n\n// 页面配置上下文(别名)\nexport type PageConfigContext = PageContext;\n\n// 页面配置函数\nexport type PageConfigFunction = (context: PageContext) => PageConfig | null;\n\n// 入口文件信息\nexport interface EntryFile {\n name: string;\n file: string;\n}\n\n// 候选文件信息\nexport interface CandidateFile extends EntryFile {\n priority: number;\n}\n\n// 构建策略配置\nexport interface BuildStrategyConfig {\n strategy: string;\n pages: string[];\n configPath?: string;\n}\n\n// CLI选项\nexport interface CLIOptions {\n configFile: string;\n outDir?: string;\n debug?: boolean;\n mode?: string;\n minify?: boolean | string;\n build?: Record<string, any>;\n base?: string;\n strategy?: string;\n port?: number | string;\n host?: string;\n https?: boolean;\n open?: boolean;\n}\n\n// 插件上下文\nexport interface PluginContext {\n mode: string;\n command: 'build' | 'serve';\n isCLI: boolean;\n}\n\n// 配置函数类型\nexport type ConfigFunction = (context: PluginContext) => MultiPageOptions;\n\n// 配置变换函数类型\nexport type ConfigTransformFunction = (\n config: MultiPageOptions,\n context: PluginContext\n) => MultiPageOptions;\n\n// 工具函数:定义配置\nexport function defineConfig(config: MultiPageOptions | ConfigFunction): ConfigFunction {\n // 如果传入的是函数,直接返回\n if (typeof config === 'function') {\n return config;\n }\n\n // 如果传入的是对象,包装成函数返回\n return () => config;\n}\n\n// 工具函数:定义配置变换\nexport function defineConfigTransform(transform: ConfigTransformFunction): ConfigTransformFunction {\n return transform;\n}\n"],"mappings":"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","names":["index_exports","__export","cleanViteOutputDirectory","index_default","defineConfig","defineConfigTransform","generateBuildConfig","getAvailableStrategies","getViteOutputDirectory","mergeWithDefaults","viteMultiPage","__toCommonJS","getImportMetaUrl","importMetaUrl","import_vite","path","fs","import_glob","path","filterEntryFiles","files","entry","exclude","_log","result","nameToFile","basePattern","candidateFiles","file","normalizedFile","normalizedBasePattern","pathParts","fileName","name","dirName","candidate","existing","escapeRegExp","string","createLogger","debug","args","getPageConfig","pageConfigs","context","log","key","config","pattern","simpleMatch","text","regexPattern","configureDevServer","server","options","log","allFiles","entryFiles","filterEntryFiles","cliStrategy","file","pageContext","pageStrategy","getPageConfig","f","req","res","next","pathWithoutQuery","indexHtml","generateIndexHtml","pageName","cleanPath","segments","possiblePageName","matchedFile","servePageHtml","error","pageConfig","strategyName","templatePath","pageSpecificTemplate","html","originalHtml","escapedPlaceholder","escapeRegExp","placeholderRegex","defineScript","key","value","stringValue","setupDevMiddleware","pageItems","strategy","strategyBadge","import_vite","import_glob","path","fs","generateBuildConfig","options","entry","exclude","template","placeholder","strategies","pageConfigs","forceBuildStrategy","log","createLogger","buildConfigs","allFiles","entryFiles","filterEntryFiles","pageStrategies","strategyPages","entryFile","pageContext","strategyName","getPageConfig","targetPages","config","generateStrategyConfig","pages","strategyConfig","allPageNames","f","defaultConfig","strategyNames","error","defaultTemplate","htmlInputs","tempFiles","allPageDefines","pageName","pageConfig","templatePath","pageSpecificTemplate","templateFullPath","templateContent","entryPath","tempHtmlPath","buildOptions","baseConfig","getViteOutputDirectory","viteBuildArgs","outDirIndex","arg","outDir","outDirArg","cleanViteOutputDirectory","outputDir","getAvailableStrategies","options","entry","exclude","pageConfigs","log","createLogger","strategySet","allFiles","entryFiles","filterEntryFiles","entryFile","pageContext","strategyName","getPageConfig","error","fs","path","import_node_url","import_jiti","CONFIG_FILES","hasCustomConfig","filename","configPath","loadUserConfig","context","customConfig","loadCustomConfig","result","loadConfigFile","filePath","importMetaUrl","cwd","configFile","configModule","configFunction","error","DEFAULT_CONFIG","mergeWithDefaults","userConfig","strategies","fs","defineConfig","config","defineConfigTransform","transform","viteMultiPage","transform","resolvedOptions","tempFiles","log","config","userConfig","hasCustomConfig","loadUserConfig","mergedConfig","mergeWithDefaults","command","args","strategyArg","arg","strategy","strategyIndex","forceBuildStrategy","buildConfigs","generateBuildConfig","targetStrategy","strategyConfig","server","devStrategy","setupDevMiddleware","file","error","index_default"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../node_modules/.pnpm/tsup@8.5.0_jiti@2.7.0_postcss@8.5.15_typescript@5.8.3/node_modules/tsup/assets/cjs_shims.js","../src/dev-server.ts","../src/file-filter.ts","../src/utils.ts","../src/page-config.ts","../src/build-config.ts","../src/config-loader.ts","../src/defaults.ts","../src/types.ts"],"sourcesContent":["import type { Plugin } from 'vite';\nimport { mergeConfig } from 'vite';\nimport { setupDevMiddleware } from './dev-server';\nimport { generateBuildConfig } from './build-config';\nimport { loadUserConfig, hasCustomConfig } from './config-loader';\nimport { mergeWithDefaults } from './defaults';\nimport type { Options, ConfigTransformFunction } from './types';\nimport * as fs from 'fs';\n\n// 导出类型和工具函数\nexport { defineConfig, defineConfigTransform } from './types';\nexport type {\n ConfigFunction,\n ConfigTransformFunction,\n PluginContext,\n PageContext,\n PageConfig,\n} from './types';\n\nexport function viteMultiPage(transform?: ConfigTransformFunction): Plugin {\n let resolvedOptions: Options;\n const tempFiles: string[] = [];\n let log: (...args: any[]) => void = () => {}; // 默认为空函数\n\n return {\n name: 'vite-multi-page',\n\n async configResolved(config) {\n // 加载用户配置文件(如果存在)\n let userConfig: Options | null = null;\n\n if (hasCustomConfig()) {\n userConfig = await loadUserConfig({\n mode: config.command === 'serve' ? 'development' : 'production',\n command: config.command,\n isCLI: false,\n });\n }\n\n // 合并用户配置和默认配置\n const mergedConfig = mergeWithDefaults(userConfig);\n\n // 应用配置变换函数(如果提供)\n resolvedOptions = transform\n ? transform(mergedConfig, {\n mode: config.command === 'serve' ? 'development' : 'production',\n command: config.command,\n isCLI: false,\n })\n : mergedConfig;\n\n // 设置debug日志\n const debug = resolvedOptions.debug ?? false;\n log = debug ? console.log.bind(console, '[vite-multi-page]') : () => {};\n\n log('Vite配置已解析, 使用配置:', {\n strategies: Object.keys(resolvedOptions.strategies || {}),\n entry: resolvedOptions.entry,\n });\n },\n\n async config(config, { command }) {\n // 处理开发模式下的策略参数\n if (command === 'serve') {\n // 检查命令行参数中的策略设置\n const args = process.argv;\n\n // 查找 --strategy=value 格式的参数\n const strategyArg = args.find(arg => arg.startsWith('--strategy='));\n if (strategyArg) {\n const strategy = strategyArg.split('=')[1];\n if (strategy) {\n process.env.VITE_MULTI_PAGE_STRATEGY = strategy;\n }\n }\n // 查找 --strategy value 格式的参数\n else {\n const strategyIndex = args.findIndex(arg => arg === '--strategy');\n if (strategyIndex !== -1 && strategyIndex + 1 < args.length) {\n const strategy = args[strategyIndex + 1];\n process.env.VITE_MULTI_PAGE_STRATEGY = strategy;\n }\n }\n\n // 确保有默认策略\n if (!process.env.VITE_MULTI_PAGE_STRATEGY) {\n process.env.VITE_MULTI_PAGE_STRATEGY = 'default';\n }\n }\n if (command === 'build') {\n // 在config钩子中临时加载配置,因为configResolved还没运行\n if (!resolvedOptions) {\n // 加载用户配置文件(如果存在)\n let userConfig: Options | null = null;\n\n if (hasCustomConfig()) {\n userConfig = await loadUserConfig({\n mode: 'production',\n command: 'build',\n isCLI: false,\n });\n }\n\n // 合并用户配置和默认配置\n const mergedConfig = mergeWithDefaults(userConfig);\n\n // 应用配置变换函数(如果提供)\n resolvedOptions = transform\n ? transform(mergedConfig, {\n mode: 'production',\n command: 'build',\n isCLI: false,\n })\n : mergedConfig;\n const debug = resolvedOptions.debug ?? false;\n log = debug ? console.log.bind(console, '[vite-multi-page]') : () => {};\n }\n\n log('配置构建模式');\n\n // 策略构建模式:生成构建配置\n const forceBuildStrategy = process.env.VITE_MULTI_PAGE_STRATEGY;\n const buildConfigs = await generateBuildConfig({\n entry: resolvedOptions.entry || 'src/pages/**/*.{ts,js}',\n exclude: resolvedOptions.exclude || [],\n template: resolvedOptions.template || 'index.html',\n placeholder: resolvedOptions.placeholder || '{{ENTRY_FILE}}',\n strategies: resolvedOptions.strategies || {},\n pageConfigs: resolvedOptions.pageConfigs || {},\n forceBuildStrategy,\n });\n\n // 应用构建配置中的策略(如果有forceBuildStrategy,buildConfigs只会包含该策略)\n const targetStrategy = Object.keys(buildConfigs)[0];\n\n if (targetStrategy && buildConfigs[targetStrategy]) {\n log(`应用构建策略: ${targetStrategy}`);\n const strategyConfig = buildConfigs[targetStrategy];\n\n // 使用Vite的mergeConfig进行智能深度合并\n const mergedConfig = mergeConfig(config, strategyConfig);\n\n // 将合并结果复制回config对象\n Object.assign(config, mergedConfig);\n\n log(`已应用策略 \"${targetStrategy}\" 的配置:`, {\n build: !!strategyConfig.build,\n define: !!strategyConfig.define,\n plugins: strategyConfig.plugins?.length || 0,\n });\n } else {\n log('未找到可用的构建策略,使用默认配置');\n\n throw new Error(\n '❌ 构建失败: 未找到任何构建策略\\n\\n' +\n '可能的原因:\\n' +\n ' 1. 配置文件返回空对象 {}\\n' +\n ' 2. 未找到匹配的入口文件\\n' +\n ' 3. 模板文件不存在\\n' +\n ' 4. 未配置 strategies 对象\\n\\n' +\n '最小配置示例:\\n' +\n 'export default () => ({\\n' +\n ' entry: \"src/pages/**/*.{ts,js}\",\\n' +\n ' template: \"index.html\",\\n' +\n ' strategies: {\\n' +\n ' default: {}\\n' +\n ' }\\n' +\n '});'\n );\n }\n }\n },\n\n configureServer(server) {\n if (server.config.command === 'serve') {\n log('配置开发服务器');\n\n // 处理开发模式下的策略参数\n // 从环境变量中获取策略,默认为 default\n const devStrategy = process.env.VITE_MULTI_PAGE_STRATEGY || 'default';\n\n log(`开发模式策略: ${devStrategy}`);\n\n setupDevMiddleware(\n server,\n {\n entry: resolvedOptions.entry || 'src/pages/**/*.{ts,js}',\n exclude: resolvedOptions.exclude || [],\n template: resolvedOptions.template || 'index.html',\n placeholder: resolvedOptions.placeholder || '{{ENTRY_FILE}}',\n strategies: resolvedOptions.strategies || {},\n pageConfigs: resolvedOptions.pageConfigs || {},\n devStrategy: devStrategy, // 传递策略给开发服务器\n },\n log\n );\n }\n },\n\n writeBundle() {\n // 构建完成,无需额外处理\n // 每个策略已经直接输出到对应的目录\n },\n\n buildEnd() {\n // 清理临时文件\n if (tempFiles.length > 0) {\n log(`清理 ${tempFiles.length} 个临时文件`);\n tempFiles.forEach(file => {\n try {\n if (fs.existsSync(file)) {\n fs.unlinkSync(file);\n log(`删除临时文件: ${file}`);\n }\n } catch (error) {\n log(`删除临时文件失败: ${file}`, error);\n }\n });\n tempFiles.length = 0;\n }\n },\n };\n}\n\nexport default viteMultiPage;\nexport type { Options } from './types';\nexport {\n generateBuildConfig,\n getAvailableStrategies,\n getViteOutputDirectory,\n cleanViteOutputDirectory,\n} from './build-config';\nexport { mergeWithDefaults } from './defaults';\n","// Shim globals in cjs bundle\n// There's a weird bug that esbuild will always inject importMetaUrl\n// if we export it as `const importMetaUrl = ... __filename ...`\n// But using a function will not cause this issue\n\nconst getImportMetaUrl = () =>\n typeof document === 'undefined'\n ? new URL(`file:${__filename}`).href\n : (document.currentScript && document.currentScript.src) ||\n new URL('main.js', document.baseURI).href\n\nexport const importMetaUrl = /* @__PURE__ */ getImportMetaUrl()\n","import type { ViteDevServer } from 'vite';\nimport * as path from 'node:path';\nimport * as fs from 'node:fs';\nimport { glob } from 'glob';\nimport { filterEntryFiles } from './file-filter';\nimport { escapeRegExp } from './utils';\nimport { DevServerOptions, PageConfigContext } from './types';\nimport { getPageConfig } from './page-config';\n\nexport function configureDevServer(\n server: ViteDevServer,\n options: DevServerOptions,\n log: (...args: any[]) => void\n) {\n try {\n const allFiles = glob.sync(options.entry, { cwd: process.cwd() });\n let entryFiles = filterEntryFiles(allFiles, options.entry, options.exclude, log);\n\n if (entryFiles.length === 0) {\n log('警告: 未找到匹配的入口文件');\n return;\n }\n\n // 获取指定的策略,优先使用开发模式传入的策略\n const cliStrategy =\n options.devStrategy ||\n (((server.config as any).__cliStrategy || (server.config as any).strategy) as\n | string\n | undefined);\n\n // 如果指定了策略,则只显示该策略下的页面或没有指定策略的默认页面\n if (cliStrategy) {\n log(`开发服务器使用指定的策略: ${cliStrategy}`);\n\n // 过滤入口文件,只保留匹配策略的页面\n entryFiles = entryFiles.filter(file => {\n // 动态获取页面策略\n const pageContext = {\n pageName: file.name,\n filePath: file.file,\n relativePath: path.relative(process.cwd(), file.file),\n strategy: undefined,\n isMatched: false,\n } as PageConfigContext;\n\n const pageConfig = getPageConfig(options.pageConfigs, pageContext, log);\n const pageStrategy = pageConfig?.strategy || 'default';\n\n // 在指定策略为default时,包含所有没有指定策略的页面\n if (cliStrategy === 'default') {\n return pageStrategy === 'default';\n }\n\n // 其他策略,只包含匹配的页面\n return pageStrategy === cliStrategy;\n });\n\n log(`策略 \"${cliStrategy}\" 下可用的页面: ${entryFiles.map(f => f.name).join(', ') || '无'}`);\n }\n\n log('开发服务器应用的入口文件:', entryFiles);\n\n // 修改中间件来处理HTML请求\n server.middlewares.use(async (req, res, next) => {\n try {\n const url = req.url || '';\n const pathWithoutQuery = url.split('?')[0];\n\n // 处理根路径请求 - 显示所有页面的索引\n if (pathWithoutQuery === '/') {\n const indexHtml = generateIndexHtml(entryFiles, options, log);\n res.statusCode = 200;\n res.setHeader('Content-Type', 'text/html');\n res.end(indexHtml);\n return;\n }\n\n // 跳过明显的静态资源请求\n if (\n pathWithoutQuery.match(/\\.(js|css|png|jpg|jpeg|gif|svg|ico|woff|woff2|ttf|eot|map)$/) &&\n !pathWithoutQuery.endsWith('.html')\n ) {\n return next();\n }\n\n // 跳过以@开头的特殊路径(如Vite的特殊路径)\n if (pathWithoutQuery.startsWith('/@')) {\n return next();\n }\n\n // 跳过 __vite_ping 和其他 Vite 内部路径\n if (pathWithoutQuery.includes('__vite') || pathWithoutQuery.startsWith('/node_modules')) {\n return next();\n }\n\n // 提取页面名称,支持 history 路由\n let pageName = '';\n\n // 1. 处理带 .html 后缀的请求\n if (pathWithoutQuery.endsWith('.html')) {\n pageName = path.basename(pathWithoutQuery, '.html');\n }\n // 2. 处理精确匹配的页面路径,如 /mobile\n else if (pathWithoutQuery.startsWith('/')) {\n const cleanPath = pathWithoutQuery.substring(1); // 移除开头的斜杠\n\n // 首先尝试精确匹配\n if (entryFiles.find(file => file.name === cleanPath)) {\n pageName = cleanPath;\n }\n // 然后尝试 history 路由匹配,如 /home/login -> home\n else {\n const segments = cleanPath.split('/');\n if (segments.length > 1) {\n const possiblePageName = segments[0];\n if (entryFiles.find(file => file.name === possiblePageName)) {\n pageName = possiblePageName;\n log(`History 路由匹配: ${pathWithoutQuery} -> ${possiblePageName}`);\n }\n }\n }\n }\n\n if (!pageName) {\n return next();\n }\n\n const matchedFile = entryFiles.find(file => file.name === pageName);\n\n if (!matchedFile) {\n return next();\n }\n\n return servePageHtml(res, matchedFile, options, log);\n } catch (error) {\n log(`开发服务器处理请求失败: ${error}`);\n next(error);\n }\n });\n\n log('开发服务器配置完成');\n } catch (error) {\n log(`配置开发服务器失败: ${error}`);\n throw error;\n }\n}\n\n// 提取页面HTML服务逻辑\nfunction servePageHtml(\n res: any,\n matchedFile: { name: string; file: string },\n options: DevServerOptions,\n log: (...args: any[]) => void\n) {\n // 获取页面配置\n const pageContext = {\n pageName: matchedFile.name,\n filePath: matchedFile.file,\n relativePath: path.relative(process.cwd(), matchedFile.file),\n strategy: undefined,\n isMatched: false,\n } as PageConfigContext;\n\n const pageConfig = getPageConfig(options.pageConfigs, pageContext, log);\n\n // 应用配置策略\n if (pageConfig?.strategy) {\n pageContext.strategy = pageConfig.strategy;\n } else if (options.appliedStrategies?.has(matchedFile.name)) {\n // 使用缓存的策略信息\n const strategyName = options.appliedStrategies.get(matchedFile.name);\n if (strategyName) {\n pageContext.strategy = strategyName;\n }\n }\n\n // 获取模板文件路径\n // 首先检查是否有页面特定的模板(例如mobile.html对应mobile页面)\n let templatePath = '';\n\n // 尝试以页面名称查找匹配的模板\n const pageSpecificTemplate = path.resolve(process.cwd(), `${matchedFile.name}.html`);\n if (fs.existsSync(pageSpecificTemplate)) {\n templatePath = pageSpecificTemplate;\n }\n // 然后尝试使用页面配置中指定的模板\n else if (pageConfig?.template) {\n templatePath = path.resolve(process.cwd(), pageConfig.template);\n }\n // 最后使用默认模板\n else {\n templatePath = path.resolve(process.cwd(), options.template);\n }\n\n if (!fs.existsSync(templatePath)) {\n res.statusCode = 404;\n res.end('Template not found');\n return;\n }\n\n // 读取并修改模板\n let html = fs.readFileSync(templatePath, 'utf-8');\n\n // 检查模板中是否包含占位符\n const containsPlaceholder = html.includes(options.placeholder);\n\n // 替换占位符为入口文件路径\n if (containsPlaceholder) {\n const originalHtml = html;\n\n // 方式1: 直接字符串替换\n html = html.split(options.placeholder).join(`/${matchedFile.file}`);\n\n // 检查替换结果\n if (html === originalHtml) {\n // 方式2: 正则表达式替换\n const escapedPlaceholder = escapeRegExp(options.placeholder);\n const placeholderRegex = new RegExp(escapedPlaceholder, 'g');\n html = originalHtml.replace(placeholderRegex, `/${matchedFile.file}`);\n\n // 检查替换结果\n if (html === originalHtml) {\n // 方式3: 硬编码替换具体的占位符格式\n html = originalHtml.replace(/\\{\\{ENTRY_FILE\\}\\}/g, `/${matchedFile.file}`);\n }\n }\n }\n\n // 添加页面级define变量\n if (pageConfig?.define) {\n const defineScript = Object.entries(pageConfig.define)\n .map(([key, value]) => {\n const stringValue = typeof value === 'string' ? `\"${value}\"` : JSON.stringify(value);\n return `window.${key} = ${stringValue};`;\n })\n .join('\\n');\n\n if (defineScript) {\n // 注入到head标签底部\n html = html.replace(\n /<\\/head>/i,\n `<script type=\"text/javascript\">\\n${defineScript}\\n</script>\\n</head>`\n );\n }\n }\n\n // 发送响应\n res.statusCode = 200;\n res.setHeader('Content-Type', 'text/html');\n res.end(html);\n}\n\n// 为了兼容性,导出setupDevMiddleware作为configureDevServer的别名\nexport const setupDevMiddleware = configureDevServer;\n\n// 生成索引页面HTML\nfunction generateIndexHtml(\n entryFiles: { name: string; file: string }[],\n options: DevServerOptions,\n log: (...args: any[]) => void\n): string {\n try {\n const pageItems = entryFiles\n .map(file => {\n // 获取页面配置和策略\n const pageContext = {\n pageName: file.name,\n filePath: file.file,\n relativePath: path.relative(process.cwd(), file.file),\n strategy: undefined,\n isMatched: false,\n };\n\n const pageConfig = getPageConfig(options.pageConfigs, pageContext, log);\n\n // 确定策略\n let strategy = 'default';\n if (pageConfig?.strategy) {\n strategy = pageConfig.strategy;\n } else if (options.appliedStrategies?.has(file.name)) {\n const strategyName = options.appliedStrategies.get(file.name);\n if (strategyName) {\n strategy = strategyName;\n }\n }\n\n const strategyBadge =\n strategy !== 'default' ? `<span class=\"badge\">${strategy}</span>` : '';\n\n return `\n <div class=\"page-item\">\n <a href=\"${file.name}.html\" class=\"page-link\">\n ${file.name}${strategyBadge}\n </a>\n <div class=\"page-path\">${file.file}</div>\n </div>`;\n })\n .join('');\n\n return `\n <!DOCTYPE html>\n <html lang=\"en\">\n <head>\n <meta charset=\"UTF-8\">\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n <title>多页面应用索引</title>\n <style>\n body {\n font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, Helvetica, Arial, sans-serif;\n line-height: 1.6;\n color: #333;\n max-width: 1200px;\n margin: 0 auto;\n padding: 20px;\n background-color: #f5f5f7;\n }\n h1 {\n font-size: 24px;\n margin-bottom: 20px;\n color: #111;\n }\n .page-list {\n display: grid;\n grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));\n gap: 16px;\n }\n .page-item {\n background-color: white;\n border-radius: 8px;\n padding: 16px;\n box-shadow: 0 1px 3px rgba(0,0,0,0.1);\n transition: transform 0.2s, box-shadow 0.2s;\n }\n .page-item:hover {\n transform: translateY(-2px);\n box-shadow: 0 4px 8px rgba(0,0,0,0.1);\n }\n .page-link {\n display: flex;\n align-items: center;\n justify-content: space-between;\n font-size: 18px;\n font-weight: 500;\n color: #0066cc;\n text-decoration: none;\n margin-bottom: 8px;\n }\n .page-path {\n font-size: 14px;\n color: #666;\n word-break: break-all;\n }\n .badge {\n display: inline-block;\n font-size: 12px;\n padding: 2px 8px;\n border-radius: 12px;\n background-color: #e6f2ff;\n color: #0066cc;\n margin-left: 8px;\n }\n .stats {\n margin-bottom: 20px;\n font-size: 14px;\n color: #666;\n }\n </style>\n </head>\n <body>\n <h1>多页面应用索引</h1>\n <div class=\"stats\">\n 找到 ${entryFiles.length} 个页面\n </div>\n <div class=\"page-list\">\n ${pageItems}\n </div>\n </body>\n </html>\n `;\n } catch (error) {\n log(`生成索引页失败: ${error}`);\n return `\n <!DOCTYPE html>\n <html>\n <head>\n <title>错误</title>\n </head>\n <body>\n <h1>生成索引页时发生错误</h1>\n <p>${error}</p>\n </body>\n </html>\n `;\n }\n}\n","import * as path from 'node:path';\nimport type { EntryFile, CandidateFile } from './types';\n\nexport function filterEntryFiles(\n files: string[],\n entry: string,\n exclude: string[],\n _log: (...args: any[]) => void\n): EntryFile[] {\n const result: EntryFile[] = [];\n const nameToFile = new Map<string, { file: string; priority: number }>();\n\n // 从entry模式中提取基础目录\n let basePattern = entry.replace(/\\/\\*.*$/, ''); // 去掉glob部分\n // 如果基础模式为空或不合理,使用默认处理\n if (!basePattern || basePattern === entry) {\n basePattern = path.dirname(entry.split('*')[0]);\n }\n const candidateFiles: CandidateFile[] = [];\n\n for (const file of files) {\n if (exclude.includes(file)) {\n continue;\n }\n\n // 统一使用正斜杠处理路径,确保Windows兼容性\n const normalizedFile = file.replace(/\\\\/g, '/');\n const normalizedBasePattern = basePattern.replace(/\\\\/g, '/');\n\n const relativePath = path.posix.relative(normalizedBasePattern, normalizedFile);\n const pathParts = relativePath.split('/'); // 使用正斜杠分割\n\n if (pathParts.length === 1) {\n // 第一级文件:src/pages/about.js -> /about.html\n const fileName = pathParts[0];\n const name = path.posix.basename(fileName, path.posix.extname(fileName));\n candidateFiles.push({ name, file, priority: 1 });\n } else if (pathParts.length >= 2) {\n // 目录下的文件\n const fileName = path.posix.basename(normalizedFile, path.posix.extname(normalizedFile));\n const dirName = pathParts[0];\n\n if (fileName === 'main') {\n // 目录下的main文件:src/pages/mobile/main.ts -> /mobile.html\n candidateFiles.push({ name: dirName, file, priority: 2 });\n }\n }\n }\n\n // 按照优先级处理冲突:目录优先覆盖文件(优先级2 > 优先级1)\n for (const candidate of candidateFiles) {\n const existing = nameToFile.get(candidate.name);\n\n if (!existing) {\n nameToFile.set(candidate.name, { file: candidate.file, priority: candidate.priority });\n } else {\n if (candidate.priority > existing.priority) {\n nameToFile.set(candidate.name, { file: candidate.file, priority: candidate.priority });\n }\n }\n }\n\n for (const [name, { file }] of nameToFile.entries()) {\n result.push({ name, file });\n }\n\n return result;\n}\n","export function escapeRegExp(string: string): string {\n return string.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n}\n\nexport function createLogger(debug: boolean) {\n return (...args: any[]) => {\n if (debug) {\n console.log('[vite-plugin-multi-page]', ...args);\n }\n };\n}\n","import type { PageConfig, PageConfigFunction, PageConfigContext } from './types';\n\n/**\n * 根据页面上下文获取页面配置\n */\nexport function getPageConfig(\n pageConfigs: Record<string, PageConfig> | PageConfigFunction | undefined,\n context: PageConfigContext,\n log: (...args: any[]) => void\n): PageConfig | null {\n if (!pageConfigs) return null;\n\n // 如果是函数,直接调用\n if (typeof pageConfigs === 'function') {\n const result = pageConfigs(context);\n return result;\n }\n\n // 对象配置:支持精确匹配和模式匹配\n for (const [key, config] of Object.entries(pageConfigs)) {\n // 精确匹配页面名称\n if (key === context.pageName) {\n log(`精确匹配页面 ${context.pageName}:`, config);\n return config;\n }\n\n // 模式匹配\n if (config.match) {\n const patterns = Array.isArray(config.match) ? config.match : [config.match];\n const isMatched = patterns.some(\n pattern =>\n simpleMatch(pattern, context.pageName) ||\n simpleMatch(pattern, context.relativePath) ||\n simpleMatch(pattern, context.filePath)\n );\n\n if (isMatched) {\n log(`模式匹配页面 ${context.pageName} (模式: ${config.match}):`, config);\n return { ...config, match: undefined };\n }\n }\n\n // glob 模式匹配页面名称\n if (simpleMatch(key, context.pageName)) {\n log(`Glob匹配页面 ${context.pageName} (模式: ${key}):`, config);\n return config;\n }\n }\n\n return null;\n}\n\n/**\n * 简单的模式匹配函数\n */\nfunction simpleMatch(pattern: string, text: string): boolean {\n const regexPattern = pattern\n .replace(/\\*\\*/g, '__DOUBLE_STAR__')\n .replace(/\\*/g, '[^/]*')\n .replace(/__DOUBLE_STAR__/g, '.*');\n const regex = new RegExp(`^${regexPattern}$`);\n return regex.test(text);\n}\n","import type { UserConfig } from 'vite';\nimport { mergeConfig } from 'vite';\nimport { glob } from 'glob';\nimport * as path from 'node:path';\nimport * as fs from 'node:fs';\nimport { filterEntryFiles } from './file-filter';\nimport { getPageConfig } from './page-config';\nimport type { BuildConfigOptions, PageConfigContext, ConfigStrategy } from './types';\nimport { createLogger } from './utils';\n\n/**\n * 构建时配置生成器\n * 根据策略和页面配置生成多页面构建配置\n */\nexport async function generateBuildConfig(\n options: BuildConfigOptions\n): Promise<Record<string, UserConfig>> {\n const {\n entry = 'src/pages/*/main.{ts,js}',\n exclude = [],\n template = 'index.html',\n placeholder = '<!--VITE_MULTI_PAGE_ENTRY-->',\n strategies = {},\n pageConfigs = {},\n forceBuildStrategy,\n } = options;\n\n const log = createLogger(true);\n const buildConfigs: Record<string, UserConfig> = {};\n\n try {\n // 1. 发现所有页面入口文件\n const allFiles = glob.sync(entry, { cwd: process.cwd() });\n const entryFiles = filterEntryFiles(allFiles, entry, exclude, log);\n\n if (entryFiles.length === 0) {\n log('警告: 未找到匹配的入口文件');\n return {};\n }\n\n // 2. 为每个页面分析配置和策略\n const pageStrategies = new Map<string, string>();\n const strategyPages = new Map<string, string[]>();\n\n for (const entryFile of entryFiles) {\n const pageContext = {\n pageName: entryFile.name,\n filePath: entryFile.file,\n relativePath: path.relative(process.cwd(), entryFile.file),\n } as PageConfigContext;\n\n // 获取页面配置\n const pageConfig = getPageConfig(pageConfigs, pageContext, log);\n const strategyName = pageConfig?.strategy || 'default';\n\n pageStrategies.set(entryFile.name, strategyName);\n\n if (!strategyPages.has(strategyName)) {\n strategyPages.set(strategyName, []);\n }\n strategyPages.get(strategyName)?.push(entryFile.name);\n }\n\n log(`📄 发现 ${entryFiles.length} 个页面: ${entryFiles.map(f => f.name).join(', ')}`);\n\n // 3. 如果指定了强制策略,只构建该策略的页面\n if (forceBuildStrategy) {\n const targetPages = strategyPages.get(forceBuildStrategy) || [];\n if (targetPages.length === 0) {\n log(`警告: 策略 \"${forceBuildStrategy}\" 下没有页面`);\n return {};\n }\n\n log(`强制构建策略: ${forceBuildStrategy}, 页面: ${targetPages.join(', ')}`);\n\n const config = await generateStrategyConfig(\n forceBuildStrategy,\n targetPages,\n entryFiles,\n strategies[forceBuildStrategy],\n pageConfigs,\n template,\n placeholder,\n log\n );\n\n buildConfigs[forceBuildStrategy] = config;\n return buildConfigs;\n }\n\n // 4. 为每个策略生成构建配置\n for (const [strategyName, pages] of strategyPages) {\n if (pages.length === 0) continue;\n\n // 获取策略配置,如果没有定义则使用空配置(允许默认策略)\n const strategyConfig = strategies[strategyName] || {};\n const config = await generateStrategyConfig(\n strategyName,\n pages,\n entryFiles,\n strategyConfig,\n pageConfigs,\n template,\n placeholder,\n log\n );\n\n buildConfigs[strategyName] = config;\n }\n\n // 确保至少有一个构建配置\n if (Object.keys(buildConfigs).length === 0) {\n log('警告: 未生成任何构建配置,创建默认配置');\n\n // 如果没有任何策略,创建一个默认策略包含所有页面\n const allPageNames = entryFiles.map(f => f.name);\n const defaultConfig = await generateStrategyConfig(\n 'default',\n allPageNames,\n entryFiles,\n {},\n pageConfigs,\n template,\n placeholder,\n log\n );\n\n buildConfigs['default'] = defaultConfig;\n }\n\n const strategyNames = Object.keys(buildConfigs);\n log(`📦 构建策略: ${strategyNames.join(', ')}`);\n return buildConfigs;\n } catch (error) {\n log('生成构建配置失败:', error);\n throw error;\n }\n}\n\n/**\n * 为特定策略生成构建配置\n */\nasync function generateStrategyConfig(\n strategyName: string,\n pages: string[],\n entryFiles: Array<{ name: string; file: string }>,\n strategyConfig: ConfigStrategy | undefined,\n pageConfigs: any,\n defaultTemplate: string,\n placeholder: string,\n log: (...args: any[]) => void\n): Promise<UserConfig> {\n const htmlInputs: Record<string, string> = {};\n const tempFiles: string[] = [];\n\n // 收集所有页面的 define 变量\n const allPageDefines: Record<string, any> = {};\n\n // 为每个页面确定使用的HTML模板并创建临时文件\n for (const pageName of pages) {\n const entryFile = entryFiles.find(f => f.name === pageName);\n if (!entryFile) continue;\n\n // 获取页面配置\n const pageContext = {\n pageName,\n filePath: entryFile.file,\n relativePath: path.relative(process.cwd(), entryFile.file),\n strategy: strategyName,\n } as PageConfigContext;\n\n const pageConfig = getPageConfig(pageConfigs, pageContext, log);\n\n // 收集页面级 define 变量\n if (pageConfig?.define) {\n Object.assign(allPageDefines, pageConfig.define);\n }\n\n // 确定HTML模板\n let templatePath = defaultTemplate;\n\n // 1. 页面特定模板(如 mobile.html 对应 mobile 页面)\n const pageSpecificTemplate = `${pageName}.html`;\n if (fs.existsSync(path.resolve(process.cwd(), pageSpecificTemplate))) {\n templatePath = pageSpecificTemplate;\n }\n // 2. 页面配置中指定的模板\n else if (pageConfig?.template) {\n templatePath = pageConfig.template;\n }\n\n // 读取模板内容\n const templateFullPath = path.resolve(process.cwd(), templatePath);\n if (!fs.existsSync(templateFullPath)) {\n log(`警告: 模板文件不存在: ${templatePath}`);\n continue;\n }\n\n let templateContent = fs.readFileSync(templateFullPath, 'utf-8');\n\n // 替换占位符\n if (templateContent.includes(placeholder)) {\n // 临时HTML在项目根目录中,使用相对路径\n const entryPath = `./${entryFile.file}`;\n templateContent = templateContent.replace(\n new RegExp(placeholder.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&'), 'g'),\n entryPath\n );\n }\n\n // 创建临时HTML文件,使用新的命名规则:.temp.mp.[name].html\n const tempHtmlPath = path.resolve(process.cwd(), `.temp.mp.${pageName}.html`);\n fs.writeFileSync(tempHtmlPath, templateContent);\n tempFiles.push(tempHtmlPath);\n\n htmlInputs[pageName] = tempHtmlPath;\n }\n\n const buildOptions: Record<string, any> = {\n input: htmlInputs,\n output: {\n entryFileNames: 'assets/[name]-[hash].js',\n chunkFileNames: 'assets/[name]-[hash].js',\n assetFileNames: 'assets/[name]-[hash][extname]',\n },\n };\n\n const baseConfig: UserConfig = {\n base: './',\n build: {\n outDir: `dist/${strategyName}`,\n rollupOptions: buildOptions,\n rolldownOptions: buildOptions,\n emptyOutDir: false,\n },\n define: {},\n };\n\n let config: UserConfig = baseConfig;\n\n if (strategyConfig) {\n config = mergeConfig(baseConfig, strategyConfig);\n }\n\n if (Object.keys(allPageDefines).length > 0) {\n config.define = {\n ...config.define,\n ...allPageDefines,\n };\n }\n\n if (!config.build) config.build = {};\n if (!config.build.rollupOptions) config.build.rollupOptions = {};\n if (!(config.build as any).rolldownOptions) (config.build as any).rolldownOptions = {};\n\n config.build.rollupOptions.input = htmlInputs;\n (config.build as any).rolldownOptions.input = htmlInputs;\n config.build.emptyOutDir = false;\n\n // 简化日志输出\n log(`策略 \"${strategyName}\" - ${pages.length} 个页面`);\n\n return config;\n}\n\n/**\n * 获取Vite配置的输出目录\n * 需要传入已解析的Vite配置或命令行参数\n */\nexport function getViteOutputDirectory(viteBuildArgs: string[] = []): string {\n // 1. 首先检查命令行参数中的 --outDir\n const outDirIndex = viteBuildArgs.findIndex(arg => arg === '--outDir');\n if (outDirIndex !== -1 && outDirIndex + 1 < viteBuildArgs.length) {\n const outDir = viteBuildArgs[outDirIndex + 1];\n return path.resolve(process.cwd(), outDir);\n }\n\n // 2. 检查 --outDir=value 格式\n const outDirArg = viteBuildArgs.find(arg => arg.startsWith('--outDir='));\n if (outDirArg) {\n const outDir = outDirArg.split('=')[1];\n return path.resolve(process.cwd(), outDir);\n }\n\n // 3. 如果没有命令行参数,使用 Vite 默认值\n // 注意:如果用户在 vite.config.ts 中配置了 build.outDir,\n // Vite 会自动使用该配置,我们这里只处理命令行参数的情况\n return path.resolve(process.cwd(), 'dist');\n}\n\n/**\n * 清理Vite配置的输出目录\n */\nexport function cleanViteOutputDirectory(viteBuildArgs: string[] = []): void {\n const outputDir = getViteOutputDirectory(viteBuildArgs);\n const log = createLogger(true);\n\n try {\n if (fs.existsSync(outputDir)) {\n fs.rmSync(outputDir, { recursive: true, force: true });\n log(`🧹 清理输出目录: ${path.relative(process.cwd(), outputDir)}`);\n }\n } catch (error) {\n log(`⚠️ 清理输出目录失败: ${outputDir}`, error);\n }\n}\n\n/**\n * 获取所有可用的构建策略\n */\nexport function discoverPages(options: BuildConfigOptions): Array<{ name: string; file: string }> {\n const { entry = 'src/pages/*/main.{ts,js}', exclude = [] } = options;\n\n const log = createLogger(true);\n\n try {\n // 发现所有页面入口文件\n const allFiles = glob.sync(entry, { cwd: process.cwd() });\n const entryFiles = filterEntryFiles(allFiles, entry, exclude, log);\n\n return entryFiles;\n } catch (error) {\n log('发现页面失败:', error);\n throw error;\n }\n}\n\nexport function getAvailableStrategies(options: BuildConfigOptions): string[] {\n const { entry = 'src/pages/*/main.{ts,js}', exclude = [], pageConfigs = {} } = options;\n\n const log = createLogger(false); // 静默模式\n const strategySet = new Set<string>();\n\n // 发现所有页面入口文件\n const allFiles = glob.sync(entry, { cwd: process.cwd() });\n const entryFiles = filterEntryFiles(allFiles, entry, exclude, log);\n\n if (entryFiles.length === 0) {\n throw new Error(`未找到匹配的入口文件: ${entry}`);\n }\n\n try {\n // 分析每个页面的策略\n for (const entryFile of entryFiles) {\n const pageContext = {\n pageName: entryFile.name,\n filePath: entryFile.file,\n relativePath: path.relative(process.cwd(), entryFile.file),\n } as PageConfigContext;\n\n const pageConfig = getPageConfig(pageConfigs, pageContext, log);\n const strategyName = pageConfig?.strategy || 'default';\n strategySet.add(strategyName);\n }\n\n // 只返回实际有页面的策略,不添加空策略\n return Array.from(strategySet).sort();\n } catch (error) {\n log('获取可用策略失败:', error);\n return ['default'];\n }\n}\n","import * as fs from 'node:fs';\nimport * as path from 'node:path';\nimport { pathToFileURL } from 'node:url';\nimport { createJiti } from 'jiti';\nimport type { Options } from './types';\n\nexport interface ConfigContext {\n mode: 'development' | 'production';\n command: 'serve' | 'build';\n isCLI?: boolean;\n}\n\nexport type ConfigFunction = (context: ConfigContext) => Options;\n\nconst CONFIG_FILES = [\n 'multipage.config.ts',\n 'multipage.config.js',\n 'multipage.config.mjs',\n] as const;\n\nexport function hasCustomConfig(): boolean {\n for (const filename of CONFIG_FILES) {\n const configPath = path.resolve(process.cwd(), filename);\n if (fs.existsSync(configPath)) {\n return true;\n }\n }\n return false;\n}\n\nexport async function loadUserConfig(context: ConfigContext): Promise<Options | null> {\n const customConfig = await loadCustomConfig();\n\n if (customConfig) {\n const result = customConfig(context);\n\n if (!result) {\n return {};\n }\n\n return result;\n }\n\n return null;\n}\n\nasync function loadConfigFile(filePath: string): Promise<any> {\n if (filePath.endsWith('.ts')) {\n const jiti = createJiti(import.meta.url, { interopDefault: true });\n return jiti.import(filePath);\n }\n\n if (filePath.endsWith('.js') || filePath.endsWith('.mjs')) {\n const fileUrl = pathToFileURL(filePath).href;\n return import(`${fileUrl}?t=${Date.now()}`);\n }\n\n throw new Error(`不支持的配置文件类型: ${filePath}`);\n}\n\nasync function loadCustomConfig(): Promise<ConfigFunction | null> {\n const cwd = process.cwd();\n\n for (const configFile of CONFIG_FILES) {\n const configPath = path.resolve(cwd, configFile);\n\n if (fs.existsSync(configPath)) {\n try {\n const configModule = await loadConfigFile(configPath);\n const configFunction = configModule.default || configModule;\n\n if (typeof configFunction === 'function') {\n return configFunction;\n } else {\n console.warn(`配置文件 ${configFile} 必须默认导出一个函数`);\n }\n } catch (error) {\n console.error(`加载配置文件 ${configFile} 失败:`, error);\n }\n }\n }\n\n return null;\n}\n","import type { MultiPageOptions } from './types';\n\n/**\n * 默认配置选项\n */\nexport const DEFAULT_CONFIG: Required<\n Omit<MultiPageOptions, '__forceBuildStrategy' | 'buildStrategies'>\n> = {\n entry: 'src/pages/**/*.{ts,js}',\n exclude: [],\n template: 'index.html',\n placeholder: '{{ENTRY_FILE}}',\n debug: false,\n strategies: {\n default: {},\n },\n pageConfigs: {},\n};\n\n/**\n * 合并用户配置和默认配置\n */\nexport function mergeWithDefaults(\n userConfig: MultiPageOptions | null | undefined\n): MultiPageOptions {\n if (!userConfig) {\n return { ...DEFAULT_CONFIG };\n }\n\n // 处理 buildStrategies 别名\n const strategies =\n userConfig.strategies ?? userConfig.buildStrategies ?? DEFAULT_CONFIG.strategies;\n\n return {\n entry: userConfig.entry ?? DEFAULT_CONFIG.entry,\n exclude: userConfig.exclude ?? DEFAULT_CONFIG.exclude,\n template: userConfig.template ?? DEFAULT_CONFIG.template,\n placeholder: userConfig.placeholder ?? DEFAULT_CONFIG.placeholder,\n debug: userConfig.debug ?? DEFAULT_CONFIG.debug,\n strategies,\n pageConfigs: userConfig.pageConfigs ?? DEFAULT_CONFIG.pageConfigs,\n __forceBuildStrategy: userConfig.__forceBuildStrategy,\n };\n}\n\n/**\n * 检查配置是否为空或无效\n */\nexport function isEmptyConfig(config: MultiPageOptions): boolean {\n // 检查是否是完全空的对象\n if (Object.keys(config).length === 0) {\n return true;\n }\n\n // 检查是否只有默认值或无效值\n const hasValidEntry = config.entry && config.entry !== DEFAULT_CONFIG.entry;\n const hasValidStrategies =\n (config.strategies && Object.keys(config.strategies).length > 0) ||\n (config.buildStrategies && Object.keys(config.buildStrategies).length > 0);\n const hasValidPageConfigs =\n config.pageConfigs &&\n (typeof config.pageConfigs === 'function' || Object.keys(config.pageConfigs).length > 0);\n\n return !hasValidEntry && !hasValidStrategies && !hasValidPageConfigs;\n}\n","import type { UserConfig } from 'vite';\n\n// 核心配置选项\nexport interface MultiPageOptions {\n entry?: string;\n exclude?: string[];\n template?: string;\n placeholder?: string;\n debug?: boolean;\n strategies?: Record<string, ConfigStrategy>;\n buildStrategies?: Record<string, ConfigStrategy>; // 别名,等同于 strategies\n pageConfigs?: Record<string, PageConfig> | PageConfigFunction;\n __forceBuildStrategy?: string;\n}\n\n// 主要导出类型\nexport type Options = MultiPageOptions;\n\n// 开发服务器选项\nexport interface DevServerOptions {\n entry: string;\n exclude: string[];\n template: string;\n placeholder: string;\n strategies?: Record<string, ConfigStrategy>;\n pageConfigs?: Record<string, PageConfig> | PageConfigFunction;\n appliedStrategies?: Map<string, string>;\n devStrategy?: string; // 开发模式下指定的策略\n}\n\n// 构建配置选项\nexport interface BuildConfigOptions {\n entry: string;\n exclude: string[];\n template: string;\n placeholder: string;\n strategies?: Record<string, ConfigStrategy>;\n pageConfigs?: Record<string, PageConfig> | PageConfigFunction;\n forceBuildStrategy?: string;\n}\n\n// 策略配置\nexport type ConfigStrategy = Omit<UserConfig, 'plugins'>;\n\n// 页面配置\nexport interface PageConfig {\n strategy?: string;\n define?: Record<string, any>;\n template?: string;\n viteConfig?: UserConfig;\n match?: string;\n}\n\n// 页面上下文\nexport interface PageContext {\n pageName: string;\n filePath: string;\n relativePath: string;\n fullPath?: string;\n strategy?: string;\n isMatched?: boolean;\n}\n\n// 页面配置上下文(别名)\nexport type PageConfigContext = PageContext;\n\n// 页面配置函数\nexport type PageConfigFunction = (context: PageContext) => PageConfig | null;\n\n// 入口文件信息\nexport interface EntryFile {\n name: string;\n file: string;\n}\n\n// 候选文件信息\nexport interface CandidateFile extends EntryFile {\n priority: number;\n}\n\n// 构建策略配置\nexport interface BuildStrategyConfig {\n strategy: string;\n pages: string[];\n configPath?: string;\n}\n\n// CLI选项\nexport interface CLIOptions {\n configFile: string;\n outDir?: string;\n debug?: boolean;\n mode?: string;\n minify?: boolean | string;\n build?: Record<string, any>;\n base?: string;\n strategy?: string;\n port?: number | string;\n host?: string;\n https?: boolean;\n open?: boolean;\n}\n\n// 插件上下文\nexport interface PluginContext {\n mode: string;\n command: 'build' | 'serve';\n isCLI: boolean;\n}\n\n// 配置函数类型\nexport type ConfigFunction = (context: PluginContext) => MultiPageOptions;\n\n// 配置变换函数类型\nexport type ConfigTransformFunction = (\n config: MultiPageOptions,\n context: PluginContext\n) => MultiPageOptions;\n\n// 工具函数:定义配置\nexport function defineConfig(config: MultiPageOptions | ConfigFunction): ConfigFunction {\n // 如果传入的是函数,直接返回\n if (typeof config === 'function') {\n return config;\n }\n\n // 如果传入的是对象,包装成函数返回\n return () => config;\n}\n\n// 工具函数:定义配置变换\nexport function defineConfigTransform(transform: ConfigTransformFunction): ConfigTransformFunction {\n return transform;\n}\n"],"mappings":"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","names":["index_exports","__export","cleanViteOutputDirectory","index_default","defineConfig","defineConfigTransform","generateBuildConfig","getAvailableStrategies","getViteOutputDirectory","mergeWithDefaults","viteMultiPage","__toCommonJS","getImportMetaUrl","importMetaUrl","import_vite","path","fs","import_glob","path","filterEntryFiles","files","entry","exclude","_log","result","nameToFile","basePattern","candidateFiles","file","normalizedFile","normalizedBasePattern","pathParts","fileName","name","dirName","candidate","existing","escapeRegExp","string","createLogger","debug","args","getPageConfig","pageConfigs","context","log","key","config","pattern","simpleMatch","text","regexPattern","configureDevServer","server","options","log","allFiles","entryFiles","filterEntryFiles","cliStrategy","file","pageContext","pageStrategy","getPageConfig","f","req","res","next","pathWithoutQuery","indexHtml","generateIndexHtml","pageName","cleanPath","segments","possiblePageName","matchedFile","servePageHtml","error","pageConfig","strategyName","templatePath","pageSpecificTemplate","html","originalHtml","escapedPlaceholder","escapeRegExp","placeholderRegex","defineScript","key","value","stringValue","setupDevMiddleware","pageItems","strategy","strategyBadge","import_vite","import_glob","path","fs","generateBuildConfig","options","entry","exclude","template","placeholder","strategies","pageConfigs","forceBuildStrategy","log","createLogger","buildConfigs","allFiles","entryFiles","filterEntryFiles","pageStrategies","strategyPages","entryFile","pageContext","strategyName","getPageConfig","targetPages","config","generateStrategyConfig","pages","strategyConfig","allPageNames","f","defaultConfig","strategyNames","error","defaultTemplate","htmlInputs","tempFiles","allPageDefines","pageName","pageConfig","templatePath","pageSpecificTemplate","templateFullPath","templateContent","entryPath","tempHtmlPath","buildOptions","baseConfig","getViteOutputDirectory","viteBuildArgs","outDirIndex","arg","outDir","outDirArg","cleanViteOutputDirectory","outputDir","getAvailableStrategies","options","entry","exclude","pageConfigs","log","createLogger","strategySet","allFiles","entryFiles","filterEntryFiles","entryFile","pageContext","strategyName","getPageConfig","error","fs","path","import_node_url","import_jiti","CONFIG_FILES","hasCustomConfig","filename","configPath","loadUserConfig","context","customConfig","loadCustomConfig","result","loadConfigFile","filePath","importMetaUrl","cwd","configFile","configModule","configFunction","error","DEFAULT_CONFIG","mergeWithDefaults","userConfig","strategies","fs","defineConfig","config","defineConfigTransform","transform","viteMultiPage","transform","resolvedOptions","tempFiles","log","config","userConfig","hasCustomConfig","loadUserConfig","mergedConfig","mergeWithDefaults","command","args","strategyArg","arg","strategy","strategyIndex","forceBuildStrategy","buildConfigs","generateBuildConfig","targetStrategy","strategyConfig","server","devStrategy","setupDevMiddleware","file","error","index_default"]}
|
package/dist/index.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{mergeConfig as ge}from"vite";import*as x from"path";import*as E from"fs";import{glob as q}from"glob";import*as
|
|
1
|
+
import{mergeConfig as ge}from"vite";import*as x from"path";import*as E from"fs";import{glob as q}from"glob";import*as v from"path";function F(n,e,o,r){let i=[],l=new Map,g=e.replace(/\/\*.*$/,"");(!g||g===e)&&(g=v.dirname(e.split("*")[0]));let s=[];for(let t of n){if(o.includes(t))continue;let a=t.replace(/\\/g,"/"),c=g.replace(/\\/g,"/"),u=v.posix.relative(c,a).split("/");if(u.length===1){let p=u[0],m=v.posix.basename(p,v.posix.extname(p));s.push({name:m,file:t,priority:1})}else if(u.length>=2){let p=v.posix.basename(a,v.posix.extname(a)),m=u[0];p==="main"&&s.push({name:m,file:t,priority:2})}}for(let t of s){let a=l.get(t.name);a?t.priority>a.priority&&l.set(t.name,{file:t.file,priority:t.priority}):l.set(t.name,{file:t.file,priority:t.priority})}for(let[t,{file:a}]of l.entries())i.push({name:t,file:a});return i}function W(n){return n.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}function _(n){return(...e)=>{n&&console.log("[vite-plugin-multi-page]",...e)}}function O(n,e,o){if(!n)return null;if(typeof n=="function")return n(e);for(let[r,i]of Object.entries(n)){if(r===e.pageName)return o(`\u7CBE\u786E\u5339\u914D\u9875\u9762 ${e.pageName}:`,i),i;if(i.match&&(Array.isArray(i.match)?i.match:[i.match]).some(s=>j(s,e.pageName)||j(s,e.relativePath)||j(s,e.filePath)))return o(`\u6A21\u5F0F\u5339\u914D\u9875\u9762 ${e.pageName} (\u6A21\u5F0F: ${i.match}):`,i),{...i,match:void 0};if(j(r,e.pageName))return o(`Glob\u5339\u914D\u9875\u9762 ${e.pageName} (\u6A21\u5F0F: ${r}):`,i),i}return null}function j(n,e){let o=n.replace(/\*\*/g,"__DOUBLE_STAR__").replace(/\*/g,"[^/]*").replace(/__DOUBLE_STAR__/g,".*");return new RegExp(`^${o}$`).test(e)}function Q(n,e,o){try{let r=q.sync(e.entry,{cwd:process.cwd()}),i=F(r,e.entry,e.exclude,o);if(i.length===0){o("\u8B66\u544A: \u672A\u627E\u5230\u5339\u914D\u7684\u5165\u53E3\u6587\u4EF6");return}let l=e.devStrategy||n.config.__cliStrategy||n.config.strategy;l&&(o(`\u5F00\u53D1\u670D\u52A1\u5668\u4F7F\u7528\u6307\u5B9A\u7684\u7B56\u7565: ${l}`),i=i.filter(g=>{let s={pageName:g.name,filePath:g.file,relativePath:x.relative(process.cwd(),g.file),strategy:void 0,isMatched:!1},a=O(e.pageConfigs,s,o)?.strategy||"default";return l==="default"?a==="default":a===l}),o(`\u7B56\u7565 "${l}" \u4E0B\u53EF\u7528\u7684\u9875\u9762: ${i.map(g=>g.name).join(", ")||"\u65E0"}`)),o("\u5F00\u53D1\u670D\u52A1\u5668\u5E94\u7528\u7684\u5165\u53E3\u6587\u4EF6:",i),n.middlewares.use(async(g,s,t)=>{try{let c=(g.url||"").split("?")[0];if(c==="/"){let p=X(i,e,o);s.statusCode=200,s.setHeader("Content-Type","text/html"),s.end(p);return}if(c.match(/\.(js|css|png|jpg|jpeg|gif|svg|ico|woff|woff2|ttf|eot|map)$/)&&!c.endsWith(".html")||c.startsWith("/@")||c.includes("__vite")||c.startsWith("/node_modules"))return t();let d="";if(c.endsWith(".html"))d=x.basename(c,".html");else if(c.startsWith("/")){let p=c.substring(1);if(i.find(m=>m.name===p))d=p;else{let m=p.split("/");if(m.length>1){let f=m[0];i.find(y=>y.name===f)&&(d=f,o(`History \u8DEF\u7531\u5339\u914D: ${c} -> ${f}`))}}}if(!d)return t();let u=i.find(p=>p.name===d);return u?K(s,u,e,o):t()}catch(a){o(`\u5F00\u53D1\u670D\u52A1\u5668\u5904\u7406\u8BF7\u6C42\u5931\u8D25: ${a}`),t(a)}}),o("\u5F00\u53D1\u670D\u52A1\u5668\u914D\u7F6E\u5B8C\u6210")}catch(r){throw o(`\u914D\u7F6E\u5F00\u53D1\u670D\u52A1\u5668\u5931\u8D25: ${r}`),r}}function K(n,e,o,r){let i={pageName:e.name,filePath:e.file,relativePath:x.relative(process.cwd(),e.file),strategy:void 0,isMatched:!1},l=O(o.pageConfigs,i,r);if(l?.strategy)i.strategy=l.strategy;else if(o.appliedStrategies?.has(e.name)){let c=o.appliedStrategies.get(e.name);c&&(i.strategy=c)}let g="",s=x.resolve(process.cwd(),`${e.name}.html`);if(E.existsSync(s)?g=s:l?.template?g=x.resolve(process.cwd(),l.template):g=x.resolve(process.cwd(),o.template),!E.existsSync(g)){n.statusCode=404,n.end("Template not found");return}let t=E.readFileSync(g,"utf-8");if(t.includes(o.placeholder)){let c=t;if(t=t.split(o.placeholder).join(`/${e.file}`),t===c){let d=W(o.placeholder),u=new RegExp(d,"g");t=c.replace(u,`/${e.file}`),t===c&&(t=c.replace(/\{\{ENTRY_FILE\}\}/g,`/${e.file}`))}}if(l?.define){let c=Object.entries(l.define).map(([d,u])=>{let p=typeof u=="string"?`"${u}"`:JSON.stringify(u);return`window.${d} = ${p};`}).join(`
|
|
2
2
|
`);c&&(t=t.replace(/<\/head>/i,`<script type="text/javascript">
|
|
3
3
|
${c}
|
|
4
4
|
</script>
|
|
@@ -98,7 +98,7 @@ ${c}
|
|
|
98
98
|
<p>${r}</p>
|
|
99
99
|
</body>
|
|
100
100
|
</html>
|
|
101
|
-
`}}import{mergeConfig as Z}from"vite";import{glob as H}from"glob";import*as h from"path";import*as b from"fs";function U(n){let{entry:e="src/pages/*/main.{ts,js}",exclude:o=[],template:r="index.html",placeholder:i="<!--VITE_MULTI_PAGE_ENTRY-->",strategies:l={},pageConfigs:g={},forceBuildStrategy:s}=n,t=_(!0),a={};try{let c=H.sync(e,{cwd:process.cwd()}),d=F(c,e,o,t);if(d.length===0)return t("\u8B66\u544A: \u672A\u627E\u5230\u5339\u914D\u7684\u5165\u53E3\u6587\u4EF6"),{};let u=new Map,p=new Map;for(let f of d){let y={pageName:f.name,filePath:f.file,relativePath:h.relative(process.cwd(),f.file)},C=O(g,y,t)?.strategy||"default";u.set(f.name,C),p.has(C)||p.set(C,[]),p.get(C)?.push(f.name)}if(t(`\u{1F4C4} \u53D1\u73B0 ${d.length} \u4E2A\u9875\u9762: ${d.map(f=>f.name).join(", ")}`),s){let f=p.get(s)||[];if(f.length===0)return t(`\u8B66\u544A: \u7B56\u7565 "${s}" \u4E0B\u6CA1\u6709\u9875\u9762`),{};t(`\u5F3A\u5236\u6784\u5EFA\u7B56\u7565: ${s}, \u9875\u9762: ${f.join(", ")}`);let y=N(s,f,d,l[s],g,r,i,t);return a[s]=y,a}for(let[f,y]of p){if(y.length===0)continue;let
|
|
101
|
+
`}}import{mergeConfig as Z}from"vite";import{glob as H}from"glob";import*as h from"path";import*as b from"fs";async function U(n){let{entry:e="src/pages/*/main.{ts,js}",exclude:o=[],template:r="index.html",placeholder:i="<!--VITE_MULTI_PAGE_ENTRY-->",strategies:l={},pageConfigs:g={},forceBuildStrategy:s}=n,t=_(!0),a={};try{let c=H.sync(e,{cwd:process.cwd()}),d=F(c,e,o,t);if(d.length===0)return t("\u8B66\u544A: \u672A\u627E\u5230\u5339\u914D\u7684\u5165\u53E3\u6587\u4EF6"),{};let u=new Map,p=new Map;for(let f of d){let y={pageName:f.name,filePath:f.file,relativePath:h.relative(process.cwd(),f.file)},C=O(g,y,t)?.strategy||"default";u.set(f.name,C),p.has(C)||p.set(C,[]),p.get(C)?.push(f.name)}if(t(`\u{1F4C4} \u53D1\u73B0 ${d.length} \u4E2A\u9875\u9762: ${d.map(f=>f.name).join(", ")}`),s){let f=p.get(s)||[];if(f.length===0)return t(`\u8B66\u544A: \u7B56\u7565 "${s}" \u4E0B\u6CA1\u6709\u9875\u9762`),{};t(`\u5F3A\u5236\u6784\u5EFA\u7B56\u7565: ${s}, \u9875\u9762: ${f.join(", ")}`);let y=await N(s,f,d,l[s],g,r,i,t);return a[s]=y,a}for(let[f,y]of p){if(y.length===0)continue;let P=l[f]||{},C=await N(f,y,d,P,g,r,i,t);a[f]=C}if(Object.keys(a).length===0){t("\u8B66\u544A: \u672A\u751F\u6210\u4EFB\u4F55\u6784\u5EFA\u914D\u7F6E\uFF0C\u521B\u5EFA\u9ED8\u8BA4\u914D\u7F6E");let f=d.map(P=>P.name),y=await N("default",f,d,{},g,r,i,t);a.default=y}let m=Object.keys(a);return t(`\u{1F4E6} \u6784\u5EFA\u7B56\u7565: ${m.join(", ")}`),a}catch(c){throw t("\u751F\u6210\u6784\u5EFA\u914D\u7F6E\u5931\u8D25:",c),c}}async function N(n,e,o,r,i,l,g,s){let t={},a=[],c={};for(let m of e){let f=o.find(M=>M.name===m);if(!f)continue;let y={pageName:m,filePath:f.file,relativePath:h.relative(process.cwd(),f.file),strategy:n},P=O(i,y,s);P?.define&&Object.assign(c,P.define);let C=l,V=`${m}.html`;b.existsSync(h.resolve(process.cwd(),V))?C=V:P?.template&&(C=P.template);let G=h.resolve(process.cwd(),C);if(!b.existsSync(G)){s(`\u8B66\u544A: \u6A21\u677F\u6587\u4EF6\u4E0D\u5B58\u5728: ${C}`);continue}let T=b.readFileSync(G,"utf-8");if(T.includes(g)){let M=`./${f.file}`;T=T.replace(new RegExp(g.replace(/[.*+?^${}()|[\]\\]/g,"\\$&"),"g"),M)}let I=h.resolve(process.cwd(),`.temp.mp.${m}.html`);b.writeFileSync(I,T),a.push(I),t[m]=I}let d={input:t,output:{entryFileNames:"assets/[name]-[hash].js",chunkFileNames:"assets/[name]-[hash].js",assetFileNames:"assets/[name]-[hash][extname]"}},u={base:"./",build:{outDir:`dist/${n}`,rollupOptions:d,rolldownOptions:d,emptyOutDir:!1},define:{}},p=u;return r&&(p=Z(u,r)),Object.keys(c).length>0&&(p.define={...p.define,...c}),p.build||(p.build={}),p.build.rollupOptions||(p.build.rollupOptions={}),p.build.rolldownOptions||(p.build.rolldownOptions={}),p.build.rollupOptions.input=t,p.build.rolldownOptions.input=t,p.build.emptyOutDir=!1,s(`\u7B56\u7565 "${n}" - ${e.length} \u4E2A\u9875\u9762`),p}function z(n=[]){let e=n.findIndex(r=>r==="--outDir");if(e!==-1&&e+1<n.length){let r=n[e+1];return h.resolve(process.cwd(),r)}let o=n.find(r=>r.startsWith("--outDir="));if(o){let r=o.split("=")[1];return h.resolve(process.cwd(),r)}return h.resolve(process.cwd(),"dist")}function ee(n=[]){let e=z(n),o=_(!0);try{b.existsSync(e)&&(b.rmSync(e,{recursive:!0,force:!0}),o(`\u{1F9F9} \u6E05\u7406\u8F93\u51FA\u76EE\u5F55: ${h.relative(process.cwd(),e)}`))}catch(r){o(`\u26A0\uFE0F \u6E05\u7406\u8F93\u51FA\u76EE\u5F55\u5931\u8D25: ${e}`,r)}}function te(n){let{entry:e="src/pages/*/main.{ts,js}",exclude:o=[],pageConfigs:r={}}=n,i=_(!1),l=new Set,g=H.sync(e,{cwd:process.cwd()}),s=F(g,e,o,i);if(s.length===0)throw new Error(`\u672A\u627E\u5230\u5339\u914D\u7684\u5165\u53E3\u6587\u4EF6: ${e}`);try{for(let t of s){let a={pageName:t.name,filePath:t.file,relativePath:h.relative(process.cwd(),t.file)},d=O(r,a,i)?.strategy||"default";l.add(d)}return Array.from(l).sort()}catch(t){return i("\u83B7\u53D6\u53EF\u7528\u7B56\u7565\u5931\u8D25:",t),["default"]}}import*as L from"fs";import*as A from"path";import{pathToFileURL as ne}from"url";import{createJiti as ie}from"jiti";var J=["multipage.config.ts","multipage.config.js","multipage.config.mjs"];function k(){for(let n of J){let e=A.resolve(process.cwd(),n);if(L.existsSync(e))return!0}return!1}async function B(n){let e=await oe();if(e){let o=e(n);return o||{}}return null}async function re(n){if(n.endsWith(".ts"))return ie(import.meta.url,{interopDefault:!0}).import(n);if(n.endsWith(".js")||n.endsWith(".mjs"))return import(`${ne(n).href}?t=${Date.now()}`);throw new Error(`\u4E0D\u652F\u6301\u7684\u914D\u7F6E\u6587\u4EF6\u7C7B\u578B: ${n}`)}async function oe(){let n=process.cwd();for(let e of J){let o=A.resolve(n,e);if(L.existsSync(o))try{let r=await re(o),i=r.default||r;if(typeof i=="function")return i;console.warn(`\u914D\u7F6E\u6587\u4EF6 ${e} \u5FC5\u987B\u9ED8\u8BA4\u5BFC\u51FA\u4E00\u4E2A\u51FD\u6570`)}catch(r){console.error(`\u52A0\u8F7D\u914D\u7F6E\u6587\u4EF6 ${e} \u5931\u8D25:`,r)}}return null}var $={entry:"src/pages/**/*.{ts,js}",exclude:[],template:"index.html",placeholder:"{{ENTRY_FILE}}",debug:!1,strategies:{default:{}},pageConfigs:{}};function R(n){if(!n)return{...$};let e=n.strategies??n.buildStrategies??$.strategies;return{entry:n.entry??$.entry,exclude:n.exclude??$.exclude,template:n.template??$.template,placeholder:n.placeholder??$.placeholder,debug:n.debug??$.debug,strategies:e,pageConfigs:n.pageConfigs??$.pageConfigs,__forceBuildStrategy:n.__forceBuildStrategy}}import*as D from"fs";function se(n){return typeof n=="function"?n:()=>n}function ae(n){return n}function le(n){let e,o=[],r=()=>{};return{name:"vite-multi-page",async configResolved(i){let l=null;k()&&(l=await B({mode:i.command==="serve"?"development":"production",command:i.command,isCLI:!1}));let g=R(l);e=n?n(g,{mode:i.command==="serve"?"development":"production",command:i.command,isCLI:!1}):g,r=e.debug??!1?console.log.bind(console,"[vite-multi-page]"):()=>{},r("Vite\u914D\u7F6E\u5DF2\u89E3\u6790, \u4F7F\u7528\u914D\u7F6E:",{strategies:Object.keys(e.strategies||{}),entry:e.entry})},async config(i,{command:l}){if(l==="serve"){let g=process.argv,s=g.find(t=>t.startsWith("--strategy="));if(s){let t=s.split("=")[1];t&&(process.env.VITE_MULTI_PAGE_STRATEGY=t)}else{let t=g.findIndex(a=>a==="--strategy");if(t!==-1&&t+1<g.length){let a=g[t+1];process.env.VITE_MULTI_PAGE_STRATEGY=a}}process.env.VITE_MULTI_PAGE_STRATEGY||(process.env.VITE_MULTI_PAGE_STRATEGY="default")}if(l==="build"){if(!e){let a=null;k()&&(a=await B({mode:"production",command:"build",isCLI:!1}));let c=R(a);e=n?n(c,{mode:"production",command:"build",isCLI:!1}):c,r=e.debug??!1?console.log.bind(console,"[vite-multi-page]"):()=>{}}r("\u914D\u7F6E\u6784\u5EFA\u6A21\u5F0F");let g=process.env.VITE_MULTI_PAGE_STRATEGY,s=await U({entry:e.entry||"src/pages/**/*.{ts,js}",exclude:e.exclude||[],template:e.template||"index.html",placeholder:e.placeholder||"{{ENTRY_FILE}}",strategies:e.strategies||{},pageConfigs:e.pageConfigs||{},forceBuildStrategy:g}),t=Object.keys(s)[0];if(t&&s[t]){r(`\u5E94\u7528\u6784\u5EFA\u7B56\u7565: ${t}`);let a=s[t],c=ge(i,a);Object.assign(i,c),r(`\u5DF2\u5E94\u7528\u7B56\u7565 "${t}" \u7684\u914D\u7F6E:`,{build:!!a.build,define:!!a.define,plugins:a.plugins?.length||0})}else throw r("\u672A\u627E\u5230\u53EF\u7528\u7684\u6784\u5EFA\u7B56\u7565\uFF0C\u4F7F\u7528\u9ED8\u8BA4\u914D\u7F6E"),new Error(`\u274C \u6784\u5EFA\u5931\u8D25: \u672A\u627E\u5230\u4EFB\u4F55\u6784\u5EFA\u7B56\u7565
|
|
102
102
|
|
|
103
103
|
\u53EF\u80FD\u7684\u539F\u56E0\uFF1A
|
|
104
104
|
1. \u914D\u7F6E\u6587\u4EF6\u8FD4\u56DE\u7A7A\u5BF9\u8C61 {}
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/dev-server.ts","../src/file-filter.ts","../src/utils.ts","../src/page-config.ts","../src/build-config.ts","../src/config-loader.ts","../src/defaults.ts","../src/types.ts"],"sourcesContent":["import type { Plugin } from 'vite';\nimport { mergeConfig } from 'vite';\nimport { setupDevMiddleware } from './dev-server';\nimport { generateBuildConfig } from './build-config';\nimport { loadUserConfig, hasCustomConfig } from './config-loader';\nimport { mergeWithDefaults } from './defaults';\nimport type { Options, ConfigTransformFunction } from './types';\nimport * as fs from 'fs';\n\n// 导出类型和工具函数\nexport { defineConfig, defineConfigTransform } from './types';\nexport type {\n ConfigFunction,\n ConfigTransformFunction,\n PluginContext,\n PageContext,\n PageConfig,\n} from './types';\n\nexport function viteMultiPage(transform?: ConfigTransformFunction): Plugin {\n let resolvedOptions: Options;\n const tempFiles: string[] = [];\n let log: (...args: any[]) => void = () => {}; // 默认为空函数\n\n return {\n name: 'vite-multi-page',\n\n async configResolved(config) {\n // 加载用户配置文件(如果存在)\n let userConfig: Options | null = null;\n\n if (hasCustomConfig()) {\n userConfig = await loadUserConfig({\n mode: config.command === 'serve' ? 'development' : 'production',\n command: config.command,\n isCLI: false,\n });\n }\n\n // 合并用户配置和默认配置\n const mergedConfig = mergeWithDefaults(userConfig);\n\n // 应用配置变换函数(如果提供)\n resolvedOptions = transform\n ? transform(mergedConfig, {\n mode: config.command === 'serve' ? 'development' : 'production',\n command: config.command,\n isCLI: false,\n })\n : mergedConfig;\n\n // 设置debug日志\n const debug = resolvedOptions.debug ?? false;\n log = debug ? console.log.bind(console, '[vite-multi-page]') : () => {};\n\n log('Vite配置已解析, 使用配置:', {\n strategies: Object.keys(resolvedOptions.strategies || {}),\n entry: resolvedOptions.entry,\n });\n },\n\n async config(config, { command }) {\n // 处理开发模式下的策略参数\n if (command === 'serve') {\n // 检查命令行参数中的策略设置\n const args = process.argv;\n\n // 查找 --strategy=value 格式的参数\n const strategyArg = args.find(arg => arg.startsWith('--strategy='));\n if (strategyArg) {\n const strategy = strategyArg.split('=')[1];\n if (strategy) {\n process.env.VITE_MULTI_PAGE_STRATEGY = strategy;\n }\n }\n // 查找 --strategy value 格式的参数\n else {\n const strategyIndex = args.findIndex(arg => arg === '--strategy');\n if (strategyIndex !== -1 && strategyIndex + 1 < args.length) {\n const strategy = args[strategyIndex + 1];\n process.env.VITE_MULTI_PAGE_STRATEGY = strategy;\n }\n }\n\n // 确保有默认策略\n if (!process.env.VITE_MULTI_PAGE_STRATEGY) {\n process.env.VITE_MULTI_PAGE_STRATEGY = 'default';\n }\n }\n if (command === 'build') {\n // 在config钩子中临时加载配置,因为configResolved还没运行\n if (!resolvedOptions) {\n // 加载用户配置文件(如果存在)\n let userConfig: Options | null = null;\n\n if (hasCustomConfig()) {\n userConfig = await loadUserConfig({\n mode: 'production',\n command: 'build',\n isCLI: false,\n });\n }\n\n // 合并用户配置和默认配置\n const mergedConfig = mergeWithDefaults(userConfig);\n\n // 应用配置变换函数(如果提供)\n resolvedOptions = transform\n ? transform(mergedConfig, {\n mode: 'production',\n command: 'build',\n isCLI: false,\n })\n : mergedConfig;\n const debug = resolvedOptions.debug ?? false;\n log = debug ? console.log.bind(console, '[vite-multi-page]') : () => {};\n }\n\n log('配置构建模式');\n\n // 策略构建模式:生成构建配置\n const forceBuildStrategy = process.env.VITE_MULTI_PAGE_STRATEGY;\n const buildConfigs = generateBuildConfig({\n entry: resolvedOptions.entry || 'src/pages/**/*.{ts,js}',\n exclude: resolvedOptions.exclude || [],\n template: resolvedOptions.template || 'index.html',\n placeholder: resolvedOptions.placeholder || '{{ENTRY_FILE}}',\n strategies: resolvedOptions.strategies || {},\n pageConfigs: resolvedOptions.pageConfigs || {},\n forceBuildStrategy,\n });\n\n // 应用构建配置中的策略(如果有forceBuildStrategy,buildConfigs只会包含该策略)\n const targetStrategy = Object.keys(buildConfigs)[0];\n\n if (targetStrategy && buildConfigs[targetStrategy]) {\n log(`应用构建策略: ${targetStrategy}`);\n const strategyConfig = buildConfigs[targetStrategy];\n\n // 使用Vite的mergeConfig进行智能深度合并\n const mergedConfig = mergeConfig(config, strategyConfig);\n\n // 将合并结果复制回config对象\n Object.assign(config, mergedConfig);\n\n log(`已应用策略 \"${targetStrategy}\" 的配置:`, {\n build: !!strategyConfig.build,\n define: !!strategyConfig.define,\n plugins: strategyConfig.plugins?.length || 0,\n });\n } else {\n log('未找到可用的构建策略,使用默认配置');\n\n throw new Error(\n '❌ 构建失败: 未找到任何构建策略\\n\\n' +\n '可能的原因:\\n' +\n ' 1. 配置文件返回空对象 {}\\n' +\n ' 2. 未找到匹配的入口文件\\n' +\n ' 3. 模板文件不存在\\n' +\n ' 4. 未配置 strategies 对象\\n\\n' +\n '最小配置示例:\\n' +\n 'export default () => ({\\n' +\n ' entry: \"src/pages/**/*.{ts,js}\",\\n' +\n ' template: \"index.html\",\\n' +\n ' strategies: {\\n' +\n ' default: {}\\n' +\n ' }\\n' +\n '});'\n );\n }\n }\n },\n\n configureServer(server) {\n if (server.config.command === 'serve') {\n log('配置开发服务器');\n\n // 处理开发模式下的策略参数\n // 从环境变量中获取策略,默认为 default\n const devStrategy = process.env.VITE_MULTI_PAGE_STRATEGY || 'default';\n\n log(`开发模式策略: ${devStrategy}`);\n\n setupDevMiddleware(\n server,\n {\n entry: resolvedOptions.entry || 'src/pages/**/*.{ts,js}',\n exclude: resolvedOptions.exclude || [],\n template: resolvedOptions.template || 'index.html',\n placeholder: resolvedOptions.placeholder || '{{ENTRY_FILE}}',\n strategies: resolvedOptions.strategies || {},\n pageConfigs: resolvedOptions.pageConfigs || {},\n devStrategy: devStrategy, // 传递策略给开发服务器\n },\n log\n );\n }\n },\n\n writeBundle() {\n // 构建完成,无需额外处理\n // 每个策略已经直接输出到对应的目录\n },\n\n buildEnd() {\n // 清理临时文件\n if (tempFiles.length > 0) {\n log(`清理 ${tempFiles.length} 个临时文件`);\n tempFiles.forEach(file => {\n try {\n if (fs.existsSync(file)) {\n fs.unlinkSync(file);\n log(`删除临时文件: ${file}`);\n }\n } catch (error) {\n log(`删除临时文件失败: ${file}`, error);\n }\n });\n tempFiles.length = 0;\n }\n },\n };\n}\n\nexport default viteMultiPage;\nexport type { Options } from './types';\nexport {\n generateBuildConfig,\n getAvailableStrategies,\n getViteOutputDirectory,\n cleanViteOutputDirectory,\n} from './build-config';\nexport { mergeWithDefaults } from './defaults';\n","import type { ViteDevServer } from 'vite';\nimport * as path from 'node:path';\nimport * as fs from 'node:fs';\nimport { glob } from 'glob';\nimport { filterEntryFiles } from './file-filter';\nimport { escapeRegExp } from './utils';\nimport { DevServerOptions, PageConfigContext } from './types';\nimport { getPageConfig } from './page-config';\n\nexport function configureDevServer(\n server: ViteDevServer,\n options: DevServerOptions,\n log: (...args: any[]) => void\n) {\n try {\n const allFiles = glob.sync(options.entry, { cwd: process.cwd() });\n let entryFiles = filterEntryFiles(allFiles, options.entry, options.exclude, log);\n\n if (entryFiles.length === 0) {\n log('警告: 未找到匹配的入口文件');\n return;\n }\n\n // 获取指定的策略,优先使用开发模式传入的策略\n const cliStrategy =\n options.devStrategy ||\n (((server.config as any).__cliStrategy || (server.config as any).strategy) as\n | string\n | undefined);\n\n // 如果指定了策略,则只显示该策略下的页面或没有指定策略的默认页面\n if (cliStrategy) {\n log(`开发服务器使用指定的策略: ${cliStrategy}`);\n\n // 过滤入口文件,只保留匹配策略的页面\n entryFiles = entryFiles.filter(file => {\n // 动态获取页面策略\n const pageContext = {\n pageName: file.name,\n filePath: file.file,\n relativePath: path.relative(process.cwd(), file.file),\n strategy: undefined,\n isMatched: false,\n } as PageConfigContext;\n\n const pageConfig = getPageConfig(options.pageConfigs, pageContext, log);\n const pageStrategy = pageConfig?.strategy || 'default';\n\n // 在指定策略为default时,包含所有没有指定策略的页面\n if (cliStrategy === 'default') {\n return pageStrategy === 'default';\n }\n\n // 其他策略,只包含匹配的页面\n return pageStrategy === cliStrategy;\n });\n\n log(`策略 \"${cliStrategy}\" 下可用的页面: ${entryFiles.map(f => f.name).join(', ') || '无'}`);\n }\n\n log('开发服务器应用的入口文件:', entryFiles);\n\n // 修改中间件来处理HTML请求\n server.middlewares.use(async (req, res, next) => {\n try {\n const url = req.url || '';\n const pathWithoutQuery = url.split('?')[0];\n\n // 处理根路径请求 - 显示所有页面的索引\n if (pathWithoutQuery === '/') {\n const indexHtml = generateIndexHtml(entryFiles, options, log);\n res.statusCode = 200;\n res.setHeader('Content-Type', 'text/html');\n res.end(indexHtml);\n return;\n }\n\n // 跳过明显的静态资源请求\n if (\n pathWithoutQuery.match(/\\.(js|css|png|jpg|jpeg|gif|svg|ico|woff|woff2|ttf|eot|map)$/) &&\n !pathWithoutQuery.endsWith('.html')\n ) {\n return next();\n }\n\n // 跳过以@开头的特殊路径(如Vite的特殊路径)\n if (pathWithoutQuery.startsWith('/@')) {\n return next();\n }\n\n // 跳过 __vite_ping 和其他 Vite 内部路径\n if (pathWithoutQuery.includes('__vite') || pathWithoutQuery.startsWith('/node_modules')) {\n return next();\n }\n\n // 提取页面名称,支持 history 路由\n let pageName = '';\n\n // 1. 处理带 .html 后缀的请求\n if (pathWithoutQuery.endsWith('.html')) {\n pageName = path.basename(pathWithoutQuery, '.html');\n }\n // 2. 处理精确匹配的页面路径,如 /mobile\n else if (pathWithoutQuery.startsWith('/')) {\n const cleanPath = pathWithoutQuery.substring(1); // 移除开头的斜杠\n\n // 首先尝试精确匹配\n if (entryFiles.find(file => file.name === cleanPath)) {\n pageName = cleanPath;\n }\n // 然后尝试 history 路由匹配,如 /home/login -> home\n else {\n const segments = cleanPath.split('/');\n if (segments.length > 1) {\n const possiblePageName = segments[0];\n if (entryFiles.find(file => file.name === possiblePageName)) {\n pageName = possiblePageName;\n log(`History 路由匹配: ${pathWithoutQuery} -> ${possiblePageName}`);\n }\n }\n }\n }\n\n if (!pageName) {\n return next();\n }\n\n const matchedFile = entryFiles.find(file => file.name === pageName);\n\n if (!matchedFile) {\n return next();\n }\n\n return servePageHtml(res, matchedFile, options, log);\n } catch (error) {\n log(`开发服务器处理请求失败: ${error}`);\n next(error);\n }\n });\n\n log('开发服务器配置完成');\n } catch (error) {\n log(`配置开发服务器失败: ${error}`);\n throw error;\n }\n}\n\n// 提取页面HTML服务逻辑\nfunction servePageHtml(\n res: any,\n matchedFile: { name: string; file: string },\n options: DevServerOptions,\n log: (...args: any[]) => void\n) {\n // 获取页面配置\n const pageContext = {\n pageName: matchedFile.name,\n filePath: matchedFile.file,\n relativePath: path.relative(process.cwd(), matchedFile.file),\n strategy: undefined,\n isMatched: false,\n } as PageConfigContext;\n\n const pageConfig = getPageConfig(options.pageConfigs, pageContext, log);\n\n // 应用配置策略\n if (pageConfig?.strategy) {\n pageContext.strategy = pageConfig.strategy;\n } else if (options.appliedStrategies?.has(matchedFile.name)) {\n // 使用缓存的策略信息\n const strategyName = options.appliedStrategies.get(matchedFile.name);\n if (strategyName) {\n pageContext.strategy = strategyName;\n }\n }\n\n // 获取模板文件路径\n // 首先检查是否有页面特定的模板(例如mobile.html对应mobile页面)\n let templatePath = '';\n\n // 尝试以页面名称查找匹配的模板\n const pageSpecificTemplate = path.resolve(process.cwd(), `${matchedFile.name}.html`);\n if (fs.existsSync(pageSpecificTemplate)) {\n templatePath = pageSpecificTemplate;\n }\n // 然后尝试使用页面配置中指定的模板\n else if (pageConfig?.template) {\n templatePath = path.resolve(process.cwd(), pageConfig.template);\n }\n // 最后使用默认模板\n else {\n templatePath = path.resolve(process.cwd(), options.template);\n }\n\n if (!fs.existsSync(templatePath)) {\n res.statusCode = 404;\n res.end('Template not found');\n return;\n }\n\n // 读取并修改模板\n let html = fs.readFileSync(templatePath, 'utf-8');\n\n // 检查模板中是否包含占位符\n const containsPlaceholder = html.includes(options.placeholder);\n\n // 替换占位符为入口文件路径\n if (containsPlaceholder) {\n const originalHtml = html;\n\n // 方式1: 直接字符串替换\n html = html.split(options.placeholder).join(`/${matchedFile.file}`);\n\n // 检查替换结果\n if (html === originalHtml) {\n // 方式2: 正则表达式替换\n const escapedPlaceholder = escapeRegExp(options.placeholder);\n const placeholderRegex = new RegExp(escapedPlaceholder, 'g');\n html = originalHtml.replace(placeholderRegex, `/${matchedFile.file}`);\n\n // 检查替换结果\n if (html === originalHtml) {\n // 方式3: 硬编码替换具体的占位符格式\n html = originalHtml.replace(/\\{\\{ENTRY_FILE\\}\\}/g, `/${matchedFile.file}`);\n }\n }\n }\n\n // 添加页面级define变量\n if (pageConfig?.define) {\n const defineScript = Object.entries(pageConfig.define)\n .map(([key, value]) => {\n const stringValue = typeof value === 'string' ? `\"${value}\"` : JSON.stringify(value);\n return `window.${key} = ${stringValue};`;\n })\n .join('\\n');\n\n if (defineScript) {\n // 注入到head标签底部\n html = html.replace(\n /<\\/head>/i,\n `<script type=\"text/javascript\">\\n${defineScript}\\n</script>\\n</head>`\n );\n }\n }\n\n // 发送响应\n res.statusCode = 200;\n res.setHeader('Content-Type', 'text/html');\n res.end(html);\n}\n\n// 为了兼容性,导出setupDevMiddleware作为configureDevServer的别名\nexport const setupDevMiddleware = configureDevServer;\n\n// 生成索引页面HTML\nfunction generateIndexHtml(\n entryFiles: { name: string; file: string }[],\n options: DevServerOptions,\n log: (...args: any[]) => void\n): string {\n try {\n const pageItems = entryFiles\n .map(file => {\n // 获取页面配置和策略\n const pageContext = {\n pageName: file.name,\n filePath: file.file,\n relativePath: path.relative(process.cwd(), file.file),\n strategy: undefined,\n isMatched: false,\n };\n\n const pageConfig = getPageConfig(options.pageConfigs, pageContext, log);\n\n // 确定策略\n let strategy = 'default';\n if (pageConfig?.strategy) {\n strategy = pageConfig.strategy;\n } else if (options.appliedStrategies?.has(file.name)) {\n const strategyName = options.appliedStrategies.get(file.name);\n if (strategyName) {\n strategy = strategyName;\n }\n }\n\n const strategyBadge =\n strategy !== 'default' ? `<span class=\"badge\">${strategy}</span>` : '';\n\n return `\n <div class=\"page-item\">\n <a href=\"${file.name}.html\" class=\"page-link\">\n ${file.name}${strategyBadge}\n </a>\n <div class=\"page-path\">${file.file}</div>\n </div>`;\n })\n .join('');\n\n return `\n <!DOCTYPE html>\n <html lang=\"en\">\n <head>\n <meta charset=\"UTF-8\">\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n <title>多页面应用索引</title>\n <style>\n body {\n font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, Helvetica, Arial, sans-serif;\n line-height: 1.6;\n color: #333;\n max-width: 1200px;\n margin: 0 auto;\n padding: 20px;\n background-color: #f5f5f7;\n }\n h1 {\n font-size: 24px;\n margin-bottom: 20px;\n color: #111;\n }\n .page-list {\n display: grid;\n grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));\n gap: 16px;\n }\n .page-item {\n background-color: white;\n border-radius: 8px;\n padding: 16px;\n box-shadow: 0 1px 3px rgba(0,0,0,0.1);\n transition: transform 0.2s, box-shadow 0.2s;\n }\n .page-item:hover {\n transform: translateY(-2px);\n box-shadow: 0 4px 8px rgba(0,0,0,0.1);\n }\n .page-link {\n display: flex;\n align-items: center;\n justify-content: space-between;\n font-size: 18px;\n font-weight: 500;\n color: #0066cc;\n text-decoration: none;\n margin-bottom: 8px;\n }\n .page-path {\n font-size: 14px;\n color: #666;\n word-break: break-all;\n }\n .badge {\n display: inline-block;\n font-size: 12px;\n padding: 2px 8px;\n border-radius: 12px;\n background-color: #e6f2ff;\n color: #0066cc;\n margin-left: 8px;\n }\n .stats {\n margin-bottom: 20px;\n font-size: 14px;\n color: #666;\n }\n </style>\n </head>\n <body>\n <h1>多页面应用索引</h1>\n <div class=\"stats\">\n 找到 ${entryFiles.length} 个页面\n </div>\n <div class=\"page-list\">\n ${pageItems}\n </div>\n </body>\n </html>\n `;\n } catch (error) {\n log(`生成索引页失败: ${error}`);\n return `\n <!DOCTYPE html>\n <html>\n <head>\n <title>错误</title>\n </head>\n <body>\n <h1>生成索引页时发生错误</h1>\n <p>${error}</p>\n </body>\n </html>\n `;\n }\n}\n","import * as path from 'node:path';\nimport type { EntryFile, CandidateFile } from './types';\n\nexport function filterEntryFiles(\n files: string[],\n entry: string,\n exclude: string[],\n _log: (...args: any[]) => void\n): EntryFile[] {\n const result: EntryFile[] = [];\n const nameToFile = new Map<string, { file: string; priority: number }>();\n\n // 从entry模式中提取基础目录\n let basePattern = entry.replace(/\\/\\*.*$/, ''); // 去掉glob部分\n // 如果基础模式为空或不合理,使用默认处理\n if (!basePattern || basePattern === entry) {\n basePattern = path.dirname(entry.split('*')[0]);\n }\n const candidateFiles: CandidateFile[] = [];\n\n for (const file of files) {\n if (exclude.includes(file)) {\n continue;\n }\n\n // 统一使用正斜杠处理路径,确保Windows兼容性\n const normalizedFile = file.replace(/\\\\/g, '/');\n const normalizedBasePattern = basePattern.replace(/\\\\/g, '/');\n\n const relativePath = path.posix.relative(normalizedBasePattern, normalizedFile);\n const pathParts = relativePath.split('/'); // 使用正斜杠分割\n\n if (pathParts.length === 1) {\n // 第一级文件:src/pages/about.js -> /about.html\n const fileName = pathParts[0];\n const name = path.posix.basename(fileName, path.posix.extname(fileName));\n candidateFiles.push({ name, file, priority: 1 });\n } else if (pathParts.length >= 2) {\n // 目录下的文件\n const fileName = path.posix.basename(normalizedFile, path.posix.extname(normalizedFile));\n const dirName = pathParts[0];\n\n if (fileName === 'main') {\n // 目录下的main文件:src/pages/mobile/main.ts -> /mobile.html\n candidateFiles.push({ name: dirName, file, priority: 2 });\n }\n }\n }\n\n // 按照优先级处理冲突:目录优先覆盖文件(优先级2 > 优先级1)\n for (const candidate of candidateFiles) {\n const existing = nameToFile.get(candidate.name);\n\n if (!existing) {\n nameToFile.set(candidate.name, { file: candidate.file, priority: candidate.priority });\n } else {\n if (candidate.priority > existing.priority) {\n nameToFile.set(candidate.name, { file: candidate.file, priority: candidate.priority });\n }\n }\n }\n\n for (const [name, { file }] of nameToFile.entries()) {\n result.push({ name, file });\n }\n\n return result;\n}\n","export function escapeRegExp(string: string): string {\n return string.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n}\n\nexport function createLogger(debug: boolean) {\n return (...args: any[]) => {\n if (debug) {\n console.log('[vite-plugin-multi-page]', ...args);\n }\n };\n}\n","import type { PageConfig, PageConfigFunction, PageConfigContext } from './types';\n\n/**\n * 根据页面上下文获取页面配置\n */\nexport function getPageConfig(\n pageConfigs: Record<string, PageConfig> | PageConfigFunction | undefined,\n context: PageConfigContext,\n log: (...args: any[]) => void\n): PageConfig | null {\n if (!pageConfigs) return null;\n\n // 如果是函数,直接调用\n if (typeof pageConfigs === 'function') {\n const result = pageConfigs(context);\n return result;\n }\n\n // 对象配置:支持精确匹配和模式匹配\n for (const [key, config] of Object.entries(pageConfigs)) {\n // 精确匹配页面名称\n if (key === context.pageName) {\n log(`精确匹配页面 ${context.pageName}:`, config);\n return config;\n }\n\n // 模式匹配\n if (config.match) {\n const patterns = Array.isArray(config.match) ? config.match : [config.match];\n const isMatched = patterns.some(\n pattern =>\n simpleMatch(pattern, context.pageName) ||\n simpleMatch(pattern, context.relativePath) ||\n simpleMatch(pattern, context.filePath)\n );\n\n if (isMatched) {\n log(`模式匹配页面 ${context.pageName} (模式: ${config.match}):`, config);\n return { ...config, match: undefined };\n }\n }\n\n // glob 模式匹配页面名称\n if (simpleMatch(key, context.pageName)) {\n log(`Glob匹配页面 ${context.pageName} (模式: ${key}):`, config);\n return config;\n }\n }\n\n return null;\n}\n\n/**\n * 简单的模式匹配函数\n */\nfunction simpleMatch(pattern: string, text: string): boolean {\n const regexPattern = pattern\n .replace(/\\*\\*/g, '__DOUBLE_STAR__')\n .replace(/\\*/g, '[^/]*')\n .replace(/__DOUBLE_STAR__/g, '.*');\n const regex = new RegExp(`^${regexPattern}$`);\n return regex.test(text);\n}\n","import type { UserConfig } from 'vite';\nimport { mergeConfig } from 'vite';\nimport { glob } from 'glob';\nimport * as path from 'node:path';\nimport * as fs from 'node:fs';\nimport { filterEntryFiles } from './file-filter';\nimport { getPageConfig } from './page-config';\nimport type { BuildConfigOptions, PageConfigContext, ConfigStrategy } from './types';\nimport { createLogger } from './utils';\n\n/**\n * 构建时配置生成器\n * 根据策略和页面配置生成多页面构建配置\n */\nexport function generateBuildConfig(options: BuildConfigOptions): Record<string, UserConfig> {\n const {\n entry = 'src/pages/*/main.{ts,js}',\n exclude = [],\n template = 'index.html',\n placeholder = '<!--VITE_MULTI_PAGE_ENTRY-->',\n strategies = {},\n pageConfigs = {},\n forceBuildStrategy,\n } = options;\n\n const log = createLogger(true);\n const buildConfigs: Record<string, UserConfig> = {};\n\n try {\n // 1. 发现所有页面入口文件\n const allFiles = glob.sync(entry, { cwd: process.cwd() });\n const entryFiles = filterEntryFiles(allFiles, entry, exclude, log);\n\n if (entryFiles.length === 0) {\n log('警告: 未找到匹配的入口文件');\n return {};\n }\n\n // 2. 为每个页面分析配置和策略\n const pageStrategies = new Map<string, string>();\n const strategyPages = new Map<string, string[]>();\n\n for (const entryFile of entryFiles) {\n const pageContext = {\n pageName: entryFile.name,\n filePath: entryFile.file,\n relativePath: path.relative(process.cwd(), entryFile.file),\n } as PageConfigContext;\n\n // 获取页面配置\n const pageConfig = getPageConfig(pageConfigs, pageContext, log);\n const strategyName = pageConfig?.strategy || 'default';\n\n pageStrategies.set(entryFile.name, strategyName);\n\n if (!strategyPages.has(strategyName)) {\n strategyPages.set(strategyName, []);\n }\n strategyPages.get(strategyName)?.push(entryFile.name);\n }\n\n log(`📄 发现 ${entryFiles.length} 个页面: ${entryFiles.map(f => f.name).join(', ')}`);\n\n // 3. 如果指定了强制策略,只构建该策略的页面\n if (forceBuildStrategy) {\n const targetPages = strategyPages.get(forceBuildStrategy) || [];\n if (targetPages.length === 0) {\n log(`警告: 策略 \"${forceBuildStrategy}\" 下没有页面`);\n return {};\n }\n\n log(`强制构建策略: ${forceBuildStrategy}, 页面: ${targetPages.join(', ')}`);\n\n const config = generateStrategyConfig(\n forceBuildStrategy,\n targetPages,\n entryFiles,\n strategies[forceBuildStrategy],\n pageConfigs,\n template,\n placeholder,\n log\n );\n\n buildConfigs[forceBuildStrategy] = config;\n return buildConfigs;\n }\n\n // 4. 为每个策略生成构建配置\n for (const [strategyName, pages] of strategyPages) {\n if (pages.length === 0) continue;\n\n // 获取策略配置,如果没有定义则使用空配置(允许默认策略)\n const strategyConfig = strategies[strategyName] || {};\n const config = generateStrategyConfig(\n strategyName,\n pages,\n entryFiles,\n strategyConfig,\n pageConfigs,\n template,\n placeholder,\n log\n );\n\n buildConfigs[strategyName] = config;\n }\n\n // 确保至少有一个构建配置\n if (Object.keys(buildConfigs).length === 0) {\n log('警告: 未生成任何构建配置,创建默认配置');\n\n // 如果没有任何策略,创建一个默认策略包含所有页面\n const allPageNames = entryFiles.map(f => f.name);\n const defaultConfig = generateStrategyConfig(\n 'default',\n allPageNames,\n entryFiles,\n {},\n pageConfigs,\n template,\n placeholder,\n log\n );\n\n buildConfigs['default'] = defaultConfig;\n }\n\n const strategyNames = Object.keys(buildConfigs);\n log(`📦 构建策略: ${strategyNames.join(', ')}`);\n return buildConfigs;\n } catch (error) {\n log('生成构建配置失败:', error);\n throw error;\n }\n}\n\n/**\n * 为特定策略生成构建配置\n */\nfunction generateStrategyConfig(\n strategyName: string,\n pages: string[],\n entryFiles: Array<{ name: string; file: string }>,\n strategyConfig: ConfigStrategy | undefined,\n pageConfigs: any,\n defaultTemplate: string,\n placeholder: string,\n log: (...args: any[]) => void\n): UserConfig {\n const htmlInputs: Record<string, string> = {};\n const tempFiles: string[] = [];\n\n // 收集所有页面的 define 变量\n const allPageDefines: Record<string, any> = {};\n\n // 为每个页面确定使用的HTML模板并创建临时文件\n for (const pageName of pages) {\n const entryFile = entryFiles.find(f => f.name === pageName);\n if (!entryFile) continue;\n\n // 获取页面配置\n const pageContext = {\n pageName,\n filePath: entryFile.file,\n relativePath: path.relative(process.cwd(), entryFile.file),\n strategy: strategyName,\n } as PageConfigContext;\n\n const pageConfig = getPageConfig(pageConfigs, pageContext, log);\n\n // 收集页面级 define 变量\n if (pageConfig?.define) {\n Object.assign(allPageDefines, pageConfig.define);\n }\n\n // 确定HTML模板\n let templatePath = defaultTemplate;\n\n // 1. 页面特定模板(如 mobile.html 对应 mobile 页面)\n const pageSpecificTemplate = `${pageName}.html`;\n if (fs.existsSync(path.resolve(process.cwd(), pageSpecificTemplate))) {\n templatePath = pageSpecificTemplate;\n }\n // 2. 页面配置中指定的模板\n else if (pageConfig?.template) {\n templatePath = pageConfig.template;\n }\n\n // 读取模板内容\n const templateFullPath = path.resolve(process.cwd(), templatePath);\n if (!fs.existsSync(templateFullPath)) {\n log(`警告: 模板文件不存在: ${templatePath}`);\n continue;\n }\n\n let templateContent = fs.readFileSync(templateFullPath, 'utf-8');\n\n // 替换占位符\n if (templateContent.includes(placeholder)) {\n // 临时HTML在项目根目录中,使用相对路径\n const entryPath = `./${entryFile.file}`;\n templateContent = templateContent.replace(\n new RegExp(placeholder.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&'), 'g'),\n entryPath\n );\n }\n\n // 创建临时HTML文件,使用新的命名规则:.temp.mp.[name].html\n const tempHtmlPath = path.resolve(process.cwd(), `.temp.mp.${pageName}.html`);\n fs.writeFileSync(tempHtmlPath, templateContent);\n tempFiles.push(tempHtmlPath);\n\n htmlInputs[pageName] = tempHtmlPath;\n }\n\n const buildOptions: Record<string, any> = {\n input: htmlInputs,\n output: {\n entryFileNames: 'assets/[name]-[hash].js',\n chunkFileNames: 'assets/[name]-[hash].js',\n assetFileNames: 'assets/[name]-[hash][extname]',\n },\n };\n\n const baseConfig: UserConfig = {\n base: './',\n build: {\n outDir: `dist/${strategyName}`,\n rollupOptions: buildOptions,\n rolldownOptions: buildOptions,\n emptyOutDir: false,\n },\n define: {},\n };\n\n let config: UserConfig = baseConfig;\n\n if (strategyConfig) {\n config = mergeConfig(baseConfig, strategyConfig);\n }\n\n if (Object.keys(allPageDefines).length > 0) {\n config.define = {\n ...config.define,\n ...allPageDefines,\n };\n }\n\n if (!config.build) config.build = {};\n if (!config.build.rollupOptions) config.build.rollupOptions = {};\n if (!(config.build as any).rolldownOptions) (config.build as any).rolldownOptions = {};\n\n config.build.rollupOptions.input = htmlInputs;\n (config.build as any).rolldownOptions.input = htmlInputs;\n config.build.emptyOutDir = false;\n\n // 简化日志输出\n log(`策略 \"${strategyName}\" - ${pages.length} 个页面`);\n\n return config;\n}\n\n/**\n * 获取Vite配置的输出目录\n * 需要传入已解析的Vite配置或命令行参数\n */\nexport function getViteOutputDirectory(viteBuildArgs: string[] = []): string {\n // 1. 首先检查命令行参数中的 --outDir\n const outDirIndex = viteBuildArgs.findIndex(arg => arg === '--outDir');\n if (outDirIndex !== -1 && outDirIndex + 1 < viteBuildArgs.length) {\n const outDir = viteBuildArgs[outDirIndex + 1];\n return path.resolve(process.cwd(), outDir);\n }\n\n // 2. 检查 --outDir=value 格式\n const outDirArg = viteBuildArgs.find(arg => arg.startsWith('--outDir='));\n if (outDirArg) {\n const outDir = outDirArg.split('=')[1];\n return path.resolve(process.cwd(), outDir);\n }\n\n // 3. 如果没有命令行参数,使用 Vite 默认值\n // 注意:如果用户在 vite.config.ts 中配置了 build.outDir,\n // Vite 会自动使用该配置,我们这里只处理命令行参数的情况\n return path.resolve(process.cwd(), 'dist');\n}\n\n/**\n * 清理Vite配置的输出目录\n */\nexport function cleanViteOutputDirectory(viteBuildArgs: string[] = []): void {\n const outputDir = getViteOutputDirectory(viteBuildArgs);\n const log = createLogger(true);\n\n try {\n if (fs.existsSync(outputDir)) {\n fs.rmSync(outputDir, { recursive: true, force: true });\n log(`🧹 清理输出目录: ${path.relative(process.cwd(), outputDir)}`);\n }\n } catch (error) {\n log(`⚠️ 清理输出目录失败: ${outputDir}`, error);\n }\n}\n\n/**\n * 获取所有可用的构建策略\n */\nexport function discoverPages(options: BuildConfigOptions): Array<{ name: string; file: string }> {\n const { entry = 'src/pages/*/main.{ts,js}', exclude = [] } = options;\n\n const log = createLogger(true);\n\n try {\n // 发现所有页面入口文件\n const allFiles = glob.sync(entry, { cwd: process.cwd() });\n const entryFiles = filterEntryFiles(allFiles, entry, exclude, log);\n\n return entryFiles;\n } catch (error) {\n log('发现页面失败:', error);\n throw error;\n }\n}\n\nexport function getAvailableStrategies(options: BuildConfigOptions): string[] {\n const { entry = 'src/pages/*/main.{ts,js}', exclude = [], pageConfigs = {} } = options;\n\n const log = createLogger(false); // 静默模式\n const strategySet = new Set<string>();\n\n // 发现所有页面入口文件\n const allFiles = glob.sync(entry, { cwd: process.cwd() });\n const entryFiles = filterEntryFiles(allFiles, entry, exclude, log);\n\n if (entryFiles.length === 0) {\n throw new Error(`未找到匹配的入口文件: ${entry}`);\n }\n\n try {\n // 分析每个页面的策略\n for (const entryFile of entryFiles) {\n const pageContext = {\n pageName: entryFile.name,\n filePath: entryFile.file,\n relativePath: path.relative(process.cwd(), entryFile.file),\n } as PageConfigContext;\n\n const pageConfig = getPageConfig(pageConfigs, pageContext, log);\n const strategyName = pageConfig?.strategy || 'default';\n strategySet.add(strategyName);\n }\n\n // 只返回实际有页面的策略,不添加空策略\n return Array.from(strategySet).sort();\n } catch (error) {\n log('获取可用策略失败:', error);\n return ['default'];\n }\n}\n","import * as fs from 'node:fs';\nimport * as path from 'node:path';\nimport { pathToFileURL } from 'node:url';\nimport { createJiti } from 'jiti';\nimport type { Options } from './types';\n\nexport interface ConfigContext {\n mode: 'development' | 'production';\n command: 'serve' | 'build';\n isCLI?: boolean;\n}\n\nexport type ConfigFunction = (context: ConfigContext) => Options;\n\nconst CONFIG_FILES = [\n 'multipage.config.ts',\n 'multipage.config.js',\n 'multipage.config.mjs',\n] as const;\n\nexport function hasCustomConfig(): boolean {\n for (const filename of CONFIG_FILES) {\n const configPath = path.resolve(process.cwd(), filename);\n if (fs.existsSync(configPath)) {\n return true;\n }\n }\n return false;\n}\n\nexport async function loadUserConfig(context: ConfigContext): Promise<Options | null> {\n const customConfig = await loadCustomConfig();\n\n if (customConfig) {\n const result = customConfig(context);\n\n if (!result) {\n return {};\n }\n\n return result;\n }\n\n return null;\n}\n\nasync function loadConfigFile(filePath: string): Promise<any> {\n if (filePath.endsWith('.ts')) {\n const jiti = createJiti(import.meta.url, { interopDefault: true });\n return jiti.import(filePath);\n }\n\n if (filePath.endsWith('.js') || filePath.endsWith('.mjs')) {\n const fileUrl = pathToFileURL(filePath).href;\n return import(`${fileUrl}?t=${Date.now()}`);\n }\n\n throw new Error(`不支持的配置文件类型: ${filePath}`);\n}\n\nasync function loadCustomConfig(): Promise<ConfigFunction | null> {\n const cwd = process.cwd();\n\n for (const configFile of CONFIG_FILES) {\n const configPath = path.resolve(cwd, configFile);\n\n if (fs.existsSync(configPath)) {\n try {\n const configModule = await loadConfigFile(configPath);\n const configFunction = configModule.default || configModule;\n\n if (typeof configFunction === 'function') {\n return configFunction;\n } else {\n console.warn(`配置文件 ${configFile} 必须默认导出一个函数`);\n }\n } catch (error) {\n console.error(`加载配置文件 ${configFile} 失败:`, error);\n }\n }\n }\n\n return null;\n}\n","import type { MultiPageOptions } from './types';\n\n/**\n * 默认配置选项\n */\nexport const DEFAULT_CONFIG: Required<\n Omit<MultiPageOptions, '__forceBuildStrategy' | 'buildStrategies'>\n> = {\n entry: 'src/pages/**/*.{ts,js}',\n exclude: [],\n template: 'index.html',\n placeholder: '{{ENTRY_FILE}}',\n debug: false,\n strategies: {\n default: {},\n },\n pageConfigs: {},\n};\n\n/**\n * 合并用户配置和默认配置\n */\nexport function mergeWithDefaults(\n userConfig: MultiPageOptions | null | undefined\n): MultiPageOptions {\n if (!userConfig) {\n return { ...DEFAULT_CONFIG };\n }\n\n // 处理 buildStrategies 别名\n const strategies =\n userConfig.strategies ?? userConfig.buildStrategies ?? DEFAULT_CONFIG.strategies;\n\n return {\n entry: userConfig.entry ?? DEFAULT_CONFIG.entry,\n exclude: userConfig.exclude ?? DEFAULT_CONFIG.exclude,\n template: userConfig.template ?? DEFAULT_CONFIG.template,\n placeholder: userConfig.placeholder ?? DEFAULT_CONFIG.placeholder,\n debug: userConfig.debug ?? DEFAULT_CONFIG.debug,\n strategies,\n pageConfigs: userConfig.pageConfigs ?? DEFAULT_CONFIG.pageConfigs,\n __forceBuildStrategy: userConfig.__forceBuildStrategy,\n };\n}\n\n/**\n * 检查配置是否为空或无效\n */\nexport function isEmptyConfig(config: MultiPageOptions): boolean {\n // 检查是否是完全空的对象\n if (Object.keys(config).length === 0) {\n return true;\n }\n\n // 检查是否只有默认值或无效值\n const hasValidEntry = config.entry && config.entry !== DEFAULT_CONFIG.entry;\n const hasValidStrategies =\n (config.strategies && Object.keys(config.strategies).length > 0) ||\n (config.buildStrategies && Object.keys(config.buildStrategies).length > 0);\n const hasValidPageConfigs =\n config.pageConfigs &&\n (typeof config.pageConfigs === 'function' || Object.keys(config.pageConfigs).length > 0);\n\n return !hasValidEntry && !hasValidStrategies && !hasValidPageConfigs;\n}\n","import type { UserConfig } from 'vite';\n\n// 核心配置选项\nexport interface MultiPageOptions {\n entry?: string;\n exclude?: string[];\n template?: string;\n placeholder?: string;\n debug?: boolean;\n strategies?: Record<string, ConfigStrategy>;\n buildStrategies?: Record<string, ConfigStrategy>; // 别名,等同于 strategies\n pageConfigs?: Record<string, PageConfig> | PageConfigFunction;\n __forceBuildStrategy?: string;\n}\n\n// 主要导出类型\nexport type Options = MultiPageOptions;\n\n// 开发服务器选项\nexport interface DevServerOptions {\n entry: string;\n exclude: string[];\n template: string;\n placeholder: string;\n strategies?: Record<string, ConfigStrategy>;\n pageConfigs?: Record<string, PageConfig> | PageConfigFunction;\n appliedStrategies?: Map<string, string>;\n devStrategy?: string; // 开发模式下指定的策略\n}\n\n// 构建配置选项\nexport interface BuildConfigOptions {\n entry: string;\n exclude: string[];\n template: string;\n placeholder: string;\n strategies?: Record<string, ConfigStrategy>;\n pageConfigs?: Record<string, PageConfig> | PageConfigFunction;\n forceBuildStrategy?: string;\n}\n\n// 策略配置\nexport type ConfigStrategy = Omit<UserConfig, 'plugins'>;\n\n// 页面配置\nexport interface PageConfig {\n strategy?: string;\n define?: Record<string, any>;\n template?: string;\n viteConfig?: UserConfig;\n match?: string;\n}\n\n// 页面上下文\nexport interface PageContext {\n pageName: string;\n filePath: string;\n relativePath: string;\n fullPath?: string;\n strategy?: string;\n isMatched?: boolean;\n}\n\n// 页面配置上下文(别名)\nexport type PageConfigContext = PageContext;\n\n// 页面配置函数\nexport type PageConfigFunction = (context: PageContext) => PageConfig | null;\n\n// 入口文件信息\nexport interface EntryFile {\n name: string;\n file: string;\n}\n\n// 候选文件信息\nexport interface CandidateFile extends EntryFile {\n priority: number;\n}\n\n// 构建策略配置\nexport interface BuildStrategyConfig {\n strategy: string;\n pages: string[];\n configPath?: string;\n}\n\n// CLI选项\nexport interface CLIOptions {\n configFile: string;\n outDir?: string;\n debug?: boolean;\n mode?: string;\n minify?: boolean | string;\n build?: Record<string, any>;\n base?: string;\n strategy?: string;\n port?: number | string;\n host?: string;\n https?: boolean;\n open?: boolean;\n}\n\n// 插件上下文\nexport interface PluginContext {\n mode: string;\n command: 'build' | 'serve';\n isCLI: boolean;\n}\n\n// 配置函数类型\nexport type ConfigFunction = (context: PluginContext) => MultiPageOptions;\n\n// 配置变换函数类型\nexport type ConfigTransformFunction = (\n config: MultiPageOptions,\n context: PluginContext\n) => MultiPageOptions;\n\n// 工具函数:定义配置\nexport function defineConfig(config: MultiPageOptions | ConfigFunction): ConfigFunction {\n // 如果传入的是函数,直接返回\n if (typeof config === 'function') {\n return config;\n }\n\n // 如果传入的是对象,包装成函数返回\n return () => config;\n}\n\n// 工具函数:定义配置变换\nexport function defineConfigTransform(transform: ConfigTransformFunction): ConfigTransformFunction {\n return transform;\n}\n"],"mappings":"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","names":["mergeConfig","path","fs","glob","path","filterEntryFiles","files","entry","exclude","_log","result","nameToFile","basePattern","candidateFiles","file","normalizedFile","normalizedBasePattern","pathParts","fileName","name","dirName","candidate","existing","escapeRegExp","string","createLogger","debug","args","getPageConfig","pageConfigs","context","log","key","config","pattern","simpleMatch","text","regexPattern","configureDevServer","server","options","log","allFiles","glob","entryFiles","filterEntryFiles","cliStrategy","file","pageContext","pageStrategy","getPageConfig","f","req","res","next","pathWithoutQuery","indexHtml","generateIndexHtml","pageName","cleanPath","segments","possiblePageName","matchedFile","servePageHtml","error","pageConfig","strategyName","templatePath","pageSpecificTemplate","html","originalHtml","escapedPlaceholder","escapeRegExp","placeholderRegex","defineScript","key","value","stringValue","setupDevMiddleware","pageItems","strategy","strategyBadge","mergeConfig","glob","path","fs","generateBuildConfig","options","entry","exclude","template","placeholder","strategies","pageConfigs","forceBuildStrategy","log","createLogger","buildConfigs","allFiles","glob","entryFiles","filterEntryFiles","pageStrategies","strategyPages","entryFile","pageContext","strategyName","getPageConfig","targetPages","config","generateStrategyConfig","pages","strategyConfig","allPageNames","f","defaultConfig","strategyNames","error","defaultTemplate","htmlInputs","tempFiles","allPageDefines","pageName","pageConfig","templatePath","pageSpecificTemplate","templateFullPath","templateContent","entryPath","tempHtmlPath","buildOptions","baseConfig","mergeConfig","getViteOutputDirectory","viteBuildArgs","outDirIndex","arg","outDir","outDirArg","cleanViteOutputDirectory","outputDir","getAvailableStrategies","options","entry","exclude","pageConfigs","log","createLogger","strategySet","allFiles","glob","entryFiles","filterEntryFiles","entryFile","pageContext","strategyName","getPageConfig","error","fs","path","pathToFileURL","createJiti","CONFIG_FILES","hasCustomConfig","filename","configPath","loadUserConfig","context","customConfig","loadCustomConfig","result","loadConfigFile","filePath","cwd","configFile","configModule","configFunction","error","DEFAULT_CONFIG","mergeWithDefaults","userConfig","strategies","fs","defineConfig","config","defineConfigTransform","transform","viteMultiPage","transform","resolvedOptions","tempFiles","log","config","userConfig","hasCustomConfig","loadUserConfig","mergedConfig","mergeWithDefaults","command","args","strategyArg","arg","strategy","strategyIndex","forceBuildStrategy","buildConfigs","generateBuildConfig","targetStrategy","strategyConfig","mergeConfig","server","devStrategy","setupDevMiddleware","file","error","index_default"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/dev-server.ts","../src/file-filter.ts","../src/utils.ts","../src/page-config.ts","../src/build-config.ts","../src/config-loader.ts","../src/defaults.ts","../src/types.ts"],"sourcesContent":["import type { Plugin } from 'vite';\nimport { mergeConfig } from 'vite';\nimport { setupDevMiddleware } from './dev-server';\nimport { generateBuildConfig } from './build-config';\nimport { loadUserConfig, hasCustomConfig } from './config-loader';\nimport { mergeWithDefaults } from './defaults';\nimport type { Options, ConfigTransformFunction } from './types';\nimport * as fs from 'fs';\n\n// 导出类型和工具函数\nexport { defineConfig, defineConfigTransform } from './types';\nexport type {\n ConfigFunction,\n ConfigTransformFunction,\n PluginContext,\n PageContext,\n PageConfig,\n} from './types';\n\nexport function viteMultiPage(transform?: ConfigTransformFunction): Plugin {\n let resolvedOptions: Options;\n const tempFiles: string[] = [];\n let log: (...args: any[]) => void = () => {}; // 默认为空函数\n\n return {\n name: 'vite-multi-page',\n\n async configResolved(config) {\n // 加载用户配置文件(如果存在)\n let userConfig: Options | null = null;\n\n if (hasCustomConfig()) {\n userConfig = await loadUserConfig({\n mode: config.command === 'serve' ? 'development' : 'production',\n command: config.command,\n isCLI: false,\n });\n }\n\n // 合并用户配置和默认配置\n const mergedConfig = mergeWithDefaults(userConfig);\n\n // 应用配置变换函数(如果提供)\n resolvedOptions = transform\n ? transform(mergedConfig, {\n mode: config.command === 'serve' ? 'development' : 'production',\n command: config.command,\n isCLI: false,\n })\n : mergedConfig;\n\n // 设置debug日志\n const debug = resolvedOptions.debug ?? false;\n log = debug ? console.log.bind(console, '[vite-multi-page]') : () => {};\n\n log('Vite配置已解析, 使用配置:', {\n strategies: Object.keys(resolvedOptions.strategies || {}),\n entry: resolvedOptions.entry,\n });\n },\n\n async config(config, { command }) {\n // 处理开发模式下的策略参数\n if (command === 'serve') {\n // 检查命令行参数中的策略设置\n const args = process.argv;\n\n // 查找 --strategy=value 格式的参数\n const strategyArg = args.find(arg => arg.startsWith('--strategy='));\n if (strategyArg) {\n const strategy = strategyArg.split('=')[1];\n if (strategy) {\n process.env.VITE_MULTI_PAGE_STRATEGY = strategy;\n }\n }\n // 查找 --strategy value 格式的参数\n else {\n const strategyIndex = args.findIndex(arg => arg === '--strategy');\n if (strategyIndex !== -1 && strategyIndex + 1 < args.length) {\n const strategy = args[strategyIndex + 1];\n process.env.VITE_MULTI_PAGE_STRATEGY = strategy;\n }\n }\n\n // 确保有默认策略\n if (!process.env.VITE_MULTI_PAGE_STRATEGY) {\n process.env.VITE_MULTI_PAGE_STRATEGY = 'default';\n }\n }\n if (command === 'build') {\n // 在config钩子中临时加载配置,因为configResolved还没运行\n if (!resolvedOptions) {\n // 加载用户配置文件(如果存在)\n let userConfig: Options | null = null;\n\n if (hasCustomConfig()) {\n userConfig = await loadUserConfig({\n mode: 'production',\n command: 'build',\n isCLI: false,\n });\n }\n\n // 合并用户配置和默认配置\n const mergedConfig = mergeWithDefaults(userConfig);\n\n // 应用配置变换函数(如果提供)\n resolvedOptions = transform\n ? transform(mergedConfig, {\n mode: 'production',\n command: 'build',\n isCLI: false,\n })\n : mergedConfig;\n const debug = resolvedOptions.debug ?? false;\n log = debug ? console.log.bind(console, '[vite-multi-page]') : () => {};\n }\n\n log('配置构建模式');\n\n // 策略构建模式:生成构建配置\n const forceBuildStrategy = process.env.VITE_MULTI_PAGE_STRATEGY;\n const buildConfigs = await generateBuildConfig({\n entry: resolvedOptions.entry || 'src/pages/**/*.{ts,js}',\n exclude: resolvedOptions.exclude || [],\n template: resolvedOptions.template || 'index.html',\n placeholder: resolvedOptions.placeholder || '{{ENTRY_FILE}}',\n strategies: resolvedOptions.strategies || {},\n pageConfigs: resolvedOptions.pageConfigs || {},\n forceBuildStrategy,\n });\n\n // 应用构建配置中的策略(如果有forceBuildStrategy,buildConfigs只会包含该策略)\n const targetStrategy = Object.keys(buildConfigs)[0];\n\n if (targetStrategy && buildConfigs[targetStrategy]) {\n log(`应用构建策略: ${targetStrategy}`);\n const strategyConfig = buildConfigs[targetStrategy];\n\n // 使用Vite的mergeConfig进行智能深度合并\n const mergedConfig = mergeConfig(config, strategyConfig);\n\n // 将合并结果复制回config对象\n Object.assign(config, mergedConfig);\n\n log(`已应用策略 \"${targetStrategy}\" 的配置:`, {\n build: !!strategyConfig.build,\n define: !!strategyConfig.define,\n plugins: strategyConfig.plugins?.length || 0,\n });\n } else {\n log('未找到可用的构建策略,使用默认配置');\n\n throw new Error(\n '❌ 构建失败: 未找到任何构建策略\\n\\n' +\n '可能的原因:\\n' +\n ' 1. 配置文件返回空对象 {}\\n' +\n ' 2. 未找到匹配的入口文件\\n' +\n ' 3. 模板文件不存在\\n' +\n ' 4. 未配置 strategies 对象\\n\\n' +\n '最小配置示例:\\n' +\n 'export default () => ({\\n' +\n ' entry: \"src/pages/**/*.{ts,js}\",\\n' +\n ' template: \"index.html\",\\n' +\n ' strategies: {\\n' +\n ' default: {}\\n' +\n ' }\\n' +\n '});'\n );\n }\n }\n },\n\n configureServer(server) {\n if (server.config.command === 'serve') {\n log('配置开发服务器');\n\n // 处理开发模式下的策略参数\n // 从环境变量中获取策略,默认为 default\n const devStrategy = process.env.VITE_MULTI_PAGE_STRATEGY || 'default';\n\n log(`开发模式策略: ${devStrategy}`);\n\n setupDevMiddleware(\n server,\n {\n entry: resolvedOptions.entry || 'src/pages/**/*.{ts,js}',\n exclude: resolvedOptions.exclude || [],\n template: resolvedOptions.template || 'index.html',\n placeholder: resolvedOptions.placeholder || '{{ENTRY_FILE}}',\n strategies: resolvedOptions.strategies || {},\n pageConfigs: resolvedOptions.pageConfigs || {},\n devStrategy: devStrategy, // 传递策略给开发服务器\n },\n log\n );\n }\n },\n\n writeBundle() {\n // 构建完成,无需额外处理\n // 每个策略已经直接输出到对应的目录\n },\n\n buildEnd() {\n // 清理临时文件\n if (tempFiles.length > 0) {\n log(`清理 ${tempFiles.length} 个临时文件`);\n tempFiles.forEach(file => {\n try {\n if (fs.existsSync(file)) {\n fs.unlinkSync(file);\n log(`删除临时文件: ${file}`);\n }\n } catch (error) {\n log(`删除临时文件失败: ${file}`, error);\n }\n });\n tempFiles.length = 0;\n }\n },\n };\n}\n\nexport default viteMultiPage;\nexport type { Options } from './types';\nexport {\n generateBuildConfig,\n getAvailableStrategies,\n getViteOutputDirectory,\n cleanViteOutputDirectory,\n} from './build-config';\nexport { mergeWithDefaults } from './defaults';\n","import type { ViteDevServer } from 'vite';\nimport * as path from 'node:path';\nimport * as fs from 'node:fs';\nimport { glob } from 'glob';\nimport { filterEntryFiles } from './file-filter';\nimport { escapeRegExp } from './utils';\nimport { DevServerOptions, PageConfigContext } from './types';\nimport { getPageConfig } from './page-config';\n\nexport function configureDevServer(\n server: ViteDevServer,\n options: DevServerOptions,\n log: (...args: any[]) => void\n) {\n try {\n const allFiles = glob.sync(options.entry, { cwd: process.cwd() });\n let entryFiles = filterEntryFiles(allFiles, options.entry, options.exclude, log);\n\n if (entryFiles.length === 0) {\n log('警告: 未找到匹配的入口文件');\n return;\n }\n\n // 获取指定的策略,优先使用开发模式传入的策略\n const cliStrategy =\n options.devStrategy ||\n (((server.config as any).__cliStrategy || (server.config as any).strategy) as\n | string\n | undefined);\n\n // 如果指定了策略,则只显示该策略下的页面或没有指定策略的默认页面\n if (cliStrategy) {\n log(`开发服务器使用指定的策略: ${cliStrategy}`);\n\n // 过滤入口文件,只保留匹配策略的页面\n entryFiles = entryFiles.filter(file => {\n // 动态获取页面策略\n const pageContext = {\n pageName: file.name,\n filePath: file.file,\n relativePath: path.relative(process.cwd(), file.file),\n strategy: undefined,\n isMatched: false,\n } as PageConfigContext;\n\n const pageConfig = getPageConfig(options.pageConfigs, pageContext, log);\n const pageStrategy = pageConfig?.strategy || 'default';\n\n // 在指定策略为default时,包含所有没有指定策略的页面\n if (cliStrategy === 'default') {\n return pageStrategy === 'default';\n }\n\n // 其他策略,只包含匹配的页面\n return pageStrategy === cliStrategy;\n });\n\n log(`策略 \"${cliStrategy}\" 下可用的页面: ${entryFiles.map(f => f.name).join(', ') || '无'}`);\n }\n\n log('开发服务器应用的入口文件:', entryFiles);\n\n // 修改中间件来处理HTML请求\n server.middlewares.use(async (req, res, next) => {\n try {\n const url = req.url || '';\n const pathWithoutQuery = url.split('?')[0];\n\n // 处理根路径请求 - 显示所有页面的索引\n if (pathWithoutQuery === '/') {\n const indexHtml = generateIndexHtml(entryFiles, options, log);\n res.statusCode = 200;\n res.setHeader('Content-Type', 'text/html');\n res.end(indexHtml);\n return;\n }\n\n // 跳过明显的静态资源请求\n if (\n pathWithoutQuery.match(/\\.(js|css|png|jpg|jpeg|gif|svg|ico|woff|woff2|ttf|eot|map)$/) &&\n !pathWithoutQuery.endsWith('.html')\n ) {\n return next();\n }\n\n // 跳过以@开头的特殊路径(如Vite的特殊路径)\n if (pathWithoutQuery.startsWith('/@')) {\n return next();\n }\n\n // 跳过 __vite_ping 和其他 Vite 内部路径\n if (pathWithoutQuery.includes('__vite') || pathWithoutQuery.startsWith('/node_modules')) {\n return next();\n }\n\n // 提取页面名称,支持 history 路由\n let pageName = '';\n\n // 1. 处理带 .html 后缀的请求\n if (pathWithoutQuery.endsWith('.html')) {\n pageName = path.basename(pathWithoutQuery, '.html');\n }\n // 2. 处理精确匹配的页面路径,如 /mobile\n else if (pathWithoutQuery.startsWith('/')) {\n const cleanPath = pathWithoutQuery.substring(1); // 移除开头的斜杠\n\n // 首先尝试精确匹配\n if (entryFiles.find(file => file.name === cleanPath)) {\n pageName = cleanPath;\n }\n // 然后尝试 history 路由匹配,如 /home/login -> home\n else {\n const segments = cleanPath.split('/');\n if (segments.length > 1) {\n const possiblePageName = segments[0];\n if (entryFiles.find(file => file.name === possiblePageName)) {\n pageName = possiblePageName;\n log(`History 路由匹配: ${pathWithoutQuery} -> ${possiblePageName}`);\n }\n }\n }\n }\n\n if (!pageName) {\n return next();\n }\n\n const matchedFile = entryFiles.find(file => file.name === pageName);\n\n if (!matchedFile) {\n return next();\n }\n\n return servePageHtml(res, matchedFile, options, log);\n } catch (error) {\n log(`开发服务器处理请求失败: ${error}`);\n next(error);\n }\n });\n\n log('开发服务器配置完成');\n } catch (error) {\n log(`配置开发服务器失败: ${error}`);\n throw error;\n }\n}\n\n// 提取页面HTML服务逻辑\nfunction servePageHtml(\n res: any,\n matchedFile: { name: string; file: string },\n options: DevServerOptions,\n log: (...args: any[]) => void\n) {\n // 获取页面配置\n const pageContext = {\n pageName: matchedFile.name,\n filePath: matchedFile.file,\n relativePath: path.relative(process.cwd(), matchedFile.file),\n strategy: undefined,\n isMatched: false,\n } as PageConfigContext;\n\n const pageConfig = getPageConfig(options.pageConfigs, pageContext, log);\n\n // 应用配置策略\n if (pageConfig?.strategy) {\n pageContext.strategy = pageConfig.strategy;\n } else if (options.appliedStrategies?.has(matchedFile.name)) {\n // 使用缓存的策略信息\n const strategyName = options.appliedStrategies.get(matchedFile.name);\n if (strategyName) {\n pageContext.strategy = strategyName;\n }\n }\n\n // 获取模板文件路径\n // 首先检查是否有页面特定的模板(例如mobile.html对应mobile页面)\n let templatePath = '';\n\n // 尝试以页面名称查找匹配的模板\n const pageSpecificTemplate = path.resolve(process.cwd(), `${matchedFile.name}.html`);\n if (fs.existsSync(pageSpecificTemplate)) {\n templatePath = pageSpecificTemplate;\n }\n // 然后尝试使用页面配置中指定的模板\n else if (pageConfig?.template) {\n templatePath = path.resolve(process.cwd(), pageConfig.template);\n }\n // 最后使用默认模板\n else {\n templatePath = path.resolve(process.cwd(), options.template);\n }\n\n if (!fs.existsSync(templatePath)) {\n res.statusCode = 404;\n res.end('Template not found');\n return;\n }\n\n // 读取并修改模板\n let html = fs.readFileSync(templatePath, 'utf-8');\n\n // 检查模板中是否包含占位符\n const containsPlaceholder = html.includes(options.placeholder);\n\n // 替换占位符为入口文件路径\n if (containsPlaceholder) {\n const originalHtml = html;\n\n // 方式1: 直接字符串替换\n html = html.split(options.placeholder).join(`/${matchedFile.file}`);\n\n // 检查替换结果\n if (html === originalHtml) {\n // 方式2: 正则表达式替换\n const escapedPlaceholder = escapeRegExp(options.placeholder);\n const placeholderRegex = new RegExp(escapedPlaceholder, 'g');\n html = originalHtml.replace(placeholderRegex, `/${matchedFile.file}`);\n\n // 检查替换结果\n if (html === originalHtml) {\n // 方式3: 硬编码替换具体的占位符格式\n html = originalHtml.replace(/\\{\\{ENTRY_FILE\\}\\}/g, `/${matchedFile.file}`);\n }\n }\n }\n\n // 添加页面级define变量\n if (pageConfig?.define) {\n const defineScript = Object.entries(pageConfig.define)\n .map(([key, value]) => {\n const stringValue = typeof value === 'string' ? `\"${value}\"` : JSON.stringify(value);\n return `window.${key} = ${stringValue};`;\n })\n .join('\\n');\n\n if (defineScript) {\n // 注入到head标签底部\n html = html.replace(\n /<\\/head>/i,\n `<script type=\"text/javascript\">\\n${defineScript}\\n</script>\\n</head>`\n );\n }\n }\n\n // 发送响应\n res.statusCode = 200;\n res.setHeader('Content-Type', 'text/html');\n res.end(html);\n}\n\n// 为了兼容性,导出setupDevMiddleware作为configureDevServer的别名\nexport const setupDevMiddleware = configureDevServer;\n\n// 生成索引页面HTML\nfunction generateIndexHtml(\n entryFiles: { name: string; file: string }[],\n options: DevServerOptions,\n log: (...args: any[]) => void\n): string {\n try {\n const pageItems = entryFiles\n .map(file => {\n // 获取页面配置和策略\n const pageContext = {\n pageName: file.name,\n filePath: file.file,\n relativePath: path.relative(process.cwd(), file.file),\n strategy: undefined,\n isMatched: false,\n };\n\n const pageConfig = getPageConfig(options.pageConfigs, pageContext, log);\n\n // 确定策略\n let strategy = 'default';\n if (pageConfig?.strategy) {\n strategy = pageConfig.strategy;\n } else if (options.appliedStrategies?.has(file.name)) {\n const strategyName = options.appliedStrategies.get(file.name);\n if (strategyName) {\n strategy = strategyName;\n }\n }\n\n const strategyBadge =\n strategy !== 'default' ? `<span class=\"badge\">${strategy}</span>` : '';\n\n return `\n <div class=\"page-item\">\n <a href=\"${file.name}.html\" class=\"page-link\">\n ${file.name}${strategyBadge}\n </a>\n <div class=\"page-path\">${file.file}</div>\n </div>`;\n })\n .join('');\n\n return `\n <!DOCTYPE html>\n <html lang=\"en\">\n <head>\n <meta charset=\"UTF-8\">\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n <title>多页面应用索引</title>\n <style>\n body {\n font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, Helvetica, Arial, sans-serif;\n line-height: 1.6;\n color: #333;\n max-width: 1200px;\n margin: 0 auto;\n padding: 20px;\n background-color: #f5f5f7;\n }\n h1 {\n font-size: 24px;\n margin-bottom: 20px;\n color: #111;\n }\n .page-list {\n display: grid;\n grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));\n gap: 16px;\n }\n .page-item {\n background-color: white;\n border-radius: 8px;\n padding: 16px;\n box-shadow: 0 1px 3px rgba(0,0,0,0.1);\n transition: transform 0.2s, box-shadow 0.2s;\n }\n .page-item:hover {\n transform: translateY(-2px);\n box-shadow: 0 4px 8px rgba(0,0,0,0.1);\n }\n .page-link {\n display: flex;\n align-items: center;\n justify-content: space-between;\n font-size: 18px;\n font-weight: 500;\n color: #0066cc;\n text-decoration: none;\n margin-bottom: 8px;\n }\n .page-path {\n font-size: 14px;\n color: #666;\n word-break: break-all;\n }\n .badge {\n display: inline-block;\n font-size: 12px;\n padding: 2px 8px;\n border-radius: 12px;\n background-color: #e6f2ff;\n color: #0066cc;\n margin-left: 8px;\n }\n .stats {\n margin-bottom: 20px;\n font-size: 14px;\n color: #666;\n }\n </style>\n </head>\n <body>\n <h1>多页面应用索引</h1>\n <div class=\"stats\">\n 找到 ${entryFiles.length} 个页面\n </div>\n <div class=\"page-list\">\n ${pageItems}\n </div>\n </body>\n </html>\n `;\n } catch (error) {\n log(`生成索引页失败: ${error}`);\n return `\n <!DOCTYPE html>\n <html>\n <head>\n <title>错误</title>\n </head>\n <body>\n <h1>生成索引页时发生错误</h1>\n <p>${error}</p>\n </body>\n </html>\n `;\n }\n}\n","import * as path from 'node:path';\nimport type { EntryFile, CandidateFile } from './types';\n\nexport function filterEntryFiles(\n files: string[],\n entry: string,\n exclude: string[],\n _log: (...args: any[]) => void\n): EntryFile[] {\n const result: EntryFile[] = [];\n const nameToFile = new Map<string, { file: string; priority: number }>();\n\n // 从entry模式中提取基础目录\n let basePattern = entry.replace(/\\/\\*.*$/, ''); // 去掉glob部分\n // 如果基础模式为空或不合理,使用默认处理\n if (!basePattern || basePattern === entry) {\n basePattern = path.dirname(entry.split('*')[0]);\n }\n const candidateFiles: CandidateFile[] = [];\n\n for (const file of files) {\n if (exclude.includes(file)) {\n continue;\n }\n\n // 统一使用正斜杠处理路径,确保Windows兼容性\n const normalizedFile = file.replace(/\\\\/g, '/');\n const normalizedBasePattern = basePattern.replace(/\\\\/g, '/');\n\n const relativePath = path.posix.relative(normalizedBasePattern, normalizedFile);\n const pathParts = relativePath.split('/'); // 使用正斜杠分割\n\n if (pathParts.length === 1) {\n // 第一级文件:src/pages/about.js -> /about.html\n const fileName = pathParts[0];\n const name = path.posix.basename(fileName, path.posix.extname(fileName));\n candidateFiles.push({ name, file, priority: 1 });\n } else if (pathParts.length >= 2) {\n // 目录下的文件\n const fileName = path.posix.basename(normalizedFile, path.posix.extname(normalizedFile));\n const dirName = pathParts[0];\n\n if (fileName === 'main') {\n // 目录下的main文件:src/pages/mobile/main.ts -> /mobile.html\n candidateFiles.push({ name: dirName, file, priority: 2 });\n }\n }\n }\n\n // 按照优先级处理冲突:目录优先覆盖文件(优先级2 > 优先级1)\n for (const candidate of candidateFiles) {\n const existing = nameToFile.get(candidate.name);\n\n if (!existing) {\n nameToFile.set(candidate.name, { file: candidate.file, priority: candidate.priority });\n } else {\n if (candidate.priority > existing.priority) {\n nameToFile.set(candidate.name, { file: candidate.file, priority: candidate.priority });\n }\n }\n }\n\n for (const [name, { file }] of nameToFile.entries()) {\n result.push({ name, file });\n }\n\n return result;\n}\n","export function escapeRegExp(string: string): string {\n return string.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n}\n\nexport function createLogger(debug: boolean) {\n return (...args: any[]) => {\n if (debug) {\n console.log('[vite-plugin-multi-page]', ...args);\n }\n };\n}\n","import type { PageConfig, PageConfigFunction, PageConfigContext } from './types';\n\n/**\n * 根据页面上下文获取页面配置\n */\nexport function getPageConfig(\n pageConfigs: Record<string, PageConfig> | PageConfigFunction | undefined,\n context: PageConfigContext,\n log: (...args: any[]) => void\n): PageConfig | null {\n if (!pageConfigs) return null;\n\n // 如果是函数,直接调用\n if (typeof pageConfigs === 'function') {\n const result = pageConfigs(context);\n return result;\n }\n\n // 对象配置:支持精确匹配和模式匹配\n for (const [key, config] of Object.entries(pageConfigs)) {\n // 精确匹配页面名称\n if (key === context.pageName) {\n log(`精确匹配页面 ${context.pageName}:`, config);\n return config;\n }\n\n // 模式匹配\n if (config.match) {\n const patterns = Array.isArray(config.match) ? config.match : [config.match];\n const isMatched = patterns.some(\n pattern =>\n simpleMatch(pattern, context.pageName) ||\n simpleMatch(pattern, context.relativePath) ||\n simpleMatch(pattern, context.filePath)\n );\n\n if (isMatched) {\n log(`模式匹配页面 ${context.pageName} (模式: ${config.match}):`, config);\n return { ...config, match: undefined };\n }\n }\n\n // glob 模式匹配页面名称\n if (simpleMatch(key, context.pageName)) {\n log(`Glob匹配页面 ${context.pageName} (模式: ${key}):`, config);\n return config;\n }\n }\n\n return null;\n}\n\n/**\n * 简单的模式匹配函数\n */\nfunction simpleMatch(pattern: string, text: string): boolean {\n const regexPattern = pattern\n .replace(/\\*\\*/g, '__DOUBLE_STAR__')\n .replace(/\\*/g, '[^/]*')\n .replace(/__DOUBLE_STAR__/g, '.*');\n const regex = new RegExp(`^${regexPattern}$`);\n return regex.test(text);\n}\n","import type { UserConfig } from 'vite';\nimport { mergeConfig } from 'vite';\nimport { glob } from 'glob';\nimport * as path from 'node:path';\nimport * as fs from 'node:fs';\nimport { filterEntryFiles } from './file-filter';\nimport { getPageConfig } from './page-config';\nimport type { BuildConfigOptions, PageConfigContext, ConfigStrategy } from './types';\nimport { createLogger } from './utils';\n\n/**\n * 构建时配置生成器\n * 根据策略和页面配置生成多页面构建配置\n */\nexport async function generateBuildConfig(\n options: BuildConfigOptions\n): Promise<Record<string, UserConfig>> {\n const {\n entry = 'src/pages/*/main.{ts,js}',\n exclude = [],\n template = 'index.html',\n placeholder = '<!--VITE_MULTI_PAGE_ENTRY-->',\n strategies = {},\n pageConfigs = {},\n forceBuildStrategy,\n } = options;\n\n const log = createLogger(true);\n const buildConfigs: Record<string, UserConfig> = {};\n\n try {\n // 1. 发现所有页面入口文件\n const allFiles = glob.sync(entry, { cwd: process.cwd() });\n const entryFiles = filterEntryFiles(allFiles, entry, exclude, log);\n\n if (entryFiles.length === 0) {\n log('警告: 未找到匹配的入口文件');\n return {};\n }\n\n // 2. 为每个页面分析配置和策略\n const pageStrategies = new Map<string, string>();\n const strategyPages = new Map<string, string[]>();\n\n for (const entryFile of entryFiles) {\n const pageContext = {\n pageName: entryFile.name,\n filePath: entryFile.file,\n relativePath: path.relative(process.cwd(), entryFile.file),\n } as PageConfigContext;\n\n // 获取页面配置\n const pageConfig = getPageConfig(pageConfigs, pageContext, log);\n const strategyName = pageConfig?.strategy || 'default';\n\n pageStrategies.set(entryFile.name, strategyName);\n\n if (!strategyPages.has(strategyName)) {\n strategyPages.set(strategyName, []);\n }\n strategyPages.get(strategyName)?.push(entryFile.name);\n }\n\n log(`📄 发现 ${entryFiles.length} 个页面: ${entryFiles.map(f => f.name).join(', ')}`);\n\n // 3. 如果指定了强制策略,只构建该策略的页面\n if (forceBuildStrategy) {\n const targetPages = strategyPages.get(forceBuildStrategy) || [];\n if (targetPages.length === 0) {\n log(`警告: 策略 \"${forceBuildStrategy}\" 下没有页面`);\n return {};\n }\n\n log(`强制构建策略: ${forceBuildStrategy}, 页面: ${targetPages.join(', ')}`);\n\n const config = await generateStrategyConfig(\n forceBuildStrategy,\n targetPages,\n entryFiles,\n strategies[forceBuildStrategy],\n pageConfigs,\n template,\n placeholder,\n log\n );\n\n buildConfigs[forceBuildStrategy] = config;\n return buildConfigs;\n }\n\n // 4. 为每个策略生成构建配置\n for (const [strategyName, pages] of strategyPages) {\n if (pages.length === 0) continue;\n\n // 获取策略配置,如果没有定义则使用空配置(允许默认策略)\n const strategyConfig = strategies[strategyName] || {};\n const config = await generateStrategyConfig(\n strategyName,\n pages,\n entryFiles,\n strategyConfig,\n pageConfigs,\n template,\n placeholder,\n log\n );\n\n buildConfigs[strategyName] = config;\n }\n\n // 确保至少有一个构建配置\n if (Object.keys(buildConfigs).length === 0) {\n log('警告: 未生成任何构建配置,创建默认配置');\n\n // 如果没有任何策略,创建一个默认策略包含所有页面\n const allPageNames = entryFiles.map(f => f.name);\n const defaultConfig = await generateStrategyConfig(\n 'default',\n allPageNames,\n entryFiles,\n {},\n pageConfigs,\n template,\n placeholder,\n log\n );\n\n buildConfigs['default'] = defaultConfig;\n }\n\n const strategyNames = Object.keys(buildConfigs);\n log(`📦 构建策略: ${strategyNames.join(', ')}`);\n return buildConfigs;\n } catch (error) {\n log('生成构建配置失败:', error);\n throw error;\n }\n}\n\n/**\n * 为特定策略生成构建配置\n */\nasync function generateStrategyConfig(\n strategyName: string,\n pages: string[],\n entryFiles: Array<{ name: string; file: string }>,\n strategyConfig: ConfigStrategy | undefined,\n pageConfigs: any,\n defaultTemplate: string,\n placeholder: string,\n log: (...args: any[]) => void\n): Promise<UserConfig> {\n const htmlInputs: Record<string, string> = {};\n const tempFiles: string[] = [];\n\n // 收集所有页面的 define 变量\n const allPageDefines: Record<string, any> = {};\n\n // 为每个页面确定使用的HTML模板并创建临时文件\n for (const pageName of pages) {\n const entryFile = entryFiles.find(f => f.name === pageName);\n if (!entryFile) continue;\n\n // 获取页面配置\n const pageContext = {\n pageName,\n filePath: entryFile.file,\n relativePath: path.relative(process.cwd(), entryFile.file),\n strategy: strategyName,\n } as PageConfigContext;\n\n const pageConfig = getPageConfig(pageConfigs, pageContext, log);\n\n // 收集页面级 define 变量\n if (pageConfig?.define) {\n Object.assign(allPageDefines, pageConfig.define);\n }\n\n // 确定HTML模板\n let templatePath = defaultTemplate;\n\n // 1. 页面特定模板(如 mobile.html 对应 mobile 页面)\n const pageSpecificTemplate = `${pageName}.html`;\n if (fs.existsSync(path.resolve(process.cwd(), pageSpecificTemplate))) {\n templatePath = pageSpecificTemplate;\n }\n // 2. 页面配置中指定的模板\n else if (pageConfig?.template) {\n templatePath = pageConfig.template;\n }\n\n // 读取模板内容\n const templateFullPath = path.resolve(process.cwd(), templatePath);\n if (!fs.existsSync(templateFullPath)) {\n log(`警告: 模板文件不存在: ${templatePath}`);\n continue;\n }\n\n let templateContent = fs.readFileSync(templateFullPath, 'utf-8');\n\n // 替换占位符\n if (templateContent.includes(placeholder)) {\n // 临时HTML在项目根目录中,使用相对路径\n const entryPath = `./${entryFile.file}`;\n templateContent = templateContent.replace(\n new RegExp(placeholder.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&'), 'g'),\n entryPath\n );\n }\n\n // 创建临时HTML文件,使用新的命名规则:.temp.mp.[name].html\n const tempHtmlPath = path.resolve(process.cwd(), `.temp.mp.${pageName}.html`);\n fs.writeFileSync(tempHtmlPath, templateContent);\n tempFiles.push(tempHtmlPath);\n\n htmlInputs[pageName] = tempHtmlPath;\n }\n\n const buildOptions: Record<string, any> = {\n input: htmlInputs,\n output: {\n entryFileNames: 'assets/[name]-[hash].js',\n chunkFileNames: 'assets/[name]-[hash].js',\n assetFileNames: 'assets/[name]-[hash][extname]',\n },\n };\n\n const baseConfig: UserConfig = {\n base: './',\n build: {\n outDir: `dist/${strategyName}`,\n rollupOptions: buildOptions,\n rolldownOptions: buildOptions,\n emptyOutDir: false,\n },\n define: {},\n };\n\n let config: UserConfig = baseConfig;\n\n if (strategyConfig) {\n config = mergeConfig(baseConfig, strategyConfig);\n }\n\n if (Object.keys(allPageDefines).length > 0) {\n config.define = {\n ...config.define,\n ...allPageDefines,\n };\n }\n\n if (!config.build) config.build = {};\n if (!config.build.rollupOptions) config.build.rollupOptions = {};\n if (!(config.build as any).rolldownOptions) (config.build as any).rolldownOptions = {};\n\n config.build.rollupOptions.input = htmlInputs;\n (config.build as any).rolldownOptions.input = htmlInputs;\n config.build.emptyOutDir = false;\n\n // 简化日志输出\n log(`策略 \"${strategyName}\" - ${pages.length} 个页面`);\n\n return config;\n}\n\n/**\n * 获取Vite配置的输出目录\n * 需要传入已解析的Vite配置或命令行参数\n */\nexport function getViteOutputDirectory(viteBuildArgs: string[] = []): string {\n // 1. 首先检查命令行参数中的 --outDir\n const outDirIndex = viteBuildArgs.findIndex(arg => arg === '--outDir');\n if (outDirIndex !== -1 && outDirIndex + 1 < viteBuildArgs.length) {\n const outDir = viteBuildArgs[outDirIndex + 1];\n return path.resolve(process.cwd(), outDir);\n }\n\n // 2. 检查 --outDir=value 格式\n const outDirArg = viteBuildArgs.find(arg => arg.startsWith('--outDir='));\n if (outDirArg) {\n const outDir = outDirArg.split('=')[1];\n return path.resolve(process.cwd(), outDir);\n }\n\n // 3. 如果没有命令行参数,使用 Vite 默认值\n // 注意:如果用户在 vite.config.ts 中配置了 build.outDir,\n // Vite 会自动使用该配置,我们这里只处理命令行参数的情况\n return path.resolve(process.cwd(), 'dist');\n}\n\n/**\n * 清理Vite配置的输出目录\n */\nexport function cleanViteOutputDirectory(viteBuildArgs: string[] = []): void {\n const outputDir = getViteOutputDirectory(viteBuildArgs);\n const log = createLogger(true);\n\n try {\n if (fs.existsSync(outputDir)) {\n fs.rmSync(outputDir, { recursive: true, force: true });\n log(`🧹 清理输出目录: ${path.relative(process.cwd(), outputDir)}`);\n }\n } catch (error) {\n log(`⚠️ 清理输出目录失败: ${outputDir}`, error);\n }\n}\n\n/**\n * 获取所有可用的构建策略\n */\nexport function discoverPages(options: BuildConfigOptions): Array<{ name: string; file: string }> {\n const { entry = 'src/pages/*/main.{ts,js}', exclude = [] } = options;\n\n const log = createLogger(true);\n\n try {\n // 发现所有页面入口文件\n const allFiles = glob.sync(entry, { cwd: process.cwd() });\n const entryFiles = filterEntryFiles(allFiles, entry, exclude, log);\n\n return entryFiles;\n } catch (error) {\n log('发现页面失败:', error);\n throw error;\n }\n}\n\nexport function getAvailableStrategies(options: BuildConfigOptions): string[] {\n const { entry = 'src/pages/*/main.{ts,js}', exclude = [], pageConfigs = {} } = options;\n\n const log = createLogger(false); // 静默模式\n const strategySet = new Set<string>();\n\n // 发现所有页面入口文件\n const allFiles = glob.sync(entry, { cwd: process.cwd() });\n const entryFiles = filterEntryFiles(allFiles, entry, exclude, log);\n\n if (entryFiles.length === 0) {\n throw new Error(`未找到匹配的入口文件: ${entry}`);\n }\n\n try {\n // 分析每个页面的策略\n for (const entryFile of entryFiles) {\n const pageContext = {\n pageName: entryFile.name,\n filePath: entryFile.file,\n relativePath: path.relative(process.cwd(), entryFile.file),\n } as PageConfigContext;\n\n const pageConfig = getPageConfig(pageConfigs, pageContext, log);\n const strategyName = pageConfig?.strategy || 'default';\n strategySet.add(strategyName);\n }\n\n // 只返回实际有页面的策略,不添加空策略\n return Array.from(strategySet).sort();\n } catch (error) {\n log('获取可用策略失败:', error);\n return ['default'];\n }\n}\n","import * as fs from 'node:fs';\nimport * as path from 'node:path';\nimport { pathToFileURL } from 'node:url';\nimport { createJiti } from 'jiti';\nimport type { Options } from './types';\n\nexport interface ConfigContext {\n mode: 'development' | 'production';\n command: 'serve' | 'build';\n isCLI?: boolean;\n}\n\nexport type ConfigFunction = (context: ConfigContext) => Options;\n\nconst CONFIG_FILES = [\n 'multipage.config.ts',\n 'multipage.config.js',\n 'multipage.config.mjs',\n] as const;\n\nexport function hasCustomConfig(): boolean {\n for (const filename of CONFIG_FILES) {\n const configPath = path.resolve(process.cwd(), filename);\n if (fs.existsSync(configPath)) {\n return true;\n }\n }\n return false;\n}\n\nexport async function loadUserConfig(context: ConfigContext): Promise<Options | null> {\n const customConfig = await loadCustomConfig();\n\n if (customConfig) {\n const result = customConfig(context);\n\n if (!result) {\n return {};\n }\n\n return result;\n }\n\n return null;\n}\n\nasync function loadConfigFile(filePath: string): Promise<any> {\n if (filePath.endsWith('.ts')) {\n const jiti = createJiti(import.meta.url, { interopDefault: true });\n return jiti.import(filePath);\n }\n\n if (filePath.endsWith('.js') || filePath.endsWith('.mjs')) {\n const fileUrl = pathToFileURL(filePath).href;\n return import(`${fileUrl}?t=${Date.now()}`);\n }\n\n throw new Error(`不支持的配置文件类型: ${filePath}`);\n}\n\nasync function loadCustomConfig(): Promise<ConfigFunction | null> {\n const cwd = process.cwd();\n\n for (const configFile of CONFIG_FILES) {\n const configPath = path.resolve(cwd, configFile);\n\n if (fs.existsSync(configPath)) {\n try {\n const configModule = await loadConfigFile(configPath);\n const configFunction = configModule.default || configModule;\n\n if (typeof configFunction === 'function') {\n return configFunction;\n } else {\n console.warn(`配置文件 ${configFile} 必须默认导出一个函数`);\n }\n } catch (error) {\n console.error(`加载配置文件 ${configFile} 失败:`, error);\n }\n }\n }\n\n return null;\n}\n","import type { MultiPageOptions } from './types';\n\n/**\n * 默认配置选项\n */\nexport const DEFAULT_CONFIG: Required<\n Omit<MultiPageOptions, '__forceBuildStrategy' | 'buildStrategies'>\n> = {\n entry: 'src/pages/**/*.{ts,js}',\n exclude: [],\n template: 'index.html',\n placeholder: '{{ENTRY_FILE}}',\n debug: false,\n strategies: {\n default: {},\n },\n pageConfigs: {},\n};\n\n/**\n * 合并用户配置和默认配置\n */\nexport function mergeWithDefaults(\n userConfig: MultiPageOptions | null | undefined\n): MultiPageOptions {\n if (!userConfig) {\n return { ...DEFAULT_CONFIG };\n }\n\n // 处理 buildStrategies 别名\n const strategies =\n userConfig.strategies ?? userConfig.buildStrategies ?? DEFAULT_CONFIG.strategies;\n\n return {\n entry: userConfig.entry ?? DEFAULT_CONFIG.entry,\n exclude: userConfig.exclude ?? DEFAULT_CONFIG.exclude,\n template: userConfig.template ?? DEFAULT_CONFIG.template,\n placeholder: userConfig.placeholder ?? DEFAULT_CONFIG.placeholder,\n debug: userConfig.debug ?? DEFAULT_CONFIG.debug,\n strategies,\n pageConfigs: userConfig.pageConfigs ?? DEFAULT_CONFIG.pageConfigs,\n __forceBuildStrategy: userConfig.__forceBuildStrategy,\n };\n}\n\n/**\n * 检查配置是否为空或无效\n */\nexport function isEmptyConfig(config: MultiPageOptions): boolean {\n // 检查是否是完全空的对象\n if (Object.keys(config).length === 0) {\n return true;\n }\n\n // 检查是否只有默认值或无效值\n const hasValidEntry = config.entry && config.entry !== DEFAULT_CONFIG.entry;\n const hasValidStrategies =\n (config.strategies && Object.keys(config.strategies).length > 0) ||\n (config.buildStrategies && Object.keys(config.buildStrategies).length > 0);\n const hasValidPageConfigs =\n config.pageConfigs &&\n (typeof config.pageConfigs === 'function' || Object.keys(config.pageConfigs).length > 0);\n\n return !hasValidEntry && !hasValidStrategies && !hasValidPageConfigs;\n}\n","import type { UserConfig } from 'vite';\n\n// 核心配置选项\nexport interface MultiPageOptions {\n entry?: string;\n exclude?: string[];\n template?: string;\n placeholder?: string;\n debug?: boolean;\n strategies?: Record<string, ConfigStrategy>;\n buildStrategies?: Record<string, ConfigStrategy>; // 别名,等同于 strategies\n pageConfigs?: Record<string, PageConfig> | PageConfigFunction;\n __forceBuildStrategy?: string;\n}\n\n// 主要导出类型\nexport type Options = MultiPageOptions;\n\n// 开发服务器选项\nexport interface DevServerOptions {\n entry: string;\n exclude: string[];\n template: string;\n placeholder: string;\n strategies?: Record<string, ConfigStrategy>;\n pageConfigs?: Record<string, PageConfig> | PageConfigFunction;\n appliedStrategies?: Map<string, string>;\n devStrategy?: string; // 开发模式下指定的策略\n}\n\n// 构建配置选项\nexport interface BuildConfigOptions {\n entry: string;\n exclude: string[];\n template: string;\n placeholder: string;\n strategies?: Record<string, ConfigStrategy>;\n pageConfigs?: Record<string, PageConfig> | PageConfigFunction;\n forceBuildStrategy?: string;\n}\n\n// 策略配置\nexport type ConfigStrategy = Omit<UserConfig, 'plugins'>;\n\n// 页面配置\nexport interface PageConfig {\n strategy?: string;\n define?: Record<string, any>;\n template?: string;\n viteConfig?: UserConfig;\n match?: string;\n}\n\n// 页面上下文\nexport interface PageContext {\n pageName: string;\n filePath: string;\n relativePath: string;\n fullPath?: string;\n strategy?: string;\n isMatched?: boolean;\n}\n\n// 页面配置上下文(别名)\nexport type PageConfigContext = PageContext;\n\n// 页面配置函数\nexport type PageConfigFunction = (context: PageContext) => PageConfig | null;\n\n// 入口文件信息\nexport interface EntryFile {\n name: string;\n file: string;\n}\n\n// 候选文件信息\nexport interface CandidateFile extends EntryFile {\n priority: number;\n}\n\n// 构建策略配置\nexport interface BuildStrategyConfig {\n strategy: string;\n pages: string[];\n configPath?: string;\n}\n\n// CLI选项\nexport interface CLIOptions {\n configFile: string;\n outDir?: string;\n debug?: boolean;\n mode?: string;\n minify?: boolean | string;\n build?: Record<string, any>;\n base?: string;\n strategy?: string;\n port?: number | string;\n host?: string;\n https?: boolean;\n open?: boolean;\n}\n\n// 插件上下文\nexport interface PluginContext {\n mode: string;\n command: 'build' | 'serve';\n isCLI: boolean;\n}\n\n// 配置函数类型\nexport type ConfigFunction = (context: PluginContext) => MultiPageOptions;\n\n// 配置变换函数类型\nexport type ConfigTransformFunction = (\n config: MultiPageOptions,\n context: PluginContext\n) => MultiPageOptions;\n\n// 工具函数:定义配置\nexport function defineConfig(config: MultiPageOptions | ConfigFunction): ConfigFunction {\n // 如果传入的是函数,直接返回\n if (typeof config === 'function') {\n return config;\n }\n\n // 如果传入的是对象,包装成函数返回\n return () => config;\n}\n\n// 工具函数:定义配置变换\nexport function defineConfigTransform(transform: ConfigTransformFunction): ConfigTransformFunction {\n return transform;\n}\n"],"mappings":"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","names":["mergeConfig","path","fs","glob","path","filterEntryFiles","files","entry","exclude","_log","result","nameToFile","basePattern","candidateFiles","file","normalizedFile","normalizedBasePattern","pathParts","fileName","name","dirName","candidate","existing","escapeRegExp","string","createLogger","debug","args","getPageConfig","pageConfigs","context","log","key","config","pattern","simpleMatch","text","regexPattern","configureDevServer","server","options","log","allFiles","glob","entryFiles","filterEntryFiles","cliStrategy","file","pageContext","pageStrategy","getPageConfig","f","req","res","next","pathWithoutQuery","indexHtml","generateIndexHtml","pageName","cleanPath","segments","possiblePageName","matchedFile","servePageHtml","error","pageConfig","strategyName","templatePath","pageSpecificTemplate","html","originalHtml","escapedPlaceholder","escapeRegExp","placeholderRegex","defineScript","key","value","stringValue","setupDevMiddleware","pageItems","strategy","strategyBadge","mergeConfig","glob","path","fs","generateBuildConfig","options","entry","exclude","template","placeholder","strategies","pageConfigs","forceBuildStrategy","log","createLogger","buildConfigs","allFiles","glob","entryFiles","filterEntryFiles","pageStrategies","strategyPages","entryFile","pageContext","strategyName","getPageConfig","targetPages","config","generateStrategyConfig","pages","strategyConfig","allPageNames","f","defaultConfig","strategyNames","error","defaultTemplate","htmlInputs","tempFiles","allPageDefines","pageName","pageConfig","templatePath","pageSpecificTemplate","templateFullPath","templateContent","entryPath","tempHtmlPath","buildOptions","baseConfig","mergeConfig","getViteOutputDirectory","viteBuildArgs","outDirIndex","arg","outDir","outDirArg","cleanViteOutputDirectory","outputDir","getAvailableStrategies","options","entry","exclude","pageConfigs","log","createLogger","strategySet","allFiles","glob","entryFiles","filterEntryFiles","entryFile","pageContext","strategyName","getPageConfig","error","fs","path","pathToFileURL","createJiti","CONFIG_FILES","hasCustomConfig","filename","configPath","loadUserConfig","context","customConfig","loadCustomConfig","result","loadConfigFile","filePath","cwd","configFile","configModule","configFunction","error","DEFAULT_CONFIG","mergeWithDefaults","userConfig","strategies","fs","defineConfig","config","defineConfigTransform","transform","viteMultiPage","transform","resolvedOptions","tempFiles","log","config","userConfig","hasCustomConfig","loadUserConfig","mergedConfig","mergeWithDefaults","command","args","strategyArg","arg","strategy","strategyIndex","forceBuildStrategy","buildConfigs","generateBuildConfig","targetStrategy","strategyConfig","mergeConfig","server","devStrategy","setupDevMiddleware","file","error","index_default"]}
|
package/package.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fchc8/vite-plugin-multi-page",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.2.3",
|
|
4
4
|
"description": "A powerful Vite plugin for building multi-page applications with smart file routing and multi-strategy builds",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"module": "dist/index.mjs",
|
|
7
7
|
"types": "dist/index.d.ts",
|
|
8
8
|
"bin": {
|
|
9
|
-
"vite-mp": "dist/cli.
|
|
9
|
+
"vite-mp": "dist/cli.mjs"
|
|
10
10
|
},
|
|
11
11
|
"files": [
|
|
12
12
|
"dist",
|
package/dist/cli.js
DELETED
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
"use strict";var ce=Object.create;var R=Object.defineProperty;var le=Object.getOwnPropertyDescriptor;var fe=Object.getOwnPropertyNames;var pe=Object.getPrototypeOf,ge=Object.prototype.hasOwnProperty;var D=(e,s)=>()=>(e&&(s=e(e=0)),s);var T=(e,s)=>{for(var n in s)R(e,n,{get:s[n],enumerable:!0})},z=(e,s,n,o)=>{if(s&&typeof s=="object"||typeof s=="function")for(let r of fe(s))!ge.call(e,r)&&r!==n&&R(e,r,{get:()=>s[r],enumerable:!(o=le(s,r))||o.enumerable});return e};var P=(e,s,n)=>(n=e!=null?ce(pe(e)):{},z(s||!e||!e.__esModule?R(n,"default",{value:e,enumerable:!0}):n,e)),ue=e=>z(R({},"__esModule",{value:!0}),e);var me,F,x=D(()=>{"use strict";me=()=>typeof document>"u"?new URL(`file:${__filename}`).href:document.currentScript&&document.currentScript.tagName.toUpperCase()==="SCRIPT"?document.currentScript.src:new URL("main.js",document.baseURI).href,F=me()});function A(e,s,n,o){let r=[],u=new Map,y=s.replace(/\/\*.*$/,"");(!y||y===s)&&(y=O.dirname(s.split("*")[0]));let c=[];for(let t of e){if(n.includes(t))continue;let i=t.replace(/\\/g,"/"),g=y.replace(/\\/g,"/"),m=O.posix.relative(g,i).split("/");if(m.length===1){let p=m[0],f=O.posix.basename(p,O.posix.extname(p));c.push({name:f,file:t,priority:1})}else if(m.length>=2){let p=O.posix.basename(i,O.posix.extname(i)),f=m[0];p==="main"&&c.push({name:f,file:t,priority:2})}}for(let t of c){let i=u.get(t.name);i?t.priority>i.priority&&u.set(t.name,{file:t.file,priority:t.priority}):u.set(t.name,{file:t.file,priority:t.priority})}for(let[t,{file:i}]of u.entries())r.push({name:t,file:i});return r}var O,J=D(()=>{"use strict";x();O=P(require("path"))});function M(e,s,n){if(!e)return null;if(typeof e=="function")return e(s);for(let[o,r]of Object.entries(e)){if(o===s.pageName)return n(`\u7CBE\u786E\u5339\u914D\u9875\u9762 ${s.pageName}:`,r),r;if(r.match&&(Array.isArray(r.match)?r.match:[r.match]).some(c=>U(c,s.pageName)||U(c,s.relativePath)||U(c,s.filePath)))return n(`\u6A21\u5F0F\u5339\u914D\u9875\u9762 ${s.pageName} (\u6A21\u5F0F: ${r.match}):`,r),{...r,match:void 0};if(U(o,s.pageName))return n(`Glob\u5339\u914D\u9875\u9762 ${s.pageName} (\u6A21\u5F0F: ${o}):`,r),r}return null}function U(e,s){let n=e.replace(/\*\*/g,"__DOUBLE_STAR__").replace(/\*/g,"[^/]*").replace(/__DOUBLE_STAR__/g,".*");return new RegExp(`^${n}$`).test(s)}var K=D(()=>{"use strict";x()});function E(e){return(...s)=>{e&&console.log("[vite-plugin-multi-page]",...s)}}var Q=D(()=>{"use strict";x()});var H={};T(H,{cleanViteOutputDirectory:()=>he,discoverPages:()=>ye,generateBuildConfig:()=>de,getAvailableStrategies:()=>be,getViteOutputDirectory:()=>L});function de(e){let{entry:s="src/pages/*/main.{ts,js}",exclude:n=[],template:o="index.html",placeholder:r="<!--VITE_MULTI_PAGE_ENTRY-->",strategies:u={},pageConfigs:y={},forceBuildStrategy:c}=e,t=E(!0),i={};try{let g=I.glob.sync(s,{cwd:process.cwd()}),l=A(g,s,n,t);if(l.length===0)return t("\u8B66\u544A: \u672A\u627E\u5230\u5339\u914D\u7684\u5165\u53E3\u6587\u4EF6"),{};let m=new Map,p=new Map;for(let d of l){let b={pageName:d.name,filePath:d.file,relativePath:S.relative(process.cwd(),d.file)},w=M(y,b,t)?.strategy||"default";m.set(d.name,w),p.has(w)||p.set(w,[]),p.get(w)?.push(d.name)}if(t(`\u{1F4C4} \u53D1\u73B0 ${l.length} \u4E2A\u9875\u9762: ${l.map(d=>d.name).join(", ")}`),c){let d=p.get(c)||[];if(d.length===0)return t(`\u8B66\u544A: \u7B56\u7565 "${c}" \u4E0B\u6CA1\u6709\u9875\u9762`),{};t(`\u5F3A\u5236\u6784\u5EFA\u7B56\u7565: ${c}, \u9875\u9762: ${d.join(", ")}`);let b=G(c,d,l,u[c],y,o,r,t);return i[c]=b,i}for(let[d,b]of p){if(b.length===0)continue;let $=u[d]||{},w=G(d,b,l,$,y,o,r,t);i[d]=w}if(Object.keys(i).length===0){t("\u8B66\u544A: \u672A\u751F\u6210\u4EFB\u4F55\u6784\u5EFA\u914D\u7F6E\uFF0C\u521B\u5EFA\u9ED8\u8BA4\u914D\u7F6E");let d=l.map($=>$.name),b=G("default",d,l,{},y,o,r,t);i.default=b}let f=Object.keys(i);return t(`\u{1F4E6} \u6784\u5EFA\u7B56\u7565: ${f.join(", ")}`),i}catch(g){throw t("\u751F\u6210\u6784\u5EFA\u914D\u7F6E\u5931\u8D25:",g),g}}function G(e,s,n,o,r,u,y,c){let t={},i=[],g={};for(let f of s){let d=n.find(V=>V.name===f);if(!d)continue;let b={pageName:f,filePath:d.file,relativePath:S.relative(process.cwd(),d.file),strategy:e},$=M(r,b,c);$?.define&&Object.assign(g,$.define);let w=u,j=`${f}.html`;v.existsSync(S.resolve(process.cwd(),j))?w=j:$?.template&&(w=$.template);let N=S.resolve(process.cwd(),w);if(!v.existsSync(N)){c(`\u8B66\u544A: \u6A21\u677F\u6587\u4EF6\u4E0D\u5B58\u5728: ${w}`);continue}let _=v.readFileSync(N,"utf-8");if(_.includes(y)){let V=`./${d.file}`;_=_.replace(new RegExp(y.replace(/[.*+?^${}()|[\]\\]/g,"\\$&"),"g"),V)}let W=S.resolve(process.cwd(),`.temp.mp.${f}.html`);v.writeFileSync(W,_),i.push(W),t[f]=W}let l={input:t,output:{entryFileNames:"assets/[name]-[hash].js",chunkFileNames:"assets/[name]-[hash].js",assetFileNames:"assets/[name]-[hash][extname]"}},m={base:"./",build:{outDir:`dist/${e}`,rollupOptions:l,rolldownOptions:l,emptyOutDir:!1},define:{}},p=m;return o&&(p=(0,X.mergeConfig)(m,o)),Object.keys(g).length>0&&(p.define={...p.define,...g}),p.build||(p.build={}),p.build.rollupOptions||(p.build.rollupOptions={}),p.build.rolldownOptions||(p.build.rolldownOptions={}),p.build.rollupOptions.input=t,p.build.rolldownOptions.input=t,p.build.emptyOutDir=!1,c(`\u7B56\u7565 "${e}" - ${s.length} \u4E2A\u9875\u9762`),p}function L(e=[]){let s=e.findIndex(o=>o==="--outDir");if(s!==-1&&s+1<e.length){let o=e[s+1];return S.resolve(process.cwd(),o)}let n=e.find(o=>o.startsWith("--outDir="));if(n){let o=n.split("=")[1];return S.resolve(process.cwd(),o)}return S.resolve(process.cwd(),"dist")}function he(e=[]){let s=L(e),n=E(!0);try{v.existsSync(s)&&(v.rmSync(s,{recursive:!0,force:!0}),n(`\u{1F9F9} \u6E05\u7406\u8F93\u51FA\u76EE\u5F55: ${S.relative(process.cwd(),s)}`))}catch(o){n(`\u26A0\uFE0F \u6E05\u7406\u8F93\u51FA\u76EE\u5F55\u5931\u8D25: ${s}`,o)}}function ye(e){let{entry:s="src/pages/*/main.{ts,js}",exclude:n=[]}=e,o=E(!0);try{let r=I.glob.sync(s,{cwd:process.cwd()});return A(r,s,n,o)}catch(r){throw o("\u53D1\u73B0\u9875\u9762\u5931\u8D25:",r),r}}function be(e){let{entry:s="src/pages/*/main.{ts,js}",exclude:n=[],pageConfigs:o={}}=e,r=E(!1),u=new Set,y=I.glob.sync(s,{cwd:process.cwd()}),c=A(y,s,n,r);if(c.length===0)throw new Error(`\u672A\u627E\u5230\u5339\u914D\u7684\u5165\u53E3\u6587\u4EF6: ${s}`);try{for(let t of c){let i={pageName:t.name,filePath:t.file,relativePath:S.relative(process.cwd(),t.file)},l=M(o,i,r)?.strategy||"default";u.add(l)}return Array.from(u).sort()}catch(t){return r("\u83B7\u53D6\u53EF\u7528\u7B56\u7565\u5931\u8D25:",t),["default"]}}var X,I,S,v,k=D(()=>{"use strict";x();X=require("vite"),I=require("glob"),S=P(require("path")),v=P(require("fs"));J();K();Q()});var se={};T(se,{hasCustomConfig:()=>$e,loadUserConfig:()=>we});function $e(){for(let e of te){let s=q.resolve(process.cwd(),e);if(Y.existsSync(s))return!0}return!1}async function we(e){let s=await Se();if(s){let n=s(e);return n||{}}return null}async function xe(e){if(e.endsWith(".ts"))return(0,ee.createJiti)(F,{interopDefault:!0}).import(e);if(e.endsWith(".js")||e.endsWith(".mjs"))return import(`${(0,Z.pathToFileURL)(e).href}?t=${Date.now()}`);throw new Error(`\u4E0D\u652F\u6301\u7684\u914D\u7F6E\u6587\u4EF6\u7C7B\u578B: ${e}`)}async function Se(){let e=process.cwd();for(let s of te){let n=q.resolve(e,s);if(Y.existsSync(n))try{let o=await xe(n),r=o.default||o;if(typeof r=="function")return r;console.warn(`\u914D\u7F6E\u6587\u4EF6 ${s} \u5FC5\u987B\u9ED8\u8BA4\u5BFC\u51FA\u4E00\u4E2A\u51FD\u6570`)}catch(o){console.error(`\u52A0\u8F7D\u914D\u7F6E\u6587\u4EF6 ${s} \u5931\u8D25:`,o)}}return null}var Y,q,Z,ee,te,ne=D(()=>{"use strict";x();Y=P(require("fs")),q=P(require("path")),Z=require("url"),ee=require("jiti"),te=["multipage.config.ts","multipage.config.js","multipage.config.mjs"]});var oe={};T(oe,{DEFAULT_CONFIG:()=>C,isEmptyConfig:()=>Ce,mergeWithDefaults:()=>ve});function ve(e){if(!e)return{...C};let s=e.strategies??e.buildStrategies??C.strategies;return{entry:e.entry??C.entry,exclude:e.exclude??C.exclude,template:e.template??C.template,placeholder:e.placeholder??C.placeholder,debug:e.debug??C.debug,strategies:s,pageConfigs:e.pageConfigs??C.pageConfigs,__forceBuildStrategy:e.__forceBuildStrategy}}function Ce(e){if(Object.keys(e).length===0)return!0;let s=e.entry&&e.entry!==C.entry,n=e.strategies&&Object.keys(e.strategies).length>0||e.buildStrategies&&Object.keys(e.buildStrategies).length>0,o=e.pageConfigs&&(typeof e.pageConfigs=="function"||Object.keys(e.pageConfigs).length>0);return!s&&!n&&!o}var C,re=D(()=>{"use strict";x();C={entry:"src/pages/**/*.{ts,js}",exclude:[],template:"index.html",placeholder:"{{ENTRY_FILE}}",debug:!1,strategies:{default:{}},pageConfigs:{}}});var _e={};T(_e,{buildAll:()=>ae});module.exports=ue(_e);x();var ie=require("child_process"),a=P(require("fs")),h=P(require("path")),B=P(require("glob"));k();function Pe(){let e=process.argv.slice(2),s=[],n=!1,o,r,u=3,y=!0;for(let c=0;c<e.length;c++){let t=e[c];if(t==="--debug")n=!0;else if(t==="--cwd")o=e[++c];else if(t==="--strategy")r=e[++c].split(",").map(g=>g.trim());else if(t==="--concurrency"){let i=e[++c];u=parseInt(i,10),(isNaN(u)||u<1)&&(console.error("\u274C \u5E76\u53D1\u6570\u5FC5\u987B\u662F\u5927\u4E8E0\u7684\u6574\u6570"),process.exit(1))}else t==="--flatten"?y=!0:t==="--no-flatten"?y=!1:t==="--help"||t==="-h"?(console.log(`
|
|
3
|
-
\u4F7F\u7528\u65B9\u6CD5: vite-mp [\u9009\u9879]
|
|
4
|
-
|
|
5
|
-
\u9009\u9879:
|
|
6
|
-
--debug \u542F\u7528\u8C03\u8BD5\u6A21\u5F0F
|
|
7
|
-
--cwd <dir> \u6307\u5B9A\u5DE5\u4F5C\u76EE\u5F55
|
|
8
|
-
--strategy <list> \u6307\u5B9A\u6784\u5EFA\u7B56\u7565\uFF0C\u652F\u6301\u9017\u53F7\u5206\u9694\u591A\u4E2A\u7B56\u7565
|
|
9
|
-
--concurrency <num> \u5E76\u53D1\u6784\u5EFA\u6570\uFF08\u9ED8\u8BA4\uFF1A3\uFF09
|
|
10
|
-
--flatten \u6241\u5E73\u5316\u8F93\u51FA\u7ED3\u6784\uFF08\u9ED8\u8BA4\u542F\u7528\uFF09
|
|
11
|
-
--no-flatten \u7981\u7528\u6241\u5E73\u5316\u8F93\u51FA\u7ED3\u6784
|
|
12
|
-
--help, -h \u663E\u793A\u5E2E\u52A9\u4FE1\u606F
|
|
13
|
-
|
|
14
|
-
\u5176\u4ED6\u6240\u6709\u53C2\u6570\u5C06\u4F20\u9012\u7ED9 vite build \u547D\u4EE4
|
|
15
|
-
|
|
16
|
-
\u793A\u4F8B:
|
|
17
|
-
vite-mp # \u6784\u5EFA\u6240\u6709\u7B56\u7565\uFF08\u9ED8\u8BA4\u6241\u5E73\u5316\uFF09
|
|
18
|
-
vite-mp --strategy mobile # \u53EA\u6784\u5EFAmobile\u7B56\u7565
|
|
19
|
-
vite-mp --strategy mobile,tablet # \u6784\u5EFAmobile\u548Ctablet\u7B56\u7565
|
|
20
|
-
vite-mp --no-flatten # \u7981\u7528\u6241\u5E73\u5316\u8F93\u51FA\u7ED3\u6784
|
|
21
|
-
vite-mp --concurrency 2 # \u8BBE\u7F6E\u5E76\u53D1\u6570\u4E3A2
|
|
22
|
-
vite-mp --debug # \u542F\u7528\u8C03\u8BD5\u6A21\u5F0F
|
|
23
|
-
vite-mp --cwd example # \u5728example\u76EE\u5F55\u8FD0\u884C
|
|
24
|
-
vite-mp --mode production --debug # \u4F20\u9012\u989D\u5916\u53C2\u6570\u7ED9vite
|
|
25
|
-
`),process.exit(0)):t!=="build"&&s.push(t)}return{viteBuildArgs:s,debug:n,cwd:o,strategies:r,concurrency:u,flatten:y}}async function Fe(){let{loadUserConfig:e,hasCustomConfig:s}=await Promise.resolve().then(()=>(ne(),se)),{mergeWithDefaults:n}=await Promise.resolve().then(()=>(re(),oe)),o=null;return s()&&(o=await e({mode:"production",command:"build",isCLI:!0}),o||console.log("\u274C \u914D\u7F6E\u6587\u4EF6\u52A0\u8F7D\u5931\u8D25")),n(o)}function Oe(e,s,n){return new Promise(o=>{let r=n?console.log.bind(console,`[${e}]`):()=>{},u={...process.env,VITE_MULTI_PAGE_STRATEGY:e},y=["build",...s],c=(0,ie.spawn)("npx",["vite",...y],{stdio:n?"inherit":"pipe",env:u,cwd:process.cwd(),shell:process.platform==="win32"}),t="";n||c.stderr?.on("data",i=>{t+=i.toString()}),c.on("close",i=>{let g=i===0,l=h.resolve(process.cwd(),"dist",e);if(g)try{if(a.existsSync(l)){let m=a.readdirSync(l);for(let p of m)if(p.startsWith(".temp.mp.")&&p.endsWith(".html")){let f=h.resolve(l,p),b=`${p.replace(/^\.temp\.mp\./,"").replace(/\.html$/,"")}.html`,$=h.resolve(l,b);a.renameSync(f,$)}}}catch(m){r("\u91CD\u547D\u540DHTML\u6587\u4EF6\u5931\u8D25:",m)}else!n&&t&&console.error(`\u7B56\u7565 ${e} \u9519\u8BEF\u8F93\u51FA:`,t);o({strategy:e,success:g,error:g?void 0:t||`\u6784\u5EFA\u5931\u8D25\uFF0C\u9000\u51FA\u7801: ${i}`,outputDir:l})}),c.on("error",i=>{r(`\u274C \u7B56\u7565 ${e} \u6784\u5EFA\u51FA\u9519:`,i.message);let g=L(s);o({strategy:e,success:!1,error:i.message,outputDir:g})})})}async function De(e){let s=B.sync(".temp.mp.*.html",{cwd:process.cwd()});for(let n of s){let o=h.resolve(process.cwd(),n);try{a.unlinkSync(o)}catch{}}}async function je(e,s){let n=s?console.log.bind(console,"[flatten]"):()=>{},o=h.resolve(process.cwd(),"dist");if(!a.existsSync(o))return;n("\u5F00\u59CB\u6241\u5E73\u5316\u8F93\u51FA\u7ED3\u6784...");let r=[];for(let t of e){let i=h.resolve(o,t);if(a.existsSync(i)){let g=a.readdirSync(i);for(let l of g)if(l.endsWith(".html")){let m=h.resolve(i,l),p=h.resolve(o,l),f=a.existsSync(p)?h.resolve(o,`${t}-${l}`):p;a.renameSync(m,f),r.push(h.basename(f)),n(`\u79FB\u52A8HTML: ${t}/${l} -> ${h.basename(f)}`)}}}let u=h.resolve(o,"assets");if(a.existsSync(u)){let t=h.resolve(o,"assets-backup");a.existsSync(t)&&a.rmSync(t,{recursive:!0}),a.renameSync(u,t)}a.mkdirSync(u,{recursive:!0});let y=new Set;for(let t of e){let i=h.resolve(o,t);if(a.existsSync(i)){let g=h.resolve(i,"assets");if(a.existsSync(g)){let l=a.readdirSync(g);for(let m of l){let p=h.resolve(g,m),f=h.resolve(u,m);if(!y.has(m))a.renameSync(p,f),y.add(m),n(`\u79FB\u52A8\u8D44\u6E90: ${t}/assets/${m} -> assets/${m}`);else{let d=a.readFileSync(p),b=a.readFileSync(f);if(d.equals(b))a.unlinkSync(p),n(`\u5220\u9664\u91CD\u590D\u8D44\u6E90: ${t}/assets/${m} (\u5185\u5BB9\u76F8\u540C)`);else{let $=h.parse(m).name,w=h.parse(m).ext,j=`${$}-${t}${w}`,N=h.resolve(u,j);a.renameSync(p,N),n(`\u79FB\u52A8\u8D44\u6E90: ${t}/assets/${m} -> assets/${j} (\u5185\u5BB9\u4E0D\u540C)`)}}}}}}let c=new Set;for(let t of e){let i=h.resolve(o,t);if(a.existsSync(i)){let g=a.readdirSync(i);for(let l of g)if(!l.endsWith(".html")&&l!=="assets"){let m=h.resolve(i,l),p=h.resolve(o,l);a.statSync(m).isDirectory()?c.has(l)?(a.rmSync(m,{recursive:!0}),n(`\u5220\u9664\u91CD\u590D\u76EE\u5F55: ${t}/${l}`)):(a.existsSync(p)&&a.rmSync(p,{recursive:!0}),a.renameSync(m,p),c.add(l),n(`\u79FB\u52A8\u76EE\u5F55: ${t}/${l} -> ${l}`)):c.has(l)?(a.unlinkSync(m),n(`\u5220\u9664\u91CD\u590D\u6587\u4EF6: ${t}/${l}`)):(a.renameSync(m,p),c.add(l),n(`\u79FB\u52A8\u6587\u4EF6: ${t}/${l} -> ${l}`))}}}for(let t of r){let i=h.resolve(o,t);if(a.existsSync(i)){let g=a.readFileSync(i,"utf-8"),l="default";t==="mobile.html"?l="mobile":t==="tablet.html"?l="tablet":t.startsWith("mobile-")?l="mobile":t.startsWith("tablet-")&&(l="tablet");let m=h.resolve(o,"assets");if(a.existsSync(m)){let p=a.readdirSync(m);for(let f of p)if(f.includes(`-${l}`)){let b=f.replace(`-${l}`,"").replace(/[.*+?^${}()|[\]\\]/g,"\\$&"),$=new RegExp(`\\./assets/${b}(?=\\s|>|"|')`,"g");g=g.replace($,`./assets/${f}`)}}a.writeFileSync(i,g),n(`\u66F4\u65B0\u8D44\u6E90\u8DEF\u5F84: ${t} -> assets/`)}}for(let t of e){let i=h.resolve(o,t);if(a.existsSync(i))try{a.rmSync(i,{recursive:!0}),n(`\u5220\u9664\u7B56\u7565\u76EE\u5F55: ${t}`)}catch(g){n(`\u5220\u9664\u7B56\u7565\u76EE\u5F55\u5931\u8D25: ${t}`,g)}}n("\u6241\u5E73\u5316\u5B8C\u6210")}async function Ee(e,s){let n=s?console.log.bind(console,"[cleanup]"):()=>{},o=B.sync(".temp.mp.*.html",{cwd:process.cwd()});for(let r of o){let u=h.resolve(process.cwd(),r);try{a.unlinkSync(u)}catch(y){n(`\u5220\u9664\u6839\u76EE\u5F55\u4E34\u65F6\u6587\u4EF6\u5931\u8D25: ${r}`,y)}}for(let r of e){let u=h.resolve(process.cwd(),"dist",r);if(a.existsSync(u)){let y=B.sync("*.mp.temp.html",{cwd:u});for(let c of y){let t=h.resolve(u,c);try{a.unlinkSync(t)}catch(i){n(`\u5220\u9664\u7B56\u7565\u76EE\u5F55\u4E34\u65F6\u6587\u4EF6\u5931\u8D25: ${r}/${c}`,i)}}}}}async function ae(){let{viteBuildArgs:e,debug:s,cwd:n,strategies:o,concurrency:r,flatten:u}=Pe(),y=s?console.log.bind(console,"[main]"):()=>{};if(n){let c=h.resolve(process.cwd(),n);a.existsSync(c)||(console.error(`\u274C \u6307\u5B9A\u7684\u76EE\u5F55\u4E0D\u5B58\u5728: ${c}`),process.exit(1)),process.chdir(c),y(`\u5207\u6362\u5DE5\u4F5C\u76EE\u5F55\u5230: ${c}`)}try{let c=await Fe(),{cleanViteOutputDirectory:t}=await Promise.resolve().then(()=>(k(),H));t(e),await Ne(c,e,s,o,r,u)}catch(c){console.error("\u274C \u6784\u5EFA\u5931\u8D25:",c instanceof Error?c.message:c),process.exit(1)}}async function Ne(e,s,n,o,r=3,u=!1){let y=n?console.log.bind(console,"[strategy-mode]"):()=>{},{getAvailableStrategies:c}=await Promise.resolve().then(()=>(k(),H)),t=c({entry:e.entry||"src/pages/*/main.{ts,js}",exclude:e.exclude||[],template:e.template||"index.html",placeholder:e.placeholder||"{{ENTRY_FILE}}",pageConfigs:e.pageConfigs||{},strategies:e.strategies||{}});if(t.length===0)throw new Error("\u672A\u627E\u5230\u4EFB\u4F55\u6784\u5EFA\u7B56\u7565");let i;if(o&&o.length>0){let f=o.filter(d=>!t.includes(d));if(f.length>0)throw new Error(`\u6307\u5B9A\u7684\u7B56\u7565\u4E0D\u5B58\u5728: ${f.join(", ")}
|
|
26
|
-
\u53EF\u7528\u7B56\u7565: ${t.join(", ")}`);i=o}else i=t;y(`\u{1F680} \u5F00\u59CB\u6784\u5EFA\u7B56\u7565: ${i.join(", ")} (\u5E76\u53D1\u6570: ${r})`);let g=[];for(let f=0;f<i.length;f+=r){let d=i.slice(f,f+r),b=d.map(w=>Oe(w,s,n)),$=await Promise.all(b);g.push(...$),n&&y(`\u6279\u6B21 ${Math.floor(f/r)+1} \u5B8C\u6210: ${d.join(", ")}`)}let l=g.filter(f=>f.success).length;g.length-l>0&&(console.log(`
|
|
27
|
-
\u274C \u6784\u5EFA\u5931\u8D25:`),g.filter(f=>!f.success).forEach(f=>{console.log(` - ${f.strategy}: ${f.error}`)}),await De(n),process.exit(1)),u&&await je(i,n),await Ee(i,n);let p=g.filter(f=>f.success);if(console.log(`
|
|
28
|
-
\u{1F389} \u6784\u5EFA\u6210\u529F\uFF01`),console.log(`\u{1F4E6} \u7B56\u7565: ${p.map(f=>f.strategy).join(", ")}`),u){console.log("\u{1F4C1} \u8F93\u51FA\u7ED3\u6784: \u6241\u5E73\u5316");let f=h.resolve(process.cwd(),"dist");if(a.existsSync(f)){let d=a.readdirSync(f).filter(b=>b.endsWith(".html"));console.log(` - HTML\u6587\u4EF6: ${d.join(", ")}`)}}else for(let f of p){let d=h.resolve(process.cwd(),"dist",f.strategy);if(a.existsSync(d)){let b=a.readdirSync(d).filter($=>$.endsWith(".html"));console.log(` - ${f.strategy}: ${b.join(", ")}`)}}}require.main===module&&ae().catch(e=>{console.error("\u274C \u672A\u5904\u7406\u7684\u9519\u8BEF:",e),process.exit(1)});0&&(module.exports={buildAll});
|
package/dist/index.d.mts
DELETED
|
@@ -1,74 +0,0 @@
|
|
|
1
|
-
import { UserConfig, Plugin } from 'vite';
|
|
2
|
-
|
|
3
|
-
interface MultiPageOptions {
|
|
4
|
-
entry?: string;
|
|
5
|
-
exclude?: string[];
|
|
6
|
-
template?: string;
|
|
7
|
-
placeholder?: string;
|
|
8
|
-
debug?: boolean;
|
|
9
|
-
strategies?: Record<string, ConfigStrategy>;
|
|
10
|
-
buildStrategies?: Record<string, ConfigStrategy>;
|
|
11
|
-
pageConfigs?: Record<string, PageConfig> | PageConfigFunction;
|
|
12
|
-
__forceBuildStrategy?: string;
|
|
13
|
-
}
|
|
14
|
-
type Options = MultiPageOptions;
|
|
15
|
-
interface BuildConfigOptions {
|
|
16
|
-
entry: string;
|
|
17
|
-
exclude: string[];
|
|
18
|
-
template: string;
|
|
19
|
-
placeholder: string;
|
|
20
|
-
strategies?: Record<string, ConfigStrategy>;
|
|
21
|
-
pageConfigs?: Record<string, PageConfig> | PageConfigFunction;
|
|
22
|
-
forceBuildStrategy?: string;
|
|
23
|
-
}
|
|
24
|
-
type ConfigStrategy = Omit<UserConfig, 'plugins'>;
|
|
25
|
-
interface PageConfig {
|
|
26
|
-
strategy?: string;
|
|
27
|
-
define?: Record<string, any>;
|
|
28
|
-
template?: string;
|
|
29
|
-
viteConfig?: UserConfig;
|
|
30
|
-
match?: string;
|
|
31
|
-
}
|
|
32
|
-
interface PageContext {
|
|
33
|
-
pageName: string;
|
|
34
|
-
filePath: string;
|
|
35
|
-
relativePath: string;
|
|
36
|
-
fullPath?: string;
|
|
37
|
-
strategy?: string;
|
|
38
|
-
isMatched?: boolean;
|
|
39
|
-
}
|
|
40
|
-
type PageConfigFunction = (context: PageContext) => PageConfig | null;
|
|
41
|
-
interface PluginContext {
|
|
42
|
-
mode: string;
|
|
43
|
-
command: 'build' | 'serve';
|
|
44
|
-
isCLI: boolean;
|
|
45
|
-
}
|
|
46
|
-
type ConfigFunction = (context: PluginContext) => MultiPageOptions;
|
|
47
|
-
type ConfigTransformFunction = (config: MultiPageOptions, context: PluginContext) => MultiPageOptions;
|
|
48
|
-
declare function defineConfig(config: MultiPageOptions | ConfigFunction): ConfigFunction;
|
|
49
|
-
declare function defineConfigTransform(transform: ConfigTransformFunction): ConfigTransformFunction;
|
|
50
|
-
|
|
51
|
-
/**
|
|
52
|
-
* 构建时配置生成器
|
|
53
|
-
* 根据策略和页面配置生成多页面构建配置
|
|
54
|
-
*/
|
|
55
|
-
declare function generateBuildConfig(options: BuildConfigOptions): Record<string, UserConfig>;
|
|
56
|
-
/**
|
|
57
|
-
* 获取Vite配置的输出目录
|
|
58
|
-
* 需要传入已解析的Vite配置或命令行参数
|
|
59
|
-
*/
|
|
60
|
-
declare function getViteOutputDirectory(viteBuildArgs?: string[]): string;
|
|
61
|
-
/**
|
|
62
|
-
* 清理Vite配置的输出目录
|
|
63
|
-
*/
|
|
64
|
-
declare function cleanViteOutputDirectory(viteBuildArgs?: string[]): void;
|
|
65
|
-
declare function getAvailableStrategies(options: BuildConfigOptions): string[];
|
|
66
|
-
|
|
67
|
-
/**
|
|
68
|
-
* 合并用户配置和默认配置
|
|
69
|
-
*/
|
|
70
|
-
declare function mergeWithDefaults(userConfig: MultiPageOptions | null | undefined): MultiPageOptions;
|
|
71
|
-
|
|
72
|
-
declare function viteMultiPage(transform?: ConfigTransformFunction): Plugin;
|
|
73
|
-
|
|
74
|
-
export { type ConfigFunction, type ConfigTransformFunction, type Options, type PageConfig, type PageContext, type PluginContext, cleanViteOutputDirectory, viteMultiPage as default, defineConfig, defineConfigTransform, generateBuildConfig, getAvailableStrategies, getViteOutputDirectory, mergeWithDefaults, viteMultiPage };
|