aws-amplify / amplify-js

A declarative JavaScript library for application development using cloud services.
https://docs.amplify.aws/lib/q/platform/js
Apache License 2.0
9.39k stars 2.11k forks source link

progressCallback not triggered in AWS Amplify hosted environment during file upload #12624

Open idanail opened 7 months ago

idanail commented 7 months ago

Before opening, please confirm:

JavaScript Framework

React

Amplify APIs

Authentication, Storage

Amplify Categories

auth, storage, function, api, hosting

Environment information

``` # Put output below this line System: OS: Windows 10 10.0.22621 CPU: (8) x64 11th Gen Intel(R) Core(TM) i7-1165G7 @ 2.80GHz Memory: 16.55 GB / 31.71 GB Binaries: Node: 16.16.0 - ~\AppData\Roaming\nvm\v16.16.0\node.EXE npm: 8.11.0 - ~\AppData\Roaming\nvm\v16.16.0\npm.CMD Browsers: Edge: Chromium (119.0.2151.72) Internet Explorer: 11.0.22621.1 npmPackages: @amplitude/analytics-browser: 2.3.0 => 2.3.0 @apollo/client: 3.8.3 => 3.8.3 @apollo/client/cache: undefined () @apollo/client/core: undefined () @apollo/client/dev: undefined () @apollo/client/errors: undefined () @apollo/client/link/batch: undefined () @apollo/client/link/batch-http: undefined () @apollo/client/link/context: undefined () @apollo/client/link/core: undefined () @apollo/client/link/error: undefined () @apollo/client/link/http: undefined () @apollo/client/link/persisted-queries: undefined () @apollo/client/link/remove-typename: undefined () @apollo/client/link/retry: undefined () @apollo/client/link/schema: undefined () @apollo/client/link/subscriptions: undefined () @apollo/client/link/utils: undefined () @apollo/client/link/ws: undefined () @apollo/client/react: undefined () @apollo/client/react/components: undefined () @apollo/client/react/context: undefined () @apollo/client/react/hoc: undefined () @apollo/client/react/hooks: undefined () @apollo/client/react/parser: undefined () @apollo/client/react/ssr: undefined () @apollo/client/testing: undefined () @apollo/client/testing/core: undefined () @apollo/client/utilities: undefined () @apollo/client/utilities/globals: undefined () @aws-amplify/ui-react: 5.3.0 => 5.3.0 @aws-amplify/ui-react-internal: undefined () @aws-crypto/sha256-js: 5.0.0 => 5.0.0 (1.2.2, 3.0.0, 2.0.0) @aws-sdk/client-s3: 3.414.0 => 3.414.0 @aws-sdk/s3-request-presigner: 3.414.0 => 3.414.0 @aws-sdk/signature-v4: 3.374.0 => 3.374.0 (3.6.1, 3.186.0) @babel/plugin-transform-runtime: 7.22.15 => 7.22.15 @babel/preset-env: 7.22.20 => 7.22.20 @babel/preset-react: 7.22.15 => 7.22.15 @electives/ui-kit: 1.1.11 => 1.1.11 @emotion/react: 11.11.1 => 11.11.1 @emotion/styled: 11.11.0 => 11.11.0 @graphql-codegen/cli: 5.0.0 => 5.0.0 @graphql-codegen/introspection: 4.0.0 => 4.0.0 @graphql-codegen/typescript: 4.0.1 => 4.0.1 @graphql-codegen/typescript-operations: 4.0.1 => 4.0.1 @graphql-codegen/typescript-react-apollo: 3.3.7 => 3.3.7 @hookform/resolvers: 3.3.1 => 3.3.1 @hookform/resolvers/ajv: 1.0.0 @hookform/resolvers/arktype: 1.0.0 @hookform/resolvers/class-validator: 1.0.0 @hookform/resolvers/computed-types: 1.0.0 @hookform/resolvers/io-ts: 1.0.0 @hookform/resolvers/joi: 1.0.0 @hookform/resolvers/nope: 1.0.0 @hookform/resolvers/superstruct: 1.0.0 @hookform/resolvers/typanion: 1.0.0 @hookform/resolvers/typebox: 1.0.0 @hookform/resolvers/valibot: 1.0.0 @hookform/resolvers/vest: 1.0.0 @hookform/resolvers/yup: 1.0.0 @hookform/resolvers/zod: 1.0.0 @jest/globals: 29.7.0 => 29.7.0 @mui/icons-material: 5.14.9 => 5.14.9 @mui/lab: 5.0.0-alpha.144 => 5.0.0-alpha.144 @mui/material: 5.14.9 => 5.14.9 @svgr/webpack: 8.1.0 => 8.1.0 @tanstack/eslint-plugin-query: 4.34.1 => 4.34.1 @tanstack/react-query: 4.35.3 => 4.35.3 @tanstack/react-query-devtools: 4.35.3 => 4.35.3 @tanstack/react-table: 8.10.0 => 8.10.0 @testing-library/jest-dom: 5.17.0 => 5.17.0 @testing-library/react: 14.0.0 => 14.0.0 @testing-library/user-event: 14.5.1 => 14.5.1 @types/draft-js: 0.11.12 => 0.11.12 @types/papaparse: 5.3.8 => 5.3.8 @types/react: 18.2.21 => 18.2.21 @types/react-csv: 1.1.4 => 1.1.4 @types/react-dom: 18.2.7 => 18.2.7 @types/react-draft-wysiwyg: 1.13.4 => 1.13.4 @types/react-image-crop: 8.1.3 => 8.1.3 @types/react-router-dom: 5.3.3 => 5.3.3 @types/sortablejs: 1.15.2 => 1.15.2 @typescript-eslint/eslint-plugin: 6.7.0 => 6.7.0 @typescript-eslint/parser: 6.7.0 => 6.7.0 @vitejs/plugin-react: 4.0.4 => 4.0.4 array-move: 4.0.0 => 4.0.0 aws-amplify: 5.3.11 => 5.3.11 aws4: 1.12.0 => 1.12.0 babel-jest: 29.7.0 => 29.7.0 babel-plugin-transform-import-meta: 2.2.1 => 2.2.1 babel-plugin-transform-vite-meta-env: 1.0.3 => 1.0.3 chart.js: ^4.4.0 => 4.4.0 chart.js-auto: undefined () chart.js-helpers: undefined () chartjs-plugin-annotation: ^3.0.1 => 3.0.1 classnames: 2.3.2 => 2.3.2 (2.3.1) date-fns: 2.30.0 => 2.30.0 date-fns-tz: 2.0.0 => 2.0.0 diff: 5.1.0 => 5.1.0 (4.0.2) draft-js: 0.11.7 => 0.11.7 draft-js-export-html: 1.4.1 => 1.4.1 eslint: 8.49.0 => 8.49.0 eslint-config-prettier: 9.0.0 => 9.0.0 eslint-plugin-react: 7.33.2 => 7.33.2 eslint-plugin-react-hooks: 4.6.0 => 4.6.0 eslint-plugin-react-refresh: 0.4.3 => 0.4.3 graphql: 16.8.0 => 16.8.0 (15.8.0) html2canvas: 1.4.1 => 1.4.1 husky: 8.0.3 => 8.0.3 identity-obj-proxy: 3.0.0 => 3.0.0 jest: 29.7.0 => 29.7.0 jest-environment-jsdom: 29.7.0 => 29.7.0 jest-svg-transformer: 1.0.0 => 1.0.0 jspdf: 2.5.1 => 2.5.1 lint-staged: 14.0.1 => 14.0.1 lodash: 4.17.21 => 4.17.21 material-ui-confirm: 3.0.9 => 3.0.9 mathjs: 11.11.0 => 11.11.0 mockdate: 3.0.5 => 3.0.5 moment: 2.29.4 => 2.29.4 moment-timezone: 0.5.43 => 0.5.43 msw: 1.3.1 => 1.3.1 mui-nested-menu: 3.2.2 => 3.2.2 nanoid: 4.0.2 => 4.0.2 (3.3.6) papaparse: 5.4.1 => 5.4.1 pdfmake: 0.2.7 => 0.2.7 prettier: 3.0.3 => 3.0.3 react: 18.2.0 => 18.2.0 react-big-calendar: 1.8.2 => 1.8.2 react-chartjs-2: ^5.2.0 => 5.2.0 react-colorful: 5.6.1 => 5.6.1 react-confetti: 6.1.0 => 6.1.0 react-csv: 2.2.2 => 2.2.2 react-day-picker: 8.8.2 => 8.8.2 react-dom: 18.2.0 => 18.2.0 react-draft-wysiwyg: 1.15.0 => 1.15.0 react-ga4: 2.1.0 => 2.1.0 react-hook-form: 7.46.1 => 7.46.1 react-image-crop: 8.6.12 => 8.6.12 react-infinite-scroll-component: 6.1.0 => 6.1.0 react-pdf: 7.3.3 => 7.3.3 react-phone-number-input: 3.3.6 => 3.3.6 react-phone-number-input/commonjs: undefined () react-phone-number-input/core: undefined () react-phone-number-input/flags: undefined () react-phone-number-input/input-core: undefined () react-phone-number-input/input-max: undefined () react-phone-number-input/input-min: undefined () react-phone-number-input/input-mobile: undefined () react-phone-number-input/max: undefined () react-phone-number-input/min: undefined () react-phone-number-input/mobile: undefined () react-phone-number-input/react-hook-form: undefined () react-phone-number-input/react-hook-form-core: undefined () react-phone-number-input/react-hook-form-input: undefined () react-phone-number-input/react-hook-form-input-core: undefined () react-phone-number-input/react-native-input: undefined () react-phone-number-input/react-styleguidist: undefined () react-player: 2.13.0 => 2.13.0 react-router-dom: 6.16.0 => 6.16.0 react-select: 5.7.4 => 5.7.4 react-share: 4.4.1 => 4.4.1 react-sortablejs: 6.1.4 => 6.1.4 react-toastify: 9.1.3 => 9.1.3 react-video-thumbnail: 0.1.3 => 0.1.3 react-virtualized-auto-sizer: 1.0.20 => 1.0.20 react-webcam: 7.1.1 => 7.1.1 react-window: 1.8.9 => 1.8.9 save-svg-as-png: 1.4.17 => 1.4.17 sortablejs: 1.15.0 => 1.15.0 swiper: 10.2.0 => 10.2.0 ts-node: 10.9.1 => 10.9.1 typescript: 5.2.2 => 5.2.2 use-fit-text: 2.4.0 => 2.4.0 use-fit-text-example: undefined () vite: 4.4.9 => 4.4.9 vite-jsconfig-paths: 2.0.1 => 2.0.1 vite-plugin-svgr: 3.2.0 => 3.2.0 vite-tsconfig-paths: 4.2.1 => 4.2.1 yup: 1.2.0 => 1.2.0 npmGlobalPackages: corepack: 0.10.0 jest: 29.5.0 nodemon: 3.0.1 npm: 8.11.0 ```

