首页
文章
隐私
  • 繁體中文
  • 简体中文
首页
文章
隐私
  • 繁體中文
  • 简体中文

【开发笔记】那些 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);
    });
  });
}