Executando verificação de segurança...
1

[ Ajuda ] [ RESOLVIDO ] Problema de hidratação no desenvolvimento usando Next.js, mas em produção funcionando normalmente - Problema persiste apenas no Firefox

Introdução:

Estou criando um mini-projeto para uso pessoal usando Next.js, Tailwindcss e armazenando dados simples no indexedDB.

Eu sempre utilizo o chrome para desenvolvimento, mas hoje decidi usar o meu navegador principal para uso pessoal, o firefox. Logo o problema apareceu.

Problema:

O problema é relacionado a hidratação, onde diz que o conteúdo gerado no cliente não corresponde ao do servidor. Porém, este problema apenas persiste no Firefox, no chrome não tem nenhuma reclamação sobre, nem mesmo um aviso sobre.

Outro ponto é que no firefox, o site crasha uma vez que eu volto a página e retorno novamente. Por exemplo, eu tenho um menu com algumas opções de seleções. Eu seleciono a rota que eu quero, de primeira funciona tudo perfeitamente. Se eu voltar para o menu e selecionar esta rota novamente, o site crasha na tela de loading, problema este que não ocorre no chrome, apenas no firefox.

O erro apresentado é que o objecStore não existe no indexedDB, o que é esquisito, pois a primeira leitura funciona perfeitamente. Se eu apagar o banco de dados do indexedDB, e recarregar a página, o database é criando normalmente, sem erros e ainda recupera os valores iniciantes normalmente.

Soluções que eu implementei, mas de nada adiantou:

Assim que o problema apareceu, pensei na compatibilidade entre navegadores, mas no MDN afirma que o indexedDB é amplamente suportando. E isto confirma pois em produção tudo funciona perfeitamente, tirando o crash.

Implementei um maior controle de transactions no indexedDB, porém o mesmo erro persiste.

Implementei um hook dedicado a inicialização do indexedDB, com um state que é definido como true quando o database for inicializado, mas mesmo assim persiste o erro. Código do hook abaixo:

'use client';
import { useEffect, useState } from "react";;

export interface databaseSignature {
    databaseName: string;
    version: number;
    storeName: string;
    indexName?: string;
    initialValues?: boolean;
}

let dbInstance: IDBDatabase | null = null;

export const initializeDB = ({
    databaseName,
    version,
    indexName,
    storeName
}: databaseSignature): Promise<IDBDatabase> => {

    if (dbInstance) return Promise.resolve(dbInstance);

    return new Promise((resolve, reject) => {
        const openDB = indexedDB.open(databaseName, version);

        openDB.onupgradeneeded = function HandleUpgrade(event) {
            const db = (event.target as IDBOpenDBRequest).result;

            if (!db.objectStoreNames.contains(storeName) && indexName) {
                const store = db.createObjectStore(storeName, {
                    keyPath: 'id',
                    autoIncrement: true,
                });
                store.createIndex(indexName, indexName, { unique: true });
            }
        };

        openDB.onsuccess = function HandleSuccess(event) {
            dbInstance = (event.target as IDBOpenDBRequest).result;
            resolve(dbInstance);
        };

        openDB.onerror = function HandleError(event) {
            console.error("Failed to open IndexedDB:", (event.target as IDBRequest).error);
            reject((event.target as IDBRequest).error);
        };
    });
};

const setInitialValues = async (db: IDBDatabase, storeName: string) => {
    const transaction = db.transaction(storeName, "readwrite");
    const store = transaction.objectStore(storeName);

    const data = [
        // aqui tem os valores iniciais...
    ];

    data.forEach((item) => store.add(item));

    return new Promise<void>((resolve, reject) => {
        transaction.oncomplete = () => resolve();
        transaction.onerror = () => reject(transaction.error);
    });
};


export const useIndexedDB = ({
    databaseName,
    version,
    initialValues,
    indexName,
    storeName,
}: databaseSignature) => {
    const [isReady, setIsReady] = useState(false);

    useEffect(() => {
        const setupDB = async () => {
            try {
                const db = await initializeDB({ databaseName, version, storeName, indexName });

                if (initialValues) {
                    const transaction = db.transaction(storeName, "readonly");
                    const store = transaction.objectStore(storeName);

                    const countRequest = store.count();
                    countRequest.onsuccess = async () => {
                        if (countRequest.result === 0) {
                            await setInitialValues(db, storeName);
                        }
                    };
                    countRequest.onerror = function(err) {
                        const error = (err.target as IDBRequest).result;
                        console.error(error);
                    };
                }

                setIsReady(true);
            } catch (error) {
                console.error("Error setting up IndexedDB:", error);
            }
        };
        setupDB();

    }, [databaseName, version, initialValues, indexName, storeName]);

    return { isReady }; 
};

Relacionado a hidratação, eu tentei de tudo, já revisei o código diversas vezes. Procurei issues relacionadas no Github, joguei no chat, analisei minuciosamente cada detalhe do código fornecido para a solução, mas era evidente que o código fornecido pelo o chat não era útil. Como em produção não gera erro de hidratação, e em desenvolvimento, ocorre apenas no Firefox, me leva a crer que é algo interno do Next.js.

Conclusão:

Isso já ocorreu com vocês? Não forneci mais código, mas eu acredito que não seria útil, afinal grande parte é apenas JSX e estados de controle de modal. Alguns useEffect para obter os valores iniciais.

solução:

A extensão CollorZilla estava, de alguma forma injetando scripts no site, causando o erro de hidratação. Ao desativar essa extensão, tudo voltou as normalidads. O problema só ocorreu no firefox porquê eu tinha instalado apenas no Firefox.

A Extensão DarkReander também provoca erro de hidratação.

Eu não entendi o motivo por trás do erro ocorrer apenas no desenvolvimento, mas eu acredito que seja porquê no desenvolvimento temos várias ferramentas como Eslint e uma tipagem poderosa do TypeScript, coisa que não existe do lado do cliente.

Carregando publicação patrocinada...
1

Problema de hidratação é o grande vilão quando usamos Next, Remix etc. Encontrar o real motivo por trás pode aer uma dir de cabeça e nao é raro acontecer.

1

tenho notado isso. O mais incrível é que surge apenas no desenvolvimento. Isso me faz questionar se não era melhor só ter feito com JavaScript puro mesmo.