Usando empacotadores de módulo com Firebase

Os empacotadores de módulos JavaScript podem fazer muitas coisas, mas um de seus recursos mais úteis é a capacidade de adicionar e usar bibliotecas externas em sua base de código. Os empacotadores de módulos leem os caminhos de importação no seu código e combinam (agregam) o código específico do aplicativo com o código da biblioteca importada.

A partir da versão 9 e posteriores, a API modular JavaScript do Firebase é otimizada para funcionar com os recursos de otimização de empacotadores de módulos para reduzir a quantidade de código do Firebase incluído na sua compilação final.

import { initializeApp } from 'firebase/app';
import { getAuth, onAuthStateChanged, getRedirectResult } from 'firebase/auth';

const firebaseApp = initializeApp({ /* config */ });
const auth = getAuth(firebaseApp);
onAuthStateChanged(auth, user => { /* check status */ });

/**
 * getRedirectResult is unused and should not be included in the code base.
 * In addition, there are many other functions within firebase/auth that are
 * not imported and therefore should not be included as well.
 */

Este processo de eliminação de código não utilizado de uma biblioteca é conhecido como trepidação de árvore. Seria extremamente demorado e propenso a erros remover manualmente esse código, mas os empacotadores de módulos podem automatizar essa remoção.

Existem muitos empacotadores de módulos de alta qualidade no ecossistema JavaScript. Este guia se concentra em abordar o uso do Firebase com webpack , Rollup e esbuild .

iniciar

Este guia requer que você tenha o npm instalado em seu ambiente de desenvolvimento. npm é usado para instalar e gerenciar dependências (bibliotecas). Para instalar o npm, instale o Node.js , que inclui o npm automaticamente.

A maioria dos desenvolvedores está configurada corretamente depois de instalar o Node.js. No entanto, existem problemas comuns que muitos desenvolvedores enfrentam ao configurar seu ambiente. Se você encontrar algum erro, certifique-se de que seu ambiente tenha a CLI npm e que você tenha as permissões adequadas configuradas para não precisar instalar pacotes como administrador com o comando sudo .

package.json e instalação do Firebase

Depois de instalar o npm, você precisará criar um arquivo package.json na raiz do seu projeto local. Gere este arquivo com o seguinte comando npm:

npm init

Isso o levará através de um assistente para fornecer as informações necessárias. Depois que o arquivo for criado, ele será semelhante ao seguinte:

{
  "name": "your-package-name",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "dependencies": {

  }
}

Este arquivo é responsável por muitas coisas diferentes. Este é um arquivo importante com o qual você deve se familiarizar se quiser aprender mais sobre agrupamento de módulos e construção de código JavaScript em geral. A peça importante deste guia é o objeto "dependencies" . Este objeto conterá um par de valores-chave da biblioteca que você instalou e a versão que ela está usando.

A adição de dependências é feita por meio do comando npm install ou npm i .

npm i firebase

Quando você executa npm i firebase , o processo de instalação atualizará package.json para listar o Firebase como uma dependência:

  "dependencies": {
    "firebase": "^9.0.0"
  },

A chave é o nome da biblioteca e o valor é a versão a ser usada. O valor da versão é flexível e pode aceitar um intervalo de valores. Isso é conhecido como versionamento semântico ou semver. Para saber mais sobre semver, consulte o guia do npm sobre versionamento semântico .

Pastas de origem versus compilação

O código que você escreve é ​​lido e processado por um empacotador de módulo e então gerado como um novo arquivo ou conjunto de arquivos. É importante separar esses dois tipos de arquivos. O código que os empacotadores de módulos leem e processam é conhecido como código "fonte". Os arquivos que eles geram são conhecidos como código construído ou "dist" (distribuição).

Uma configuração comum em bases de código é armazenar o código-fonte em uma pasta chamada src e o código construído em uma pasta chamada dist .

- src
 |_ index.js
 |_ animations.js
 |_ datalist.js