Describe the bug

I am experiencing an issue with the Storage.put() method in my Amplify application when deployed to the hosted environment. The file upload itself is successful, but the progress is not displayed progressively as expected, but only when the file uploads successfully. Locally, the progressCallback() is working as intended and progressively displaying the percentage.

Expected behavior

I expect the progressCallback function to be triggered multiple times during the file upload, providing progress information.

Reproduction steps

Deploy the Amplify application to the hosted environment. Trigger a file upload using the Storage.put() method. Observe that the file is successfully uploaded, but the progress is not displayed.

Code Snippet

// Put your code below this line.

const [preEventVideoUploadProgress, setPreEventVideoUploadProgress] = useState(0);

const fileUpload = async (file, progressSetter) => {
    await Storage.put(`path`, file, {
        progressCallback(progress) {
            console.log(`uploaded: ${progress.loaded}/${progress.total}`);
            progressSetter(Math.round((progress.loaded / progress.total) * 100));
        }
    })
    .then((result) => {
        // handling the result
        console.log("result: ", result);
    })
    .catch((err) => {
        // handling the error
        console.error("error: ", err);
    });
};

return (
    <Button
        variant="outlined"
        color="primary"
        component="label"
        size="small"
        className={classes.button}
        disabled={!(preEventVideoUploadProgress === 0 || preEventVideoUploadProgress === 100)}
    >
        {preEventVideoUploadProgress === 0 || preEventVideoUploadProgress === 100
            ? "Upload New File"
            : "Uploading ... " + preEventVideoUploadProgress + "%"}
        <input
            type="file"
            accept=".mp4, .m4v, .mov"
            style={{ display: "none" }}
            onChange={(e) => {
                fileUpload(e.target.files[0], setPreEventVideoUploadProgress);
            }}
        />
    </Button>
);

