Você já usou uma extensão do Chrome em seu navegador da Web Google Chrome? Pessoalmente, uso muitas delas e algumas das minhas favoritas incluem ColorZilla e Hangouts do Google. Você já quis criar sua própria extensão do Chrome ou, mais importante ainda, uma extensão do Chrome que sincroniza dados com sua fonte de dados remota?
As extensões do Chrome são apenas aplicativos JavaScript e, como desenvolvedores de JavaScript, temos todas as habilidades necessárias para criar algo incrível.

Vamos dar uma olhada na criação de uma extensão do Google Chrome que sincroniza os dados da lista de compras entre navegadores e até mesmo entre dispositivos usando o Angular 2, PouchDBe Couchbase.
Os requisitos
Há alguns requisitos quando se trata de fazer a extensão de pop-up planejada. Eles são os seguintes:
- Node.js 4.0+
- CLI angular
- Gateway de sincronização do Couchbase 1.3+
Como estamos criando a extensão usando o Angular 2, precisaremos da CLI do Angular, que é disponibilizada pelo Node Package Manager (NPM) encontrado no Node.js. Embora não estejamos usando o Couchbase Server neste exemplo, ele pode ser facilmente adicionado ao nosso arquivo de configuração do Couchbase Sync Gateway a ser criado em breve. Em vez disso, usaremos uma solução de armazenamento na memória que vem com o Sync Gateway e usaremos o Sync Gateway para sincronizar nossos dados entre navegadores, dispositivos, plataformas e o Couchbase Server.
Preparação do Couchbase Sync Gateway para replicação de dados
Há várias maneiras de criar uma extensão do Chrome que usa o Couchbase. Para este exemplo, e em um esforço para criar apenas um aplicativo, vamos mantê-lo voltado para o cliente com JavaScript e o Couchbase Sync Gateway. Outros exemplos poderiam incluir um serviço de back-end com o qual nosso aplicativo cliente se comunica, e esse serviço de back-end se comunicaria com o Couchbase.
Como a extensão do Chrome é um aplicativo, precisamos de uma configuração para o Sync Gateway para que ele saiba como orquestrar os dados. Uma configuração em uma de suas formas mais simples pode se parecer com o seguinte:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
{ "log":["CRUD+", "REST+", "Mudanças+", "Anexar+"], "bancos de dados": { "exemplo": { "servidor":"walrus:", "sync":` função (doc) { canal (doc.canais); } `, "usuários": { "CONVIDADO": { "desativado": falso, "admin_channels": ["*"] } } } }, "CORS": { "Origem": ["http://localhost:4200", "chrome-extension://ecfgpjabjmlpkedejekaipjipddddohj"], "LoginOrigin": ["http://localhost:4200", "chrome-extension://ecfgpjabjmlpkedejekaipjipddddohj"], "Headers" (Cabeçalhos): ["Content-Type"], "MaxAge": 17280000 } } |
A configuração acima seria salva em um arquivo chamado sync-gateway-config.json e carregado ao iniciar o Sync Gateway.
Na configuração, estamos usando um banco de dados chamado exemplo sem permissões específicas de leitura ou gravação. A seção CORS é para compartilhamento de recursos entre origens, um requisito quando se trata de aplicativos JavaScript. O que estamos dizendo é que gostaríamos de permitir conexões da porta 4200, que é o nosso aplicativo Angular 2 durante o teste, e o endereço da nossa extensão do Chrome.
Baixar o Sync Gateway e inicie-o executando o seguinte:
|
1 |
/caminho/para/portais de sincronização /caminho/para/sincronização-portal-configuração.json |
O procedimento acima começará a servir o Sync Gateway em http://localhost:4985/_admin/.
Criação de um novo aplicativo com o Bootstrap e o Angular 2
Para simplificar, iniciaremos um novo projeto do Angular 2 e, posteriormente, o agruparemos em uma extensão do Chrome. Na CLI do Angular, execute o seguinte comando:
|
1 |
ng novo Projeto Angular |
O comando acima criará um projeto Angular 2 pronto para uso. Em um esforço para evitar que tenhamos uma interface de usuário horrível, vamos incluir o popular Bootstrap framework. Há muitas outras estruturas e, em um dos meus exemplos anteriores, até usei o Ionic como estrutura.
Esse é um processo um pouco manual, já que o Angular 2 não é necessariamente compatível com nossas dependências, mas precisamos fazer o download de Bootstrap, jQuerye Caixa de inicialização.
Coloque os arquivos JavaScript no diretório src/assets/js/ os arquivos CSS no diretório src/assets/css/ e os arquivos de fontes no diretório src/assets/fonts/ diretório.
O Bootstrap será nossa estrutura CSS, mas ele depende do jQuery. O Bootbox nos dará uma maneira conveniente de criar prompts pop-up para o nosso aplicativo. Ele foi desenvolvido com base no Bootstrap e no jQuery.
Precisamos adicionar o Bootstrap ao nosso projeto da maneira antiga. Abra a seção src/index.html e faça com que ele se pareça com o seguinte:
|
1 2 3 4 5 6 7 8 9 10 11 |
<!doctype html> Couchbase Compras Carregamento... |
Observe que estamos importando os arquivos CSS e JavaScript que foram baixados.
Neste momento, podemos começar a programar, mas, antes disso, é uma boa ideia obter mais algumas dependências que serão usadas em todo o projeto.
Usando o prompt de comando (Windows) ou o terminal (Mac e Linux), execute o seguinte:
|
1 2 3 |
npm instalar bolsadb --salvar npm instalar uuid @tipos/uuid --salvar npm instalar @tipos/nó --salvar |
Os comandos acima instalarão o PouchDB, que usaremos para replicar dados de e para o Couchbase Sync Gateway. Usaremos a dependência UUID para gerar valores de identificação exclusivos que usaremos como chaves de documento e usaremos a dependência Node para podermos importar a biblioteca do PouchDB para o nosso projeto. Precisamos da dependência do Node, pois o PouchDB não tem definições de tipo TypeScript.
Vamos começar a desenvolver o aplicativo por trás da nossa extensão agora.
Desenvolvimento de um provedor compartilhado com Angular 2 e PouchDB
Se você assistiu aos meus últimos tutoriais, isso pode lhe parecer familiar. Ao trabalhar com dados em um aplicativo Angular 2, é uma boa ideia separar a lógica do restante do aplicativo. Podemos fazer isso criando um provedor compartilhado do Angular 2 que envolve o PouchDB e pode ser usado em todo o aplicativo.
Criar um arquivo, src/app/pouchdb.service.ts e incluir a seguinte lógica TypeScript:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 |
importação { Injetável, Emissor de eventos } de '@angular/core'; var PouchDB = exigir("pouchdb"); @Injetável() exportação classe PouchService { privado isInstantiated: booleano; privado banco de dados: qualquer; privado ouvinte: Emissor de eventos = novo Emissor de eventos(); público construtor() { se(!este.isInstantiated) { este.banco de dados = novo PouchDB("nraboy"); este.banco de dados.mudanças({ ao vivo: verdadeiro, incluir_docs: verdadeiro }).em("mudança, mudança => { este.ouvinte.emitir(mudança); }); este.isInstantiated = verdadeiro; } } público obter(id: string) { retorno este.banco de dados.obter(id); } público colocar(documento: qualquer, id: string) { documento._id = id; retorno este.obter(id).então(resultado => { documento._rev = resultado._rev; retorno este.banco de dados.colocar(documento); }, erro => { se(erro.status == "404") { retorno este.banco de dados.colocar(documento); } mais { retorno novo Promessa((resolver, rejeitar) => { rejeitar(erro); }); } }); } público sincronização(remoto: string) { deixar banco de dados remoto = novo PouchDB(remoto); este.banco de dados.sincronização(banco de dados remoto, { ao vivo: verdadeiro, tentar novamente: verdadeiro }); } público getChangeListener() { retorno este.ouvinte; } } |
Há muita coisa acontecendo, então é melhor pararmos um pouco para detalhar.
|
1 2 |
importação { Injetável, Emissor de eventos } de '@angular/core'; var PouchDB = exigir("pouchdb"); |
Planejamos injetar esse provedor em cada uma de nossas páginas de extensão. Como o PouchDB tem um ouvinte de alterações, queremos emitir essas alterações para que as páginas possam se inscrever nelas.
|
1 2 3 4 5 6 7 8 9 10 11 12 |
público construtor() { se(!este.isInstantiated) { este.banco de dados = novo PouchDB("nraboy"); este.banco de dados.mudanças({ ao vivo: verdadeiro, incluir_docs: verdadeiro }).em("mudança, mudança => { este.ouvinte.emitir(mudança); }); este.isInstantiated = verdadeiro; } } |
O objetivo é ter uma única instância do banco de dados local. Depois de abrir o banco de dados e configurar os emissores de alterações, queremos armazenar o registro de que o banco de dados está aberto para que não possamos abri-lo novamente. A melhor maneira de fazer isso é no construtor método.
Salvar no PouchDB não é mais do que uma única linha, mas se quisermos fazer o upsert, será necessário um pouco mais:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
público colocar(documento: qualquer, id: string) { documento._id = id; retorno este.obter(id).então(resultado => { documento._rev = resultado._rev; retorno este.banco de dados.colocar(documento); }, erro => { se(erro.status == "404") { retorno este.banco de dados.colocar(documento); } mais { retorno novo Promessa((resolver, rejeitar) => { rejeitar(erro); }); } }); } |
A inserção ascendente envolve verificar se o documento já existe. Se existir, capturar a revisão e atualizá-la. Se o documento não existir, crie o documento.
|
1 2 3 4 5 6 7 |
público sincronização(remoto: string) { deixar banco de dados remoto = novo PouchDB(remoto); este.banco de dados.sincronização(banco de dados remoto, { ao vivo: verdadeiro, tentar novamente: verdadeiro }); } |
Desejamos sincronizar, portanto, criaremos um sincronização que usa um banco de dados remoto. O banco de dados remoto é o nosso Couchbase Sync Gateway. Quando ativado, sincronizaremos continuamente em ambas as direções.
|
1 2 3 |
público getChangeListener() { retorno este.ouvinte; } |
Finalmente, temos um getChangeListener que nos permitirá recuperar e assinar o emissor do evento de alteração.
Antes de começarmos a usar o provedor, ele deve ser importado para a pasta @NgModule bloco. Abra a seção src/app/app.module.ts e inclua o seguinte:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
importação { Módulo do navegador } de '@angular/platform-browser'; importação { NgModule } de '@angular/core'; importação { FormsModule } de '@angular/forms'; importação { HttpModule } de '@angular/http'; importação { Componente de aplicativo } de './app.component'; importação { PouchService } de "./pouchdb.service"; @NgModule({ declarações: [ Componente de aplicativo ], importações: [ Módulo do navegador, FormsModule, HttpModule ], provedores: [PouchService], bootstrap: [Componente de aplicativo] }) exportação classe AppModule { } |
Observe que o PouchService foi importado e adicionado ao provedores matriz do @NgModule bloco. Nesse ponto, o provedor pode ser usado em qualquer página da extensão.
Criação do aplicativo e adição de dados da extensão do Chrome
Há algumas coisas que precisam ser feitas nesse projeto. A funcionalidade do Angular 2 para o pop-up da extensão deve ser adicionada e deve ser empacotada em uma extensão real do Google Chrome, em vez de ser deixada como um aplicativo da Web.
Criação da página do aplicativo Angular 2
A extensão que estamos criando consiste apenas em uma única página. Essa página terá uma interface HTML e CSS personalizada, bem como uma lógica para acioná-la.
Começando com o TypeScript, abra o arquivo src/app/app.component.ts e inclua o seguinte TypeScript:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
importação { Componente, OnInit, NgZone } de '@angular/core'; importar * como Uuid de "uuid"; importação { PouchService } de "./pouchdb.service"; declarar var caixa de inicialização: qualquer; @Componente({ seletor: 'raiz do aplicativo', templateUrl: './app.component.html', styleUrls: ['./app.component.css'] }) exportação classe Componente de aplicativo implementa OnInit { público itens: Matriz; público construtor(privado banco de dados: PouchService, privado zona: NgZone) { este.itens = []; } público ngOnInit() { este.banco de dados.sincronização("http://localhost:4984/example"); este.banco de dados.getChangeListener().assinar(dados => { este.zona.executar(() => { este.itens.empurrar(dados.doc); }); }); } público inserir() { caixa de inicialização.imediato("O que você quer acrescentar?", resultado => { se(resultado) { este.banco de dados.colocar({tipo: "lista", título: resultado}, Uuid.v4()); } }); } } |
No TypeScript acima, estamos importando alguns componentes do Angular 2, o provedor PouchDB que criamos, bem como a biblioteca UUID para gerar chaves de documento exclusivas.
Com base em como decidimos incluir Caixa de inicializaçãoele deve ser declarado como qualquer para evitar erros do TypeScript. Mais informações sobre a inclusão de bibliotecas baseadas em navegador JavaScript em um aplicativo TypeScript podem ser encontradas aqui.
Cada item de compras será armazenado no itens array. Ele é público, portanto pode ser acessado a partir da marcação HTML. O construtor não apenas inicializa essa matriz, mas também injeta o serviço PouchDB na página, bem como o NgZone. Usaremos o NgZone ao atualizar a interface do usuário em um ouvinte de eventos.
Como é uma prática ruim carregar dados dentro do construtor carregamos no método ngOnInit método. Os dados são carregados por meio da assinatura do ouvinte de eventos e da sincronização das alterações do servidor remoto.
Por fim, podemos usar o Bootbox em nosso inserir para solicitar dados e salvá-los no banco de dados. Se estiver sincronizando, os dados serão salvos e depois replicados para o Couchbase.
A interface de usuário HTML por trás dessa lógica pode ser encontrada no src/app/app.component.html file:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 |
<div> <navegação classe="navbar navbar-default navbar-fixed-top" estilo="cor de fundo: #CC2A2E;"> <div classe="navbar-header" (cabeçalho da barra de navegação)> <extensão classe="navbar-brand" estilo="color: #FFFFFF">Couchbase Compras</extensão> </div> </navegação> <ul classe="grupo de listas" estilo="margin-top: 52px"> <li classe="list-group-item" *ngFor="let item of items">{{ item.título }}</li> </ul> <a (clique)="insert()" classe="btn btn-circle btn-primary" estilo="position: fixed; bottom: 10px; right: 10px"> <extensão classe="glyphicon glyphicon-plus"></extensão> </a> </div> |
Usando o Bootstrap e CSS personalizado, a interface do usuário tem uma barra de ação com uma lista de dados. A lista de dados é preenchida a partir do itens e é adicionado por meio de um botão flutuante. O botão flutuante tem o seguinte CSS, que pode ser adicionado à seção src/app/app.component.css file:
|
1 2 3 4 5 6 7 8 9 10 |
/* Extraído de http://bootsnipp.com/snippets/8deZ */ .btn-círculo { largura: 35px; altura: 35px; texto-alinhar: centro; acolchoamento: 2px 0; fonte-tamanho: 20px; linha-altura: 1.65; fronteira-raio: 30px; } |
Quando clicado, o botão acionará a função inserir método. Neste ponto, temos um aplicativo da Web do Angular 2 totalmente funcional que se replica com Couchbase. No entanto, nosso objetivo é transformá-lo em uma extensão para o Google Chrome.
Preparação e empacotamento para implantação do Google Chrome
O Google Chrome exige pelo menos duas coisas ao criar uma extensão do Chrome. Você deve ter um ícone de extensão e um arquivo de manifesto. Para obter qualidade, você deve ter ícones de vários tamanhos, mas, para simplificar, usaremos apenas um.
Crie um novo projeto, fora de seu projeto Angular 2. Talvez o chame de MyChromeExtension. O que você deseja fazer é criar seu projeto Angular 2 nesse novo projeto de extensão do Chrome. Por exemplo, você faria algo assim:
|
1 |
ng construir --saída-caminho=/caminho/para/MyChromeExtension/ |
Se for bem-sucedido, todos os arquivos de projeto do Angular 2 empacotados acabarão em sua pasta MyChromeExtension diretório. Nesse mesmo diretório, crie um arquivo manifest.json com o seguinte:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
{ "manifest_version": 2, "name" (nome): "Couchbase Shopping", "description" (descrição): "Sincronizar com o Couchbase em uma extensão do Google Chrome", "versão": "1.0", "browser_action": { "default_icon": "icon.png", "default_popup": "index.html" }, "permissões": [], "content_security_policy" (política de segurança de conteúdo): "script-src 'self' 'unsafe-eval'; object-src 'self'", "web_accessible_resources": [ "assets/css/*", "assets/js/*", "assets/fonts/*" ] } |
Há algumas partes importantes no arquivo de manifesto acima. Estamos dizendo que o ícone da extensão será ícone.png encontrado na raiz do projeto. Se você ainda não tiver criado um, crie um ícone de 128×128 no formato PNG. A página a ser aberta ao clicar no ícone em sua barra de ferramentas do Chrome é a index.html que deve ter sido gerado durante a criação do seu projeto Angular 2.
Por padrão, não podemos usar arquivos a menos que os especifiquemos. Ao definir uma lista de recursos acessíveis na web estamos dizendo que nossa extensão tem permissão para usar o JavaScript, o CSS e as fontes que o Bootstrap nos deixou.
Precisamos ter um política de segurança de conteúdo porque o JavaScript em nosso projeto se comunica com serviços fora do nosso pacote. Mais especificamente, o Couchbase Sync Gateway.
Para instalar nossa extensão em um navegador Chrome, abra o Chrome e navegue até o gerenciador de extensões.

Na parte superior, ative a extensão de desenvolvedor e navegue até seu MyChromeExtension diretório de extensão descompactado. Ao carregá-la, a extensão será colocada em sua barra de ferramentas do Chrome como qualquer outra extensão.
Vendo o pacote completo
Havia muita coisa para entender quando se tratava dessa extensão do Angular 2 para o Google Chrome. Eu fez o upload do projeto no GitHub, caso você queira fazer um teste.
Faça o download do projeto e navegue até o diretório AngularExtension . A partir desse diretório, execute o seguinte:
|
1 2 |
npm instalar ng construir --saída-caminho=../público |
Uma vez que o público tenha sido criado, copie os arquivos de manifesto e de ícone para o diretório público. Em seguida, você pode carregá-lo no Google Chrome.
Conclusão
Você acabou de ver como criar uma extensão do Google Chrome com o Angular 2 que usa o Couchbase para replicar dados. Esse projeto era basicamente um aplicativo Angular 2 com o pacote do Google Chrome, mas demonstrou como é fácil criar essas extensões.
Como mencionado anteriormente, há muitas maneiras diferentes de usar Couchbase com extensões do Google Chrome. Você pode usar o PouchDB e o Sync Gateway, pode usar solicitações HTTP e o Sync Gateway, pode criar sua própria API da Web com os SDKs do Couchbase ou qualquer outra coisa.