- dist
 |_ bundle.js

Na estrutura de arquivo de exemplo acima, considere que index.js importa animations.js e datalist.js . Quando um empacotador de módulo processa o código-fonte, ele produzirá o arquivo bundle.js na pasta dist . O bundle.js é uma combinação dos arquivos na pasta src e também de quaisquer bibliotecas importadas.

Se você estiver usando sistemas de controle de origem como o Git, é comum ignorar a pasta dist ao armazenar este código no repositório principal.

Pontos de entrada

Todos os empacotadores de módulos têm um conceito de ponto de entrada. Você pode pensar no seu aplicativo como uma árvore de arquivos. Um arquivo importa código de outro e assim por diante. Isso significa que um arquivo será a raiz da árvore. Este arquivo é conhecido como ponto de entrada.

Vamos revisitar o exemplo anterior de estrutura de arquivos.

- src
 |_ index.js
 |_ animations.js
 |_ datalist.js


- dist
 |_ bundle.js
// src/index.js
import { animate } from './animations';
import { createList } from './datalist';

// This is not real code, but for example purposes only
const theList = createList('users/123/tasks');
theList.addEventListener('loaded', event => {
  animate(theList);
});

O arquivo src/index.js é considerado o ponto de entrada porque inicia a importação de todo o código necessário para a aplicação. Este arquivo de ponto de entrada é usado pelos empacotadores de módulos para iniciar o processo de empacotamento.

Usando Firebase com webpack

Não há configuração específica necessária para aplicativos Firebase e webpack. Esta seção cobre uma configuração geral do webpack .

A primeira etapa é instalar o webpack do npm como uma dependência de desenvolvimento.

npm i webpack webpack-cli -D

Crie um arquivo na raiz do seu projeto local chamado webpack.config.js e adicione o código a seguir.

const path = require('path');

module.exports = {
  // The entry point file described above
  entry: './src/index.js',
  // The location of the build folder described above
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: 'bundle.js'
  },
  // Optional and for development only. This provides the ability to
  // map the built code back to the original source format when debugging.
  devtool: 'eval-source-map',
};

Em seguida, certifique-se de ter o Firebase instalado como uma dependência.

npm i firebase

Em seguida, inicialize o Firebase em sua base de código. O código a seguir importa e inicializa o Firebase em um arquivo de ponto de entrada e usa o Firestore Lite para carregar um documento de “cidade”.

// src/index.js
import { initializeApp } from 'firebase/app';
import { getFirestore, doc, getDoc } from 'firebase/firestore/lite';

const firebaseApp = initializeApp({ /* config */ });
const db = getFirestore(firebaseApp);

async function loadCity(name) {
  const cityDoc = doc(db, `cities/${name}`);
  const snapshot = await getDoc(cityDoc);
  return {
    id: snapshot.id,
    ...snapshot.data(),
  };
}

A próxima etapa é adicionar um script npm para executar a construção do webpack. Abra o arquivo package.json e adicione o seguinte par de valores-chave ao objeto "scripts" .

  "scripts": {
    "build": "webpack --mode=development"
  },

Para executar o webpack e gerar a pasta de construção, execute o seguinte comando.

npm run build

Finalmente, verifique a pasta dist build. Ele deve conter um arquivo chamado bundle.js que contém o aplicativo incluído e o código de dependência.

Para obter mais informações sobre como otimizar a construção do seu webpack para produção, consulte a documentação oficial sobre a configuração "mode" .

Usando Firebase com Rollup

Não há configuração específica necessária para aplicativos Firebase e Rollup. Esta seção aborda uma configuração geral de Rollup.

O primeiro passo é instalar o Rollup e um plugin usado para mapear importações para dependências instaladas com npm.

npm i rollup @rollup/plugin-node-resolve -D

Crie um arquivo na raiz do seu projeto local chamado rollup.config.js e adicione o código a seguir.