Log output

``` // Put your logs below this line On localhost, during the uploading process, the log `console.log(`uploaded: ${progress.loaded}/${progress.total}`);` gets executed several times, displaying progressive percentages. On the deployed Amplify app (including staging and prod), however, it doesn't render the log `console.log(`uploaded: ${progress.loaded}/${progress.total}`);` even once. The file gets uploaded, and the next log I see is `console.log("result: ", result);`. I tried converting the `fileUpload` from an arrow function into a regular function. I tried removing the `async...await` and making other front-end syntax changes. All of them work locally, but on the deployed Amplify app, I experience the same behavior. I tried uploading files with sizes ranging from 2 MB to 20 MB. ```

aws-exports.js

No response

Manual configuration

No response

Additional configuration

No response

Mobile Device

No response

Mobile Operating System

No response

Mobile Browser

No response

Mobile Browser Version

No response

Additional information and screenshots

No response

nadetastic commented 7 months ago

Hi @idanail thank you for opening this issue. It doesn't look like you have enabled resumable option in your sample code as described in the documentation here - could you try that and let me know if the progress call back works as expected?

idanail commented 7 months ago

@nadetastic I already tried that, also tried with various file sizes (2MB-20MB). On localhost the progress callback works as intended, but not on the hosted environment.

brewerdaniel-IW commented 7 months ago

