umijs / umi

A framework in react community ✨
https://umijs.org
MIT License
15.06k stars 2.64k forks source link

[Bug] umijs 4 与@aws-sdk/lib-storage和@aws-sdk/client-s3不兼容,dev可运行,但build出错 #12123

Closed miscab closed 4 months ago

miscab commented 4 months ago

What happens?

用aws-sdk和client-s3开发了一个文件上传组件,在npm run dev模式下一切正常。一旦到npm run build,就会出现一系列问题。

  1. ERROR in 810.befaf443.async.js 810.befaf443.async.js from Terser plugin Transform failed with 4 errors: 810.befaf443.async.js:16806:0: ERROR: Transforming async generator functions to the configured target environment ("chrome80", "es2015") is not supported yet

image

为了解决这个问题,查询网上的做法,在根目录建立.umirc.ts,在其中输入targets: { chrome: 80 },这个问题不再报错,但发现了层出不穷的新问题,都跟插件有关。结论是umi max没有自动生成插件代码,所以在组件中无法使用各类插件,包括useModel等。

为了绕过这一问题,只有注释掉引用文件上传组件的代码,故障就不存在了。

<S3Uploader name="attachments" remotePath='erp/attachments/test' title="上传文件" />

Mini Showcase Repository(REQUIRED)

Please provide a minimal reproduction then upload to your GitHub. 请提供 最小重现,并上传到你的 GitHub 仓库

S3Uploader.tsx代码如下:

` import React from 'react'; import moment from 'moment';

import { ProFormUploadButton, ProFormUploadButtonProps } from '@ant-design/pro-components';

import { S3Client, DeleteObjectCommand, } from '@aws-sdk/client-s3';

import { Upload, } from '@aws-sdk/lib-storage';

import { UploadFile, message, Modal } from 'antd';

import { formatBytes } from '@/utils';

type S3UploaderProps = ProFormUploadButtonProps & { remotePath: string };

const S3Uploader: React.FC = (props) => {

const createClient = () => {
    return new S3Client({
        region: REACT_APP_AWS_REGION,
        credentials: {
            accessKeyId: REACT_APP_AWS_ACCESS_KEY_ID,
            secretAccessKey: REACT_APP_AWS_SECRET_ACCESS_KEY,
        },
    });
};

// 生成随机的文件key前缀 const getUploadFileKey = (remotePath: string, filename: string) => { remotePath = remotePath.replace(/\/$/, ''); return ${remotePath}/${moment(new Date()).format("YYYYMMDDHHmmss")}-${filename}.trim(); };

const [defaultFileList, setDefaultFileList] = React.useState<UploadFile[]>(props.value || []);

return (
    <ProFormUploadButton {...props}
        fieldProps={{
            fileList: defaultFileList,
            multiple: true,
            listType: 'picture',
            beforeUpload: (file) => {
                if (file.size > 1024 * 1024 * 50) {
                    message.error('上传文件不得超过50MB。');
                    return Upload.LIST_IGNORE;
                }
                return true;
            },

            onChange: ({ file, fileList }) => {
                if (!file.nameChanged) {
                    file.name = `${file.name} - ${formatBytes(file.size)}`;
                    file.nameChanged = true;
                }
                setDefaultFileList(fileList);
            },

            onRemove: (file) => {
                const {confirm} = Modal;
                return new Promise((resolve, reject) => {
                    confirm({
                        title: '删除附件',
                        content: '删除附件可能会导致数据丢失,确定要删除此附件吗?',
                        okText: '确定',
                        okType: 'danger',
                        cancelText: '取消',
                        onOk() {
                            const params = {
                                Bucket: REACT_APP_AWS_BUCKET_NAME,
                                Key: file?.response?.Key || file.key
                            };
                            const client = createClient();
                            client.send(new DeleteObjectCommand(params)).then((response) => {
                                const index = defaultFileList.indexOf(file);
                                const newFileList = defaultFileList.slice();
                                newFileList.splice(index, 1);
                                setDefaultFileList(newFileList);
                                resolve(true);
                            }).catch((error) => {
                                console.error(error);
                                reject(error);
                            });
                        },
                        onCancel() {
                            resolve(false);
                        },
                    });
                })
            },

            customRequest: async (options) => {
                const { onProgress, onError, onSuccess, file } = options;

                try {
                    const client = createClient();

                    const upload = new Upload({
                        client: client,
                        params: {
                            Bucket: REACT_APP_AWS_BUCKET_NAME,
                            Key: getUploadFileKey(props.remotePath, file.name),
                            ContentType: file.type,
                            Body: file
                        },
                    });

                    upload.on('httpUploadProgress', (progress) => {
                        onProgress({ percent: (progress.loaded / progress.total) * 100 });
                    });

                    upload.done().then((response) => {
                        onSuccess(response);
                    }).catch((error) => {
                        onError(error);
                    });
                } catch (error) {
                    onError(error);
                }
            },
        }}
    />
);

};

export default S3Uploader; `

How To Reproduce