import { nodeResolve } from '@rollup/plugin-node-resolve';

export default {
  // the entry point file described above
  input: 'src/index.js',
  // the output for the build folder described above
  output: {
    file: 'dist/bundle.js',
    // Optional and for development only. This provides the ability to
    // map the built code back to the original source format when debugging.
    sourcemap: 'inline',
    // Configure Rollup to convert your module code to a scoped function
    // that "immediate invokes". See the Rollup documentation for more
    // information: https://rollupjs.org/guide/en/#outputformat
    format: 'iife'
  },
  // Add the plugin to map import paths to dependencies
  // installed with npm
  plugins: [nodeResolve()]
};

Em seguida, inicialize o Firebase em sua base de código. O código a seguir importa e inicializa o Firebase em um arquivo de ponto de entrada e usa o Firestore Lite para carregar um documento de “cidade”.

// src/index.js
import { initializeApp } from 'firebase/app';
import { getFirestore, doc, getDoc } from 'firebase/firestore/lite';

const firebaseApp = initializeApp({ /* config */ });
const db = getFirestore(firebaseApp);

async function loadCity(name) {
  const cityDoc = doc(db, `cities/${name}`);
  const snapshot = await getDoc(cityDoc);
  return {
    id: snapshot.id,
    ...snapshot.data(),
  };
}

A próxima etapa é adicionar um script npm para executar a compilação rollup. Abra o arquivo package.json e adicione o seguinte par de valores-chave ao objeto "scripts" .

  "scripts": {
    "build": "rollup -c rollup.config.js"
  },

Para executar o rollup e gerar a pasta de compilação, execute o seguinte comando.

npm run build

Finalmente, verifique a pasta dist build. Ele deve conter um arquivo chamado bundle.js que contém o aplicativo incluído e o código de dependência.

Para obter mais informações sobre como otimizar seu build Rollup para produção, consulte a documentação oficial sobre plug-ins para builds de produção .

Usando Firebase com esbuild

Não há configuração específica necessária para aplicativos Firebase e esbuild. Esta seção cobre uma configuração geral do esbuild.

O primeiro passo é instalar o esbuild como uma dependência de desenvolvimento.

npm i esbuild -D

Crie um arquivo na raiz do seu projeto local chamado esbuild.config.js e adicione o código a seguir.

require('esbuild').build({
  // the entry point file described above
  entryPoints: ['src/index.js'],
  // the build folder location described above
  outfile: 'dist/bundle.js',
  bundle: true,
  // Replace with the browser versions you need to target
  target: ['chrome60', 'firefox60', 'safari11', 'edge20'],
  // Optional and for development only. This provides the ability to
  // map the built code back to the original source format when debugging.
  sourcemap: 'inline',
}).catch(() => process.exit(1))

Em seguida, inicialize o Firebase em sua base de código. O código a seguir importa e inicializa o Firebase em um arquivo de ponto de entrada e usa o Firestore Lite para carregar um documento de “cidade”.

// src/index.js
import { initializeApp } from 'firebase/app';
import { getFirestore, doc, getDoc } from 'firebase/firestore/lite';

const firebaseApp = initializeApp({ /* config */ });
const db = getFirestore(firebaseApp);

async function loadCity(name) {
  const cityDoc = doc(db, `cities/${name}`);
  const snapshot = await getDoc(cityDoc);
  return {
    id: snapshot.id,
    ...snapshot.data(),
  };
}

A próxima etapa é adicionar um script npm para executar o esbuild. Abra o arquivo package.json e adicione o seguinte par de valores-chave ao objeto "scripts" .

  "scripts": {
    "build": "node ./esbuild.config.js"
  },

Finalmente, verifique a pasta dist build. Ele deve conter um arquivo chamado bundle.js que contém o aplicativo incluído e o código de dependência.

Para obter mais informações sobre como otimizar o esbuild para produção, consulte a documentação oficial sobre minificação e outras otimizações .