I too am having this issue. Works fine when running the development server (vite dev) but once pushed to S3/CloudFront the progress callback doesn't fire.

brewerdaniel-IW commented 7 months ago

I've, painfully, gone through all versions of aws-amplify and it seems that the update from 5.3.3 to 5.3.4 is what break it for me.

nadetastic commented 5 months ago

Hi @brewerdaniel-IW following up here - I can confirm the same behavior with v5 of my app when running a production build, which seems to be the key differentiator and not necessarily the deploy location. Im currently discussing with the team for understand what the root issue is but also wanted to provide an alternatives.

First if you haven't yet, I would strongly suggest migrating from v5 to v6 of the library, as this issue should not be present in v6. You can take a look at the migration documentation here but feel free to ask me any questions you may have.

If migrating is not possible for some reason, you can instead provide the resumable: true parameter to Storage.put() which I can confirm will trigger the progressCallback method. However by doing so, the Storage.put() command does not return a promise. Here's an example

Storage.put(`path`, file, {
      resumable: true, // Enable this
      progressCallback(progress) {
        console.log(`uploaded: ${progress.loaded}/${progress.total}`);
      },
      completeCallback: (event) => {
        console.log(`Successfully uploaded ${event}`);
      },
      errorCallback: (err) => {
        console.error("Unexpected error while uploading", err);
      },
});

I will follow up again but please let me know if you have any questions in the meantime.