Search code examples
javascriptwebpackvue.jsworkerpapaparse

Vue Webpack & PapaParse


I've been trying to utilize PapaParse's worker option (http://papaparse.com/#worker) with Vue's webpack template (https://github.com/vuejs-templates/webpack) but I'm having a problem:

Uncaught ReferenceError: window is not #defined

So I figure that it requires the file separately from the bundle file, so I used dependency like https://github.com/danderson00/webpack-worker and set it up to initialize a Worker class from the worker file. But I get the same error, and I have no idea why.

Here's my work

Vue file:

import axios from 'axios'
import client from 'webpack-worker/client'
import squel from 'squel'
import FileSaver from 'filesaver.js'
export default {
  name: 'Country',
  data () {
    return {
      downloading: true,
      dl_progress: 0,
      parsing: false,
      processing: false,
      data: null,
      ipv4: [],
      meta: [],
      dict: {},
      selected_country: []
    }
  },
  mounted () {
    // Unfortunately, MaxMind site has no cross-origin header, so we are unable to download directly
    axios.get(require('../../assets/archive/GeoLite2-Country-CSV.zip'), {
      responseType: 'blob', // JSZIP only takes in binary data, so we set the response as blob (binary)
      onDownloadProgress: (progressEvent) => {
        this.dl_progress = Math.round((event.loaded * 100) / event.total)
      }
    })
      .then((response) => {
        this.progress = 100
        this.downloading = false
        this.parsing = true
        this.data = response.data
        this.parse()
      })
  },
  methods: {
    parse () {
      client(new Worker('country.js'), {
        data: this.data
      })
        .subscribe(progress => {
          console.log(progress)
        })
        .then(result => {
          console.log('got result')
        })
    },
    process () {
      let out = []
      this.ipv4.forEach((block) => {
        if (this.selected_country.includes(block.registered_country_geoname_id)) {
          out.push({cidr: block.network, comment: this.dict[block.registered_country_geoname_id]})
        }
      })
      let SQL = squel
                  .insert()
                  .into('cidr_list')
                  .setFieldsRows(out)
                  .toString()
      let blob = new Blob([SQL], {type: 'application/sql;charset=utf-8'})
      FileSaver.saveAs(blob, 'country.sql')
      this.$toast.open({
        message: 'Successfully downloaded country import file',
        type: 'is-success'
      })
    }
  }
}

Worker file:

import process from 'webpack-worker/process'
import Papa from 'papaparse'
import JSZip from 'jszip'
import _ from 'lodash'

process((params, emit) => {
  emit(0)
  let zip = new JSZip()
  zip.loadAsync(params.data)
    .then((zipContent) => {
      zip.file('GeoLite2-Country-CSV_20171003/GeoLite2-Country-Blocks-IPv4.csv')
        .async('string')
        .then(data => {
          emit(25)
          Papa.parse(data, {
            header: true,
            complete: ipv4 => {
              emit(50)
              zip.file('GeoLite2-Country-CSV_20171003/GeoLite2-Country-Locations-en.csv')
                .async('string')
                .then(data => {
                  emit(75)
                  Papa.parse(data, {
                    header: true,
                    complete: meta => {
                      emit(100)
                      let dict = {}
                      meta.data.forEach(geo => {
                        dict[geo.geoname_id] = geo.country_name
                      })
                      return {
                        ipv4: ipv4.data,
                        meta: _.sortBy(meta.data, 'country_name'),
                        dict: dict
                      }
                    }
                  })
                })
            }
          })
        })
    })
})

Solution

  • Using worker-loader and set a rule for worker files solved my issue.