Steps to reproduce the behavior: 1. 2.

  1. 安装依赖,npm i @aws-sdk/lib-stroage @aws-sdk/client-s3
  2. 在任一组件中引用开发的组件S3Uploader <S3Uploader name="attachments" remotePath='erp/test' title="上传文件" />
  3. 运行npm run build,就会出现无法完成的情况。

Expected behavior 1. 2.

期待的行为是命令成功完成,在dist下生成可上传的html和资源文件。

Context

package.json

{ "name": "ant-design-pro", "version": "6.0.0", "private": true, "description": "An out-of-box UI solution for enterprise applications", "scripts": { "analyze": "cross-env ANALYZE=1 max build", "build": "max build", "deploy": "npm run build && npm run gh-pages", "dev": "npm run start:dev", "gh-pages": "gh-pages -d dist", "i18n-remove": "pro i18n-remove --locale=zh-CN --write", "postinstall": "max setup", "jest": "jest", "lint": "npm run lint:js && npm run lint:prettier && npm run tsc", "lint-staged": "lint-staged", "lint-staged:js": "eslint --ext .js,.jsx,.ts,.tsx ", "lint:fix": "eslint --fix --cache --ext .js,.jsx,.ts,.tsx --format=pretty ./src ", "lint:js": "eslint --cache --ext .js,.jsx,.ts,.tsx --format=pretty ./src", "lint:prettier": "prettier -c --write \"**/**.{js,jsx,tsx,ts,less,md,json}\" --end-of-line auto", "openapi": "max openapi", "prepare": "husky install", "prettier": "prettier -c --write \"**/**.{js,jsx,tsx,ts,less,md,json}\"", "preview": "npm run build && max preview --port 8000", "record": "cross-env NODE_ENV=development REACT_APP_ENV=test max record --scene=login", "serve": "umi-serve", "start": "cross-env UMI_ENV=dev max dev", "start:dev": "cross-env REACT_APP_ENV=dev MOCK=none UMI_ENV=dev max dev", "start:no-mock": "cross-env MOCK=none UMI_ENV=dev max dev", "start:pre": "cross-env REACT_APP_ENV=pre UMI_ENV=dev max dev", "start:test": "cross-env REACT_APP_ENV=test MOCK=none UMI_ENV=dev max dev", "test": "jest", "test:coverage": "npm run jest -- --coverage", "test:update": "npm run jest -- -u", "tsc": "tsc --noEmit" }, "lint-staged": { "**/*.{js,jsx,ts,tsx}": "npm run lint-staged:js", "**/*.{js,jsx,tsx,ts,less,md,json}": [ "prettier --write" ] }, "browserslist": [ "> 1%", "last 2 versions", "not ie <= 10" ], "dependencies": { "@ant-design/icons": "^4.8.1", "@ant-design/pro-components": "^2.6.48", "@aws-sdk/client-s3": "^3.515.0", "@aws-sdk/lib-storage": "^3.515.0", "@umijs/route-utils": "^2.2.2", "antd": "^5.13.2", "antd-style": "^3.6.1", "bcryptjs": "^2.4.3", "classnames": "^2.5.1", "omit.js": "^2.0.2", "querystring": "^0.2.1", "rc-menu": "^9.12.4", "rc-util": "^5.38.1", "react": "^18.2.0", "react-dom": "^18.2.0", "react-helmet-async": "^1.3.0", "ts-md5": "^1.3.1" }, "devDependencies": { "@ant-design/pro-cli": "^3.3.0", "@ant-design/use-emotion-css": "^1.0.4", "@testing-library/react": "^13.4.0", "@types/classnames": "^2.3.1", "@types/express": "^4.17.21", "@types/history": "^4.7.11", "@types/jest": "^29.5.11", "@types/lodash": "^4.14.202", "@types/react": "^18.2.48", "@types/react-dom": "^18.2.18", "@types/react-helmet": "^6.1.11", "@umijs/fabric": "^2.14.1", "@umijs/lint": "^4.1.1", "@umijs/max": "^4.1.1", "cross-env": "^7.0.3", "eslint": "^8.56.0", "express": "^4.18.2", "gh-pages": "^3.2.3", "husky": "^7.0.4", "jest": "^29.7.0", "jest-environment-jsdom": "^29.7.0", "lint-staged": "^10.5.4", "mockjs": "^1.1.0", "prettier": "^2.8.8", "react-dev-inspector": "^1.9.0", "swagger-ui-dist": "^4.19.1", "ts-node": "^10.9.2", "typescript": "^5.3.3", "umi-presets-pro": "^2.0.3", "umi-serve": "^1.9.11" }, "engines": { "node": ">=12.0.0" } }

day-xue commented 4 months ago

感觉就是打包器不支持 把generator 打包成es6以前的语法 可以自己引入polyfill 试试

fz6m commented 4 months ago

第一个你遇到的 esbuild 压缩问题,可以根据打印的提示修改配置提升 targets 或者更改 jsMinifier 解决。

除了这个问题以外的问题,都是和你自己使用的库或者编写的代码相关的,如有问题,自行通过调整自己的代码应该都可以解决。

若还无法解决,需要给一个打包失败的最小复现仓库链接。