首頁
文章
隱私
  • 繁體中文
  • 简体中文
首頁
文章
隱私
  • 繁體中文
  • 简体中文

【開發筆記】那些 Webpack 過渡到 Vite 的坑

用 JavaScript 開發 Web 應用的朋友,一定多少聽過 Webpack。雖然不完美,但是長年下來,至少在 Vue 2 框架以前 Webpack 一直是封裝 Web 應用的主流選擇之一。直到近年 Vite 發表且開始逐漸受到重視,Webpack 過去令人詬病的體積龐大,編譯緩慢等等問題才慢慢獲得解決。但是...

Vite 是以 Native ES Modules 方式載入程式碼

不同於 Webpack 將需要用到的資源以打包的方式整個轉譯和封裝起來,Vite 在熱更新時,僅在程式碼的部分以 Native ES Modules 方式載入,避開 bundle 和 translation 耗費時間的過程,讓整個開發修改迭代的過程更加敏捷,更有效率。

新的機制帶來新的坑

不過新的機制雖然改善了就有的問題,但是也帶來新的毛病。例如在筆者近期的專案上,就出現了 AWS SDK v2 在 Vue 3 + Vite 項目配置上出現了生產環境編譯成功,但是無法執行的問題。直到 AWS SDK 更新到 v3 改寫了 S3 相關的程式碼才獲得解決。過程雖然波折,但是成果是值得的。整個 Web 應用在最後編譯輸出的大小節約方面,獲得了巨大的改善。

不過新的 Upload() 在處理上傳進度的部分,因為最小單位是 5mb 起跳,因此小檔案上傳時,prgress 更新不如先前 v2 使用 putObject 來得積極,算是個小缺點。

import { Buffer } from "buffer";
import { XhrHttpHandler } from "@aws-sdk/xhr-http-handler";
import { S3 } from "@aws-sdk/client-s3";
import { Upload } from "@aws-sdk/lib-storage";

(file, Key) => {
        return new Promise(async (resolve, reject) => {
            const reader = new FileReader()
            const blob = await fetch(file.objectURL).then((r) => r.blob()); //blob:url
            reader.readAsDataURL(blob);

            reader.onerror = function (error) {
                reject(error)
            }

            reader.onload = async function (loadEvent) {
                const base64 = reader.result.replace(`data:${file.type};base64,`, '')
                const params = {
                    ACL: 'public-read',
                    Key: encodeURI(Key),
                    Body: Buffer.from(base64, 'base64'),
                    ContentType: file.type,
                    Bucket: bucket
                }

                try {
                    const upload = new Upload({
                        client: s3,
                        params: params,
                    });
                    upload.on("httpUploadProgress", (progressEvent) => {
                        const value = parseInt(Math.round((progressEvent.loaded * 100) / progressEvent.total));
                        window.dispatchEvent(new CustomEvent(import.meta.env.VITE_DEFAULT_NOTIFICATION_CUSTOM_HTTPUPLOADPROGRESS, {
                            detail: {
                                progress: value,
                                loaded: progressEvent.loaded,
                                total: progressEvent.total
                            }
                        }));
                    });
                    upload.done().then((response) => {
                        resolve(response);
                    });
                } catch (error) {
                    console.log(error);
                    reject(error);
                }
            }
        })
    }

child_process 在 Vite 內也無法直接封裝到項目中引用

另外,就是 child_process 的部分。雖然網路上有些朋友分享了編輯 vite.config.js 讓 child_process 可以直接在項目中引用的方式,但是筆者一直沒有嘗試成功。後來是將 child_process 分離到後端中,以接口調用的方式來解決。

表面上似乎麻煩了一點,但是在整個項目架構上,因為 child_process 是用在 shell command 與 JavaScript 不同的異質性執行,或許分離到後端中是更加合理以及彈性,容易維護的選擇。

以下是 nodejs 後端參考的代碼例子。

const iconv = require("iconv-lite");
iconv.skipDecodeWarning = true;
const child_process = require("child_process");
function handleShellCommand(cmd) {
  let result = {};
  return new Promise((resolve, reject) => {
    child_process.exec(cmd, { encoding: "binary" }, (err, stdout, stderr) => {
      let data = iconv.decode(stdout, "utf-8");
      if (err) {
        result.errCode = 500;
        result.data = {
          data: data,
          code: result.errCode,
          message: `錯誤:指令’${str.split(" ")["0"]}’無法執行`
        };
        reject(result);
        return;
      }
      result.errCode = 200;
      result.data = {
        data: data,
        code: result.errCode,
        message: "成功"
      };
      resolve(result);
    });
  });
}