Este estudo de caso explora como a Kiwix, uma organização sem fins lucrativos, usa a tecnologia de app da Web progressivo e a API File System Access para permitir que os usuários façam o download e armazenem grandes arquivos da Internet para uso off-line. Saiba mais sobre a implementação técnica do código que lida com o Origin Private File System (OPFS), um novo recurso do navegador no PWA Kiwix que aprimora o gerenciamento de arquivos, oferecendo acesso aprimorado aos arquivos sem solicitações de permissão. O artigo discute desafios e destaca possíveis desenvolvimentos futuros nesse novo sistema de arquivos.
Sobre o Kiwix
Mais de 30 anos após o nascimento da Web, um terço da população mundial ainda aguarda um acesso confiável à Internet, de acordo com a União Internacional de Telecomunicações. É aqui que a história termina? Claro que não. A equipe da Kiwix, uma organização sem fins lucrativos da Suíça, desenvolveu um ecossistema de apps e conteúdo de código aberto que visa disponibilizar conhecimento para pessoas com acesso limitado ou nenhum acesso à Internet. A ideia é que, se você não conseguir acessar a Internet com facilidade, alguém poderá fazer o download de recursos importantes para você, onde e quando a conectividade estiver disponível, e armazená-los localmente para uso off-line posterior. Muitos sites importantes, como a Wikipedia, o Project Gutenberg, o Stack Exchange ou até mesmo as palestras do TED, agora podem ser convertidos em arquivos altamente compactados, chamados de arquivos ZIM, e lidos em tempo real pelo navegador Kiwix.
Os arquivos ZIM usam a compactação Zstandard (ZSTD) altamente eficiente (as versões mais antigas usavam XZ), principalmente para armazenar HTML, JavaScript e CSS, enquanto as imagens geralmente são convertidas para o formato compactado WebP. Cada ZIM também inclui um URL e um índice de títulos. A compactação é fundamental, já que todo o conteúdo da Wikipedia em inglês (6, 4 milhões de artigos e imagens) é compactado para 97 GB após a conversão para o formato ZIM, o que parece muito até você perceber que a soma de todo o conhecimento humano agora cabe em um smartphone Android de nível intermediário. Muitos recursos menores também são oferecidos, incluindo versões temáticas da Wikipédia, como matemática, medicina etc.
O Kiwix oferece uma gama de apps nativos voltados para uso em computadores (Windows/Linux/macOS) e dispositivos móveis (iOS/Android). No entanto, este estudo de caso vai se concentrar no App Web Progressivo (PWA), que tem como objetivo ser uma solução universal e simples para qualquer dispositivo com um navegador moderno.
Vamos analisar os desafios apresentados no desenvolvimento de um app da Web universal que precisa oferecer acesso rápido a grandes arquivos de conteúdo totalmente off-line e algumas APIs JavaScript modernas, principalmente a API File System Access e o Origin Private File System, que oferecem soluções inovadoras e interessantes para esses desafios.
Um app da Web para uso off-line?
Os usuários do Kiwix são um grupo eclético com muitas necessidades diferentes, e o Kiwix tem pouco ou nenhum controle sobre os dispositivos e sistemas operacionais em que eles vão acessar o conteúdo. Alguns desses dispositivos podem ser lentos ou desatualizados, especialmente em áreas de baixa renda do mundo. Embora o Kiwix tente abranger o maior número possível de casos de uso, a organização também percebeu que poderia alcançar ainda mais usuários usando o software mais universal em qualquer dispositivo: o navegador da Web. Assim, inspirados pela Lei de Atwood, que afirma que qualquer aplicativo que possa ser escrito em JavaScript será escrito em JavaScript, alguns desenvolvedores do Kiwix, há cerca de 10 anos, começaram a portar o software do Kiwix de C++ para JavaScript.
A primeira versão dessa porta, chamada Kiwix HTML5, era para o Firefox OS, que já não existe mais, e para extensões de navegador. O núcleo era (e é) um mecanismo de descompressão C++ (XZ e ZSTD) compilado para a linguagem JavaScript intermediária do ASM.js e, mais tarde, Wasm ou WebAssembly, usando o compilador Emscripten. Mais tarde, renomeadas como Kiwix JS, as extensões de navegador ainda estão sendo desenvolvidas.
Entre no Progressive Web App (PWA). Percebendo o potencial dessa tecnologia, os desenvolvedores do Kiwix criaram uma versão PWA dedicada do Kiwix JS e começaram a adicionar integrações de SO que permitiam que o app oferecesse recursos semelhantes aos nativos, principalmente nas áreas de uso off-line, instalação, manuseio de arquivos e acesso ao sistema de arquivos.
Os PWAs com foco na conexão off-line são extremamente leves e, por isso, são perfeitos para contextos em que a Internet móvel é intermitente ou cara. A tecnologia por trás disso é a API Service Worker e a API Cache relacionada, usada por todos os apps baseados no Kiwix JS. Essas APIs permitem que os apps atuem como um servidor, interceptando solicitações de busca do documento ou artigo principal que está sendo visualizado e redirecionando-as para o back-end (JS) para extrair e criar uma resposta do arquivo ZIM.
Armazenamento em todos os lugares
Considerando o grande tamanho dos arquivos ZIM, o armazenamento e o acesso a eles, especialmente em dispositivos móveis, provavelmente é a maior dor de cabeça dos desenvolvedores do Kiwix. Muitos usuários finais do Kiwix fazem o download de conteúdo no app, quando a Internet está disponível, para uso off-line posterior. Outros usuários fazem o download em um PC usando um torrent e depois transferem para um dispositivo móvel ou tablet. Alguns trocam conteúdo em pen drives ou discos rígidos portáteis em áreas com Internet móvel instável ou cara. Todas essas maneiras de acessar conteúdo de locais arbitrários acessíveis ao usuário precisam ter suporte ao Kiwix JS e ao Kiwix PWA.
O que inicialmente permitiu que o Kiwix JS lesse arquivos enormes, de
centenas de GB
(um
dos nossos arquivos ZIM tem 166 GB!), mesmo em dispositivos com pouca memória, é a
API File. Essa API
tem suporte universal em qualquer navegador, até mesmo
muito antigos, e
funciona como substituto universal quando as APIs mais recentes não têm suporte. É tão
fácil quanto definir um elemento input
no HTML, no caso do Kiwix:
<input
type="file"
accept="application/octet-stream,.zim,.zimaa,.zimab,.zimac, ..."
value="Select folder with ZIM files"
id="archiveFilesLegacy"
multiple
/>
Depois de selecionado, o elemento de entrada armazena os objetos de arquivo, que são essencialmente metadados que fazem referência aos dados subjacentes no armazenamento. Tecnicamente, o back-end orientado a objetos do Kiwix, escrito em JavaScript puro do lado do cliente, lê pequenas fatias do grande arquivo conforme necessário. Se essas fatias precisarem ser descompactadas, o back-end as transmitirá ao descompressor Wasm, recebendo mais fatias, se solicitado, até que um blob completo seja descompactado (geralmente um artigo ou um recurso). Isso significa que o arquivo grande nunca precisa ser lido inteiramente na memória.
Por ser universal, a API File tem uma desvantagem que faz com que os apps Kiwix JS pareçam desajeitados e antiquados em comparação com os apps nativos: ela exige que o usuário selecione arquivos usando um seletor de arquivos ou arrastar e soltar um arquivo no app, sempre que o app é iniciado, porque com essa API, não há como manter as permissões de acesso de uma sessão para a próxima.
Para reduzir essa experiência ruim, como muitos desenvolvedores, os desenvolvedores do Kiwix JS inicialmente seguiram a rota do Electron. O ElectronJS é um framework incrível que oferece recursos poderosos, incluindo acesso total ao sistema de arquivos usando APIs do Node. No entanto, ele tem algumas desvantagens bem conhecidas:
- Ele só é executado em sistemas operacionais para computadores.
- É grande e pesado (70 MB a 100 MB).
O tamanho dos apps do Electron, devido ao fato de que uma cópia completa do Chromium é incluída em cada app, é muito menor do que apenas 5,1 MB para o PWA minimizado e agrupado.
Então, havia uma maneira de o Kiwix melhorar a situação para os usuários do PWA?
API File System Access para o resgate
Por volta de 2019, o Kiwix soube de uma API emergente que estava passando por um teste de origem no Chrome 78, chamada de API Native File System. Ele prometia a capacidade de receber um identificador de arquivo para um arquivo ou uma pasta e armazená-lo em um banco de dados IndexedDB. É importante ressaltar que esse identificador persiste entre as sessões do app. Assim, o usuário não precisa escolher o arquivo ou a pasta novamente ao iniciar o app novamente (embora ele precise responder a uma solicitação de permissão rápida). Quando chegou à produção, foi renomeada como API File System Access, e as partes principais foram padronizadas pelo WHATWG como a API File System (FSA).
Como funciona a parte File System Access da API? Alguns pontos importantes:
- É uma API assíncrona (exceto para funções especializadas em Web Workers).
- Os seletores de arquivo ou diretório precisam ser iniciados programaticamente capturando um gesto do usuário (clique ou toque em um elemento da interface).
- Para que o usuário conceda permissão novamente para acessar um arquivo escolhido anteriormente (em uma nova sessão), um gesto do usuário também é necessário. Na verdade, o navegador se recusa a mostrar a solicitação de permissão se não for iniciado por um gesto do usuário.
O código é relativamente simples, exceto pelo uso da API IndexedDB para armazenar identificadores de arquivos e diretórios. A boa notícia é que há algumas bibliotecas que fazem grande parte do trabalho pesado para você, como browser-fs-access. No Kiwix JS, decidimos trabalhar diretamente com as APIs, que são muito bem documentadas.
Como abrir seletores de arquivos e diretórios
A abertura de um seletor de arquivos é semelhante a esta (aqui usando promessas, mas se
você preferir async/await
sugar, consulte o
tutorial do Chrome para desenvolvedores):
return window
.showOpenFilePicker({ multiple: false })
.then(function (fileHandles) {
return processFileHandle(fileHandles[0]);
})
.catch(function (err) {
// This is normal if app is launching
console.warn(
'User cancelled, or cannot access fs without user gesture',
err,
);
});
Para simplificar, esse código processa apenas o primeiro arquivo
selecionado e não permite selecionar mais de um. Se você quiser permitir a seleção
de vários arquivos com { multiple: true }
, basta agrupar todas as promessas que
processam cada identificador em uma instrução Promise.all().then(...)
, por exemplo:
let promisesForFiles = fileHandles.map(function (fileHandle) {
return processFileHandle(fileHandle);
});
return Promise.all(promisesForFiles).then(function (arrayOfFiles) {
// Do something with the files array
console.log(arrayOfFiles);
}).catch(function (err) {
// Handle any errors that occurred during processing
console.error('Error processing file handles!', err);
)};
No entanto, é melhor escolher vários arquivos pedindo ao usuário que
selecione o diretório que contém esses arquivos, em vez de cada um deles,
principalmente porque os usuários do Kiwix tendem a organizar todos os arquivos ZIM no
mesmo diretório. O código para iniciar o seletor de diretório é quase o
mesmo que o acima, exceto pelo uso de
window.showDirectoryPicker.then(function (dirHandle) { … });
.
Processar o identificador de arquivo ou diretório
Depois de ter o identificador, é necessário processá-lo. Assim, a função
processFileHandle
pode ficar assim:
function processFileHandle(fileHandle) {
// Serialize fileHandle to indexedDB
serializeFSHandletoIdxDB('pickedFSHandle', fileHandle, function (val) {
console.debug('IndexedDB responded with ' + val);
});
return fileHandle.getFile().then(function (file) {
// Do something with the file
return file;
});
}
Você precisa fornecer a função para armazenar o identificador de arquivo. Não há
métodos de conveniência para isso, a menos que você use uma biblioteca de abstração. A implementação
do Kiwix pode ser vista no arquivo
cache.js
,
mas pode ser simplificada consideravelmente se for usada apenas para armazenar e recuperar
um identificador de arquivo ou pasta.
O processamento de diretórios é um pouco mais complicado, porque você precisa iterar
as entradas no diretório escolhido com entries.next()
assíncrono para encontrar
os arquivos ou tipos de arquivo que você quer. Há várias maneiras de fazer isso, mas
este é o código usado no Kiwix PWA, em resumo:
let iterableEntryList = dirHandle.entries();
return iterateAsyncDirEntries(iterableEntryList, []).then(function (entryList) {
// Do something with the entry list
return entryList;
});
/**
* Iterates FileSystemDirectoryHandle iterator and adds entries to an array
* @param {Iterator} entries An asynchronous iterator of entries
* @param {Array} archives An array to which to add the entries (may be empty)
* @return {Promise<Array>} A Promise for an array of entries in the directory
*/
function iterateAsyncDirEntries(entries, archives) {
return entries
.next()
.then(function (result) {
if (!result.done) {
let entry = result.value[1];
// Filter for the files you want
if (/\.zim(\w\w)?$/i.test(entry.name)) {
archives.push(entry);
}
return iterateAsyncDirEntryArray(entries, archives);
} else {
// We've processed all the entries
if (!archives.length) {
console.warn('No archives found in the picked directory!');
}
return archives;
}
})
.catch(function (err) {
console.error('There was an error processing the directory!', err);
});
}
Para cada entrada no entryList
, você precisará acessar o arquivo
com entry.getFile().then(function (file) { … })
quando precisar usá-lo ou
o equivalente usando const file = await entry.getFile()
em um
async function
.
Podemos ir mais longe?
A exigência de que o usuário conceda permissão iniciada com um gesto do usuário em lançamentos subsequentes do app adiciona uma pequena quantidade de atrito à (re)abertura de arquivos e pastas, mas ainda é muito mais fluido do que ser forçado a escolher um arquivo novamente. Os desenvolvedores do Chromium estão finalizando o código que permitiria permissões persistentes para PWAs instalados. Isso é algo que muitos desenvolvedores de PWA têm solicitado e é muito esperado.
Mas e se não precisarmos esperar?! Recentemente, os desenvolvedores do Kiwix descobriram que é
possível eliminar todos os avisos de permissão usando um novo recurso
da API File Access que é compatível com os navegadores Chromium e Firefox (e parcialmente compatível com o Safari, mas ainda
falta FileSystemWritableFileStream
).
Esse novo recurso é o Origin Private File System.
Como usar o sistema de arquivos particular da origem: a versão totalmente nativa
O Origin Private File System (OPFS, na sigla em inglês) ainda é um recurso experimental no PWA do Kiwix, mas a equipe está muito animada para incentivar os usuários a testá-lo, porque ele preenche a lacuna entre apps nativos e apps da Web. Estes são os principais benefícios:
- Os arquivos no OPFS podem ser acessados sem solicitações de permissão, mesmo na inicialização. Os usuários podem continuar lendo um artigo e navegando em um arquivo de onde pararam em uma sessão anterior, sem nenhuma dificuldade.
- Ele oferece acesso altamente otimizado aos arquivos armazenados nele: no Android, notamos melhorias de velocidade entre cinco e dez vezes mais rápidas.
O acesso padrão a arquivos no Android usando a API File é muito lento, especialmente (como costuma ser o caso dos usuários do Kiwix) se grandes arquivos forem armazenados em um cartão microSD em vez de no armazenamento do dispositivo. Tudo isso muda com essa nova API. Embora a maioria dos usuários não consiga armazenar um arquivo de 97 GB no OPFS, que consome o armazenamento do dispositivo, e não do cartão microSD, ele é perfeito para armazenar arquivos de tamanho pequeno a médio. Você quer a enciclopédia médica mais completa do WikiProject Medicine? Sem problemas. Com 1,7 GB, cabe facilmente no OPFS. Dica: procure other → mdwiki_en_all_maxi na biblioteca no app.
Como o OPFS funciona
O OPFS é um sistema de arquivos fornecido pelo navegador, separado para cada origem, que pode ser considerado semelhante ao armazenamento no escopo do app no Android. Os arquivos podem ser importados para o OPFS do sistema de arquivos visível para o usuário ou podem ser transferidos por download diretamente para ele. A API também permite criar arquivos no OPFS. Quando estão no OPFS, eles são isolados do restante do dispositivo. Em computadores com navegadores baseados no Chromium, também é possível exportar arquivos do OPFS para o sistema de arquivos visível para o usuário.
Para usar o OPFS, a primeira etapa é solicitar acesso a ele usando
navigator.storage.getDirectory()
. Se você preferir ver o código usando
await
, leia
O sistema de arquivos particular do Origin:
return navigator.storage
.getDirectory()
.then(function (handle) {
return processDirHandle(handle);
})
.catch(function (err) {
console.warn('Unable to get the OPFS directory entry', err);
});
O handle que você recebe é do mesmo tipo de
FileSystemDirectoryHandle
que você recebe do window.showDirectoryPicker()
mencionado acima, o que significa que você pode reutilizar o código que lida com isso.
Felizmente, não é necessário armazenar isso em indexedDB
. Basta receber quando
precisar. Digamos que você já tenha alguns arquivos no OPFS e queira
usá-los. Usando a função iterateAsyncDirEntries()
mostrada anteriormente,
você pode fazer algo como:
return navigator.storage.getDirectory().then(function (dirHandle) {
let entries = dirHandle.entries();
return iterateAsyncDirEntries(entries, [])
.then(function (archiveList) {
return archiveList;
})
.catch(function (err) {
console.error('Unable to iterate OPFS entries', err);
});
});
Não se esqueça de que você ainda precisa usar getFile()
em qualquer entrada que queira trabalhar
com a matriz archiveList
.
Como importar arquivos para o OPFS
Como você coloca arquivos no OPFS? Mas não é bem assim. Primeiro, você precisa estimar a quantidade de armazenamento com que vai trabalhar e garantir que os usuários não tentem colocar um arquivo de 97 GB se ele não couber.
É fácil saber a cota estimada:
navigator.storage.estimate().then(function (estimate) { … });
. Um pouco mais difícil
é descobrir como mostrar isso ao usuário. No app Kiwix, optamos por um
pequeno painel no app, ao lado da caixa de seleção, que permite que os usuários testem
o OPFS:
O painel é preenchido usando
estimate.quota
e
estimate.usage
,
por exemplo:
let OPFSQuota; // Global variable, so we don't have to keep checking it
return navigator.storage.estimate().then(function (estimate) {
const percent = ((estimate.usage / estimate.quota) * 100).toFixed(2);
OPFSQuota = estimate.quota - estimate.usage;
document.getElementById('OPFSQuota').innerHTML =
'<b>OPFS storage quota:</b><br />Used: <b>' +
percent +
'%</b>; ' +
'Remaining: <b>' +
(OPFSQuota / 1024 / 1024 / 1024).toFixed(2) +
' GB</b>';
});
Como você pode ver, também há um botão que permite que os usuários adicionem arquivos ao OPFS
no sistema de arquivos visível para o usuário. A boa notícia é que você pode usar a
API File para receber o
objeto de arquivo necessário que será importado. Na verdade, é
importante não usar window.showOpenFilePicker()
porque esse método não é
compatível com o Firefox, enquanto o OPFS é.
O botão Add file(s) visível na captura de tela acima não é um seletor de arquivos
legado, mas click()
um seletor legado oculto
(elemento <input type="file" multiple … />
) quando clicado. O
app captura o evento change
da entrada de arquivo oculta, verifica o
tamanho dos arquivos e os rejeita se eles forem muito grandes para a cota. Se tudo estiver
bem, pergunte ao usuário se ele quer adicionar:
archiveFilesLegacy.addEventListener('change', function (files) {
const filesArray = Array.from(files.target.files);
// Abort if user didn't select any files
if (filesArray.length === 0) return;
// Calculate the size of the picked files
let filesSize = 0;
filesArray.forEach(function (file) {
filesSize += file.size;
});
// Check the size of the files does not exceed the quota
if (filesSize > OPFSQuota) {
// Oh no, files are too big! Tell user...
console.log('Files would exceed the OPFS quota!');
} else {
// Ask user if they're sure... if user said yes...
return importOPFSEntries(filesArray)
.then(function () {
// Tell user we successfully imported the archives
})
.catch(function (err) {
// Tell user there was an error (error catching is important!)
});
}
});
Como em alguns sistemas operacionais, como o Android, importar arquivos não é a operação mais rápida, o Kiwix também mostra um banner e um pequeno ícone giratório enquanto os arquivos são importados. A equipe não descobriu como adicionar um indicador de progresso para essa operação. Se você descobrir, responda em um cartão-postal.
Como o Kiwix implementou a função importOPFSEntries()
? Isso envolve
usar o método fileHandle.createWriteable()
, que permite que cada
arquivo seja transmitido para o OPFS. Todo o trabalho pesado é feito pelo
navegador. O Kiwix está usando promessas aqui por motivos relacionados ao nosso repositório de
código legado, mas é preciso dizer que, neste caso, await
produz uma sintaxe
mais simples e evita o efeito pirâmide da morte.
function importOPFSEntries(files) {
// Get a handle on the OPFS directory
return navigator.storage
.getDirectory()
.then(function (dir) {
// Collect the promises for each file that we want to write
let promises = files.map(function (file) {
// Create the file and get a writeable handle on it
return dir
.getFileHandle(file.name, { create: true })
.then(function (fileHandle) {
// Get a writer for the file
return fileHandle.createWritable().then(function (writer) {
// Show a banner / spinner, then write the file
return writer
.write(file)
.then(function () {
// Finished with this writer
return writer.close();
})
.catch(function (err) {
console.error('There was an error writing to the OPFS!', err);
});
});
})
.catch(function (err) {
console.error('Unable to get file handle from OPFS!', err);
});
});
// Return a promise that resolves when all the files have been written
return Promise.all(promises);
})
.catch(function (err) {
console.error('Unable to get a handle on the OPFS directory!', err);
});
}
Fazer o download de um fluxo de arquivos diretamente no OPFS
Uma variação disso é a capacidade de transmitir um arquivo da Internet diretamente
para o OPFS ou para qualquer diretório para o qual você tenha um identificador de diretório (ou seja, diretórios escolhidos com window.showDirectoryPicker()
). Ele usa os mesmos
princípios do código acima, mas constrói um Response
que consiste em um
ReadableStream
e um controlador que enfileira os bytes lidos do arquivo
remoto. O Response.body
resultante é então
encaminhado para o gravador do novo arquivo
dentro do OPFS.
Nesse caso, o Kiwix pode contar os bytes que passam pelo
ReadableStream
e, assim, fornecer um indicador de progresso ao usuário e também alertá-lo
para que não saia do app durante o download. O código é um pouco complicado
para mostrar aqui, mas, como nosso app é um app FOSS, você pode
consultar a origem
se tiver interesse em fazer algo semelhante. A interface do Kiwix tem esta aparência.
Os diferentes valores de progresso mostrados abaixo são porque ele só atualiza o
banner quando a porcentagem muda, mas atualiza o painel Download progress
com mais frequência:
Como o download pode ser uma operação longa, o Kiwix permite que os usuários usem o app livremente durante a operação, mas garante que o banner seja sempre exibido para que os usuários não fechem o app até que a operação de download seja concluída.
Como implementar um minigerenciador de arquivos no app
Nesse ponto, os desenvolvedores do PWA do Kiwix perceberam que não bastava adicionar arquivos ao OPFS. O app também precisava oferecer aos usuários uma maneira de excluir arquivos que não são mais necessários nessa área de armazenamento e, idealmente, exportar arquivos bloqueados no OPFS de volta para o sistema de arquivos visível para o usuário. Na prática, foi necessário implementar um mini sistema de gerenciamento de arquivos no app.
Um breve comentário sobre a maravilhosa extensão OPFS Explorer para Chrome, que também funciona no Edge. Ele adiciona uma guia nas ferramentas para desenvolvedores que permite ver exatamente o que está no OPFS e também excluir arquivos maliciosos ou com falhas. Foi muito útil para verificar se o código estava funcionando, monitorar o comportamento dos downloads e, de modo geral, limpar nossos experimentos de desenvolvimento.
A export depende da capacidade de receber um identificador de arquivo em um arquivo
ou diretório escolhido em que o Kiwix vai salvar o arquivo exportado. Portanto, isso só
funciona em contextos em que é possível usar o método window.showSaveFilePicker()
. Se
os arquivos do Kiwix fossem menores que vários GB, poderíamos construir um blob
na memória, atribuir um URL a ele e fazer o download para o sistema de arquivos visível para o usuário.
Infelizmente, isso não é possível com arquivos tão grandes. Se houver suporte,
a exportação é bastante simples: praticamente a mesma coisa, ao contrário, como salvar um
arquivo no OPFS (pegar um identificador do arquivo a ser salvo, pedir ao usuário para escolher um
local para salvar com window.showSaveFilePicker()
e, em seguida, usar
createWriteable()
no saveHandle
). Você pode
ver o código
no repositório.
A exclusão de arquivos é aceita por todos os navegadores e pode ser feita com um
dirHandle.removeEntry('filename')
simples. No caso do Kiwix, preferimos
iterar as entradas do OPFS como fizemos acima para verificar se o
arquivo selecionado existe primeiro e pedir confirmação, mas isso pode não ser
necessário para todos. Novamente, você pode
examinar nosso código
se tiver interesse.
Decidimos não sobrecarregar a interface do Kiwix com botões que oferecem essas opções, e, em vez disso, colocar pequenos ícones diretamente abaixo da lista de arquivos. Tocar em um desses ícones muda a cor da lista de arquivos, como uma dica visual para o usuário sobre o que ele vai fazer. O usuário clica ou toca em um dos arquivos, e a operação correspondente (exportar ou excluir) é realizada após a confirmação.
Por fim, confira uma demonstração de screencast de todos os recursos de gerenciamento de arquivos discutidos acima: adicionar um arquivo ao OPFS, fazer o download dele diretamente, excluir um arquivo e exportar para o sistema de arquivos visível para o usuário.
O trabalho de um desenvolvedor nunca acaba
O OPFS é uma grande inovação para desenvolvedores de PWAs, oferecendo recursos de gerenciamento de arquivos muito eficientes que ajudam a fechar a lacuna entre apps nativos e da Web. Mas os desenvolvedores são um grupo infeliz. Eles nunca ficam satisfeitos. O OPFS é quase perfeito, mas não totalmente… É ótimo que os principais recursos funcionem nos navegadores Chromium e Firefox e que sejam implementados no Android e no computador. Esperamos que o conjunto completo de recursos também seja implementado no Safari e no iOS em breve. Os seguintes problemas ainda existem:
- Atualmente, o Firefox coloca um limite de 10 GB na cota do OPFS, não importa quanto espaço em disco exista. Embora para a maioria dos autores de PWA isso possa ser amplo, para o Kiwix, isso é bastante restritivo. Felizmente, os navegadores Chromium são muito mais generosos.
- No momento, não é possível exportar arquivos grandes do OPFS para o
sistema de arquivos visível para o usuário em navegadores para dispositivos móveis ou no Firefox para computador, porque
window.showSaveFilePicker()
não está implementado. Nesses navegadores, os arquivos grandes são efetivamente armazenados no OPFS. Isso vai contra o espírito do Kiwix de acesso aberto ao conteúdo e a capacidade de compartilhar arquivos entre usuários, especialmente em áreas com conectividade de Internet intermitente ou cara. - O usuário não pode controlar qual armazenamento o sistema de arquivos virtual do OPFS vai consumir. Isso é particularmente problemático em dispositivos móveis, em que os usuários podem ter grandes quantidades de espaço em um cartão microSD, mas uma quantidade muito pequena no armazenamento do dispositivo.
No geral, essas são pequenas falhas em um grande avanço para o acesso a arquivos em PWAs. A equipe da PWA do Kiwix é muito grata aos desenvolvedores e defensores do Chromium que propuseram e projetaram a API de acesso ao sistema de arquivos e pelo trabalho árduo de alcançar um consenso entre os fornecedores de navegadores sobre a importância do sistema de arquivos particular de origem. Para a PWA do Kiwix JS, ela resolveu muitos dos problemas de UX que prejudicaram o app no passado e nos ajuda na nossa busca para melhorar a acessibilidade do conteúdo do Kiwix para todos. Teste a PWA do Kiwix e diga aos desenvolvedores o que você acha.
Para conferir alguns recursos excelentes sobre as capacidades de PWA, acesse estes sites:
- Project Fugu API showcase (link em inglês): uma coleção de apps da Web que mostram recursos que preenchem a lacuna entre apps nativos e PWAs.
- O que as PWAs podem fazer hoje: uma demonstração do que é possível fazer com PWAs.