Skip to content

Cannot parse from a stream in the browser #443

@psaffrey

Description

@psaffrey

Describe the bug

I want to allow a user to upload a gzipped csv file and parse it in a stream (using pipeThrough / pipeTo). This works in Node, but not in the browser, where I get:

file-upload.html:52 Uncaught (in promise) TypeError: Failed to execute 'pipeTo' on 'ReadableStream': parameter 1 is not of type 'WritableStream'.
    at HTMLInputElement.<anonymous> (file-upload.html:52:18)

Line 52 is the pipeTo line from the example below, so it seems to think that the parse object is not a WritableStream.

To Reproduce

Dump the code below into a file, open it in a browser and then try uploading a .tsv.gz file. I tested in Chrome and Firefox. The same code works in Node, although you have to swap pipeThrough and pipeTo for pipe. I'll admit that I find the differences between Node and the browser for streaming a bit confusing so I may have made some obvious error here.

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>File Upload</title>
</head>
<body>
    <div class="upload-container">
        <form class="upload-form">
            <input type="file" id="fileInput" name="file">
        </form>
    </div>

    <script type="module">
        import { parse } from 'https://cdn.jsdelivr.net/npm/csv-parse@5.5.6/+esm'

        document.querySelector('#fileInput').addEventListener('change', (e) => {

            e.preventDefault();
            const file = document.getElementById('fileInput').files[0];

            // turn the file into a stream
            const fileStream = file.stream()

            // create a gunzip transform stream
            const unzipper = new DecompressionStream('gzip')    

            const records = [];

            // create a csv parser writeable stream
            const parser = parse({
              delimiter: '\t'
            });            
 
            parser.on('readable', function(){
              let record;
              while ((record = parser.read()) !== null) {
                records.push(record);
              }
            });
            parser.on('error', function(err){
              console.error(err.message);
            });
            parser.on('end', function(){
                console.log(records)
            })

            console.log("piping!")
            // pipe the file stream through the gunzip stream and into the csv parse stream
            fileStream
                .pipeThrough(unzipper)
                .pipeTo(parser)
        });
    </script>
</body>
</html>

** Additional Context **

I wonder if this issue is related, although I'm not trying to parse the complex CSVs listed in that issue.

I also have a similar issue raised for Papaparse.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions