Problema detectado
Al implementar la biblioteca @zip.js/zip.js (versión 2.7.72) en un entorno basado en webpack4 para la descompresión de archivos ZIP, se genera un error de sintaxis indicando "token inesperado import.meta.url". Esta excepción ocurre porque webpack4 no proporciona soporte nativo para la característica import.meta.url, la cual es una funcionalidad de módulos ECMAScript moderna. Previamente, se utilizaba jszip para este propósito, pero debido a sus restricciones de memoria al descomprimir en RAM, se optó por cambiar a @zip.js/zip.js, que ofrece capacidades de streaming.
Ejemplo de implementación
A continuación, se muestra un componente Vue.js que ilustra el uso básico de @zip.js/zip.js para procesar un archivo ZIP subido por el usuario.
<template>
<div>
<input type="file" ref="archivoEntrada" @change="manejarArchivoZip">
</div>
</template>
<script>
import { ZipReader, BlobReader, TextWriter } from '@zip.js/zip.js'
export default {
name: 'ComponenteZip',
data() {
return {
estado: 'listo'
}
},
methods: {
async manejarArchivoZip(evento) {
const archivo = evento.target.files[0]
if (!archivo) {
console.warn('No se seleccionó ningún archivo')
return
}
try {
console.log('Iniciando proceso de descompresión...')
const lector = new ZipReader(new BlobReader(archivo))
const listaEntradas = await lector.getEntries()
console.log(`Archivo ZIP contiene ${listaEntradas.length} elementos, tamaño total: ${archivo.size} bytes`)
for (const entrada of listaEntradas) {
if (entrada.directory) continue
console.log(`Procesando: ${entrada.filename}`)
try {
const datos = await entrada.getData(new TextWriter())
console.log('Contenido extraído:', datos)
} catch (falloLectura) {
console.error('Fallo al obtener datos de la entrada:', falloLectura)
}
}
await lector.close()
console.log('Proceso finalizado exitosamente')
} catch (errorGeneral) {
console.error('Error durante la descompresión:', errorGeneral)
}
}
}
}
</script>
Métodos de solución
Actualizar a webpack5
La solución más directa consiste en migrar el proyecto a webpack5, el cual maneja adecuadamente la sintaxis import.meta.url. Sin embargo, este cambio puede requerir ajustes significativos en la configuración y dependencias del proyecto.
Emplear una versión compatible de @zip.js/zip.js
Utilizar la versión 2.0.12 de la biblioteca, que no implementa import.meta.url. En este caso, es necesario gestionar el uso de web workers, ya que esta versión los emplea por defecto.
Para desactivar los web workers y evitar errores relacionados:
const lector = new ZipReader(new BlobReader(archivo), { useWebWorkers: false })
Alternativamente, se pueden configurar los scripts de los workers manualmente. Primero, descargar el archivo z-worker.js desde el repositorio oficial y colocarlo en el directorio público del proyecto. Luego, aplicar una de estas configuraciones:
Configuración global en el punto de entrada:
import { configure } from '@zip.js/zip.js'
configure({
workerScripts: {
deflate: ['/ruta/a/z-worker.js'],
inflate: ['/ruta/a/z-worker.js']
}
})
O especificar directamente en la instancia del lector:
const lector = new ZipReader(new BlobReader(archivo), {
workerScripts: {
deflate: ['/z-worker.js'],
inflate: ['/z-worker.js']
}
})
Personalizar webpack con un loader
Para proyectos que deben permanecer en webpack4, se puede crear un loader personalizado que transforme import.meta.url en una cadena vacía durante la compilación. En un proyecto Vue.js creado con Vue CLI 4.x, agregar la siguiente configuración en vue.config.js:
const path = require('path')
module.exports = {
chainWebpack: configuracion => {
configuracion.module
.rule('transformar-import-meta')
.enforce('pre')
.test(/\.js$/)
.include
.add(path.resolve(__dirname, 'node_modules/@zip.js/zip.js'))
.end()
.use('loader-import-meta')
.loader(path.resolve(__dirname, 'loaders/transformar-import-meta.js'))
}
}
Crear el archivo loaders/transformar-import-meta.js con el siguiente contenido:
module.exports = function(codigoFuente) {
return codigoFuente.replace(/import\.meta\.url/g, '""')
}