Jelajahi Sumber

fix: add Vite base back for JS imports + proxy rewrites JS/CSS too

- vite.config.js: base from PREVIEW_BASE_PATH for JS module import resolution
- previewProxy: now rewrites paths in text/javascript responses too
- Regex matches HTML (src/href) and JS (from/import) paths
- Skips paths already prefixed with /ads/preview/ to avoid doubling
guoziyun 3 minggu lalu
induk
melakukan
e7eedf6639

+ 1 - 1
platform/server/dist/middleware/previewProxy.d.ts.map

@@ -1 +1 @@
-{"version":3,"file":"previewProxy.d.ts","sourceRoot":"","sources":["../../src/middleware/previewProxy.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAmB5C;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,GAAG,IAAI,CAsF9D"}
+{"version":3,"file":"previewProxy.d.ts","sourceRoot":"","sources":["../../src/middleware/previewProxy.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAmB5C;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,GAAG,IAAI,CA2F9D"}

+ 18 - 13
platform/server/dist/middleware/previewProxy.js

@@ -53,8 +53,10 @@ function previewProxy(req, res) {
         headers: reqHeaders,
     }, (proxyRes) => {
         const contentType = (proxyRes.headers["content-type"] || "");
-        const isHtml = contentType.includes("text/html");
-        console.log(`[preview:proxy] response ${proxyRes.statusCode} content-type=${contentType} isHtml=${isHtml}`);
+        const isText = contentType.includes("text/html") ||
+            contentType.includes("text/javascript") ||
+            contentType.includes("application/javascript");
+        console.log(`[preview:proxy] response ${proxyRes.statusCode} content-type=${contentType} isText=${isText}`);
         // 复制响应 headers(过滤 hop-by-hop)
         const resHeaders = {};
         for (const [key, value] of Object.entries(proxyRes.headers)) {
@@ -65,20 +67,23 @@ function previewProxy(req, res) {
             }
         }
         res.status(proxyRes.statusCode || 200);
-        if (isHtml) {
+        if (isText) {
             const chunks = [];
             proxyRes.on("data", (chunk) => chunks.push(chunk));
             proxyRes.on("end", () => {
-                let html = Buffer.concat(chunks).toString("utf-8");
-                // 将 src="/..." 和 href="/..." 重写为 /ads/preview/...
-                // 匹配 root-absolute 路径:以 / 开头,后跟非 / 字符(避免匹配 //)
-                html = html.replace(/(src|href)="\/([^/][^"]*)"/g, '$1="/ads/preview/$2"');
-                // 日志:检查重写后的 @vite/client 行
-                const viteClientMatch = html.match(/src="[^"]*@vite\/client[^"]*"/);
-                console.log(`[preview:proxy] HTML vite/client: ${viteClientMatch?.[0] || "NOT FOUND"}`);
-                const body = Buffer.from(html, "utf-8");
-                resHeaders["content-type"] = "text/html; charset=utf-8";
-                resHeaders["content-length"] = String(body.length);
+                let body = Buffer.concat(chunks).toString("utf-8");
+                // 重写 HTML (src="/...", href="/...") 和 JS (from "/...", import "/...")
+                // 为 /ads/preview/...(跳过已有前缀的,支持单双引号)
+                body = body.replace(/((?:src|href)=["']|(?:from|import)\s*["'])\/(?!ads\/preview\/)([^"']+)(["'])/g, '$1/ads/preview/$2$3');
+                // 日志
+                if (contentType.includes("text/html")) {
+                    const viteClientMatch = body.match(/src="[^"]*@vite\/client[^"]*"/);
+                    console.log(`[preview:proxy] HTML vite/client: ${viteClientMatch?.[0] || "NOT FOUND"}`);
+                }
+                resHeaders["content-type"] = contentType.includes("text/html")
+                    ? "text/html; charset=utf-8"
+                    : contentType;
+                resHeaders["content-length"] = String(Buffer.byteLength(body, "utf-8"));
                 res.set(resHeaders);
                 res.send(body);
             });

File diff ditekan karena terlalu besar
+ 0 - 0
platform/server/dist/middleware/previewProxy.js.map


+ 20 - 15
platform/server/src/middleware/previewProxy.ts

@@ -51,8 +51,10 @@ export function previewProxy(req: Request, res: Response): void {
     },
     (proxyRes) => {
       const contentType = (proxyRes.headers["content-type"] || "") as string;
-      const isHtml = contentType.includes("text/html");
-      console.log(`[preview:proxy] response ${proxyRes.statusCode} content-type=${contentType} isHtml=${isHtml}`);
+      const isText = contentType.includes("text/html") ||
+                     contentType.includes("text/javascript") ||
+                     contentType.includes("application/javascript");
+      console.log(`[preview:proxy] response ${proxyRes.statusCode} content-type=${contentType} isText=${isText}`);
 
       // 复制响应 headers(过滤 hop-by-hop)
       const resHeaders: Record<string, string> = {};
@@ -65,26 +67,29 @@ export function previewProxy(req: Request, res: Response): void {
 
       res.status(proxyRes.statusCode || 200);
 
-      if (isHtml) {
+      if (isText) {
         const chunks: Buffer[] = [];
         proxyRes.on("data", (chunk: Buffer) => chunks.push(chunk));
         proxyRes.on("end", () => {
-          let html = Buffer.concat(chunks).toString("utf-8");
+          let body = Buffer.concat(chunks).toString("utf-8");
 
-          // 将 src="/..." 和 href="/..." 重写为 /ads/preview/...
-          // 匹配 root-absolute 路径:以 / 开头,后跟非 / 字符(避免匹配 //
-          html = html.replace(
-            /(src|href)="\/([^/][^"]*)"/g,
-            '$1="/ads/preview/$2"',
+          // 重写 HTML (src="/...", href="/...") 和 JS (from "/...", import "/...")
+          // 为 /ads/preview/...(跳过已有前缀的,支持单双引号
+          body = body.replace(
+            /((?:src|href)=["']|(?:from|import)\s*["'])\/(?!ads\/preview\/)([^"']+)(["'])/g,
+            '$1/ads/preview/$2$3',
           );
 
-          // 日志:检查重写后的 @vite/client 行
-          const viteClientMatch = html.match(/src="[^"]*@vite\/client[^"]*"/);
-          console.log(`[preview:proxy] HTML vite/client: ${viteClientMatch?.[0] || "NOT FOUND"}`);
+          // 日志
+          if (contentType.includes("text/html")) {
+            const viteClientMatch = body.match(/src="[^"]*@vite\/client[^"]*"/);
+            console.log(`[preview:proxy] HTML vite/client: ${viteClientMatch?.[0] || "NOT FOUND"}`);
+          }
 
-          const body = Buffer.from(html, "utf-8");
-          resHeaders["content-type"] = "text/html; charset=utf-8";
-          resHeaders["content-length"] = String(body.length);
+          resHeaders["content-type"] = contentType.includes("text/html")
+            ? "text/html; charset=utf-8"
+            : contentType;
+          resHeaders["content-length"] = String(Buffer.byteLength(body, "utf-8"));
           res.set(resHeaders);
           res.send(body);
         });

+ 5 - 0
templates/coloring/vite.config.js

@@ -42,7 +42,12 @@ module.exports = defineConfig(({ mode }) => {
   const output = platformBuild?.output;
   const outDir = output ? `dist/${output}` : "dist";
 
+  // PREVIEW_BASE_PATH 仅用于 Vite dev server,控制 JS module import 的路径前缀
+  // (HTML 中的 @vite/client 注入不生效,由 Express 代理处理)
+  const base = process.env.PREVIEW_BASE_PATH || undefined;
+
   return {
+    base,
     plugins: [viteSingleFile(), finalizeHtmlPlugin(outDir, adapter)],
     server: {
       allowedHosts: ["color2.jccytech.cn", "localhost", ".jccytech.cn"],

Beberapa file tidak ditampilkan karena terlalu banyak file yang berubah dalam diff ini