Uma das últimas fases do processo de desenvolvimento envolve o empacotamento da aplicação, no caso do Angular podemos usar o Electron para tal feito, um framework para aplicações Web extremamente utilizado, sendo base do Chromium, Visual Studio Code, Spotify, etc.
Esse processo muitas vezes pode ser doloroso já que qualquer erro pode inviabilizar o feito, este artigo portanto tratará de fornecer uma série de instruções e arquivos para realizar essa etapa.
É importante salientar que esse documento abordará somente o empacotamento para a plataforma Windows.
As seguintes fontes são extremamente completas e podem ser usadas para melhor compreensão do assunto:
- How to create a windows installer for an application built with Electron Framework
- Entendendo o empacotamento e distribuição de app com Electron — Parte I
- Entendendo o empacotamento e distribuição de app com Electron — Parte II
Compreendendo a estrutura
Como durante o processo serão necessárias algumas mudanças entre os diretórios é importante deixar claro desde o início como a aplicação está estruturada:
Main_Directory
└── Angular_Application
├── dist
├── e2e
├── node_modules
├── src
├── angular.json
├── browserslist
├── karma.conf.js
├── package-lock.json
├── package.json
├── tsconfig.app.json
├── tsconfig.json
├── tsconfig.spec.json
└── tslint.json
Utilizarei um Main_Directory
no qual todos os procedimentos serão feitos. No momento é somente
necessário que a pasta da aplicação Angular, no meu caso nomeada de Angular_Application
,
esteja presente. Os nomes dos diretórios podem ser tranquilamente trocados conforme desejado,
os escolhidos aqui são somente de cunho ilustrativo.
Instalando as dependências
No diretório Angular_Application
instale as seguintes dependências:
$ npm i electron --save
$ npm i electron-squirrel-startup --save
$ npm i -g electron-packager
Verifique se os pacotes foram realmente adicionados na parte de dependencies
no arquivo package.json
,
durante minhas tentativas provavelmente por culpa de algum bug eles foram adicionados em devDependencies
.
A seguir está ilustrado como o arquivo deve estar:
{
...
"dependencies": {
...
"electron": "^9.0.0",
"electron-squirrel-startup": "1.0.0"
},
...
}
As versões listadas podem mudar conforme a data de instalação.
Criando o arquivo main.js
Este arquivo é de extrema importância e contém todas as instruções do Electron e de como os procedimentos de instalação, remoção, update devem ocorrer.
Na raiz da pasta Angular_Application
crie um arquivo chamado main.js
com o seguinte conteúdo:
const { app, BrowserWindow } = require('electron')
let win;
let MenuPrincipal = null;
if (require('electron-squirrel-startup')) return;
if (handleSquirrelEvent()) {
return;
}
function handleSquirrelEvent() {
if (process.argv.length === 1) {
return false;
}
const ChildProcess = require('child_process');
const path = require('path');
const appFolder = path.resolve(process.execPath, '..');
const rootAtomFolder = path.resolve(appFolder, '..');
const updateDotExe = path.resolve(path.join(rootAtomFolder, 'Update.exe'));
const exeName = path.basename(process.execPath);
const spawn = function (command, args) {
let spawnedProcess, error;
try {
spawnedProcess = ChildProcess.spawn(command, args, { detached: true });
} catch (error) { }
return spawnedProcess;
};
const spawnUpdate = function (args) {
return spawn(updateDotExe, args);
};
const squirrelEvent = process.argv[1];
switch (squirrelEvent) {
case '--squirrel-install':
case '--squirrel-updated':
spawnUpdate(['--createShortcut', exeName]);
setTimeout(app.quit, 1000);
return true;
case '--squirrel-uninstall':
spawnUpdate(['--removeShortcut', exeName]);
setTimeout(app.quit, 1000);
return true;
case '--squirrel-obsolete':
app.quit();
return true;
}
};
function createWindow() {
win = new BrowserWindow({
width: 1280,
height: 720,
backgroundColor: '#ffffff',
//Trocar caminho para corresponder ao ícone da aplicação
icon: `${ __dirname}/dist/Angular_Application/assets/img/logo.png`
})
win.setMenu(MenuPrincipal);
//Trocar caminho para corresponder ao index.html da aplicação
win.loadFile('dist/Angular_Application/index.html')
win.on('closed', function () {
win = null
})
}
app.on('ready', createWindow)
Provavelmente a única função que voce terá que se preocupar é a createWindow()
, já que nela será necessário trocar o
caminho para o ícone e do index.html
para corresponder ao da sua aplicação
O Electron possue uma barra de ferramentas, na qual é possível abrir o painel do desenvolvedor por exemplo, caso não deseje esconder essa barra comente as seguintes linhas:
let MenuPrincipal = null
win.setMenu(MenuPrincipal)
Adicionando scripts
Ainda na raiz do projeto, em Angular_Application
, edite o arquivo package.json
para conter:
{
...
"main": "main.js",
"scripts": {
...
"electron": "electron .",
"electron:build": "ng build --base-href ./ && electron .",
"package:win": "electron-packager . --platform=win32 --arch=ia32 --executable-name=\"Angular_Application\" --win32metadata ProductName=\"Angular_Application\" --win32m etadata.CompanyName=\"Company\" --asar --overwrite"
},
...
}
Lembre-se de trocar o Angular_Application
e Company
para o nome desejado.
O objetivo aqui é primeiro informar para o node.js que esse o main.js
existe, o restante do conteúdo em
scripts
provêm uma série de comandos úteis, sendo:
electron
permite executar a aplicação sem compilar novamente o Electron;electron:build
compila a aplicação e depois executa o Electron;package:win
cria um executável do Angular utilizando o Electron.
Modificando index.html
Localize o arquivo index.html
, encontrado dentro da pasta src
.
Main_Directory
└── Angular_Application
├── dist
├── e2e
├── node_modules
├── src
│ └── index.html
├── angular.json
├── browserslist
├── karma.conf.js
├── main.js
├── package-lock.json
├── package.json
├── tsconfig.app.json
├── tsconfig.json
├── tsconfig.spec.json
└── tslint.json
Edite o mesmo para que contenha um “.” em href
:
<head>
...
<base href="./">
...
</head>
Usando o electron-packager
Em Angular_Application
, execute o seguinte comando no terminal:
$ npm run electron:build
Caso tudo tenha sido feito corretamente uma janela do Electron com a aplicação deve ter aparecido, se isso aconteceu pode-se prosseguir, caso contrário recomenda-se verificar se o nome de todos os campos foram ajustados corretamente.
Prossiga para criar o executável através do terminal, com o comando:
$ npm run package:win
Surgirá uma pasta nova contendo o executável do Electron e todas as dependências necessárias para o mesmo, no meu caso angular_application-win32-ia32
, a pasta pode ser visualizada abaixo:
Main_Directory
└── Angular_Application
├── angular_application-win32-ia32
├── dist
├── e2e
├── node_modules
├── src
├── angular.json
├── browserslist
├── karma.conf.js
├── main.js
├── package-lock.json
├── package.json
├── tsconfig.app.json
├── tsconfig.json
├── tsconfig.spec.json
└── tslint.json
A aplicação nesse ponto já está totalmente isolada e funcionando com o Electron, porém para um programa mais profissional
pode-se continuar o tutorial para a criação de um único executável .exe
Instalando o electron-winstaller
Crie agora uma pasta chamada Electron
dentro de Main_Directory
:
Main_Directory
├── Angular_Application
│ ├── angular_application-win32-ia32
│ ├── dist
│ ├── e2e
│ ├── node_modules
│ ├── src
│ ├── angular.json
│ ├── browserslist
│ ├── karma.conf.js
│ ├── main.js
│ ├── package-lock.json
│ ├── package.json
│ ├── tsconfig.app.json
│ ├── tsconfig.json
│ ├── tsconfig.spec.json
│ └── tslint.json
└── Electron
Dentro da pasta Electron
inicie um projeto node e instale o electron-winstaller
, executando os comandos:
$ npm init
$ npm i electron-winstaller --save-dev
Copie a pasta criada no tópico anterior, no meu caso angular_application-win32-ia32
para dentro do diretório Electron
, a sua
estrutura deve ser basicamente essa:
Main_Directory
├── Angular_Application
│ ├── dist
│ ├── e2e
│ ├── node_modules
│ ├── src
│ ├── angular.json
│ ├── browserslist
│ ├── karma.conf.js
│ ├── main.js
│ ├── package-lock.json
│ ├── package.json
│ ├── tsconfig.app.json
│ ├── tsconfig.json
│ ├── tsconfig.spec.json
│ └── tslint.json
└── Electron
├── angular_application-win32-ia32
├── node_modules
└── package.json
Criando o arquivo build.js
Na pasta Electron
crie um arquivo nomeado de build.js
, contendo:
const electronInstaller = require('electron-winstaller');
resultPromise = electronInstaller.createWindowsInstaller({
//Troque o nome da pasta para corresponder a sua aplicação
appDirectory: './angular_application-win32-ia32',
outputDirectory: './Installer',
//Troque o nome dos autores
authors: 'Company_Name',
//Troque o nome do executável
exe: 'Angular_Application.exe',
description: 'App de controle de pedidos'
});
resultPromise.then(
() => console.log("Success"),
(e) => console.log(`Error: ${e.message}`)
);
Compilando o executável
No diretório Electron
execute no terminal:
$ node build.js
Caso tudo tenha ocorrido corretamente uma pasta chamada Installer
deve ter sido criada contendo o executável .exe
para a instalação da aplicação.
Informações Adicionais
Se por acaso no tópico anterior o terminal indicar o erro:
$ node build.js
creating windows installer
Error: Failed with exit code: 1
Output:
Tentando construir o pacote de 'teste.nuspec'.
O caminho especificado, o nome do arquivo ou ambos sao muito longos. O nome de arquivo totalmente qualificado deve ter menos de 260 caracteres e o nome do diretório menos de 248 caracteres.
Recomenda-se habilitar a política [Enable NTFS long paths policy]
do Windows, para tal:
- Aperte a tecla do Windows, digite
gpedit.msc
e aperte Enter - Navegue para
Local Computer Policy
>Computer Configuration
>Administrative Templates
>System
>Filesystem
>NTFS
- Dê um duplo clique em
Enable NTFS long paths
e habilite a opção
Apesar do instalador funcionar corretamente e criar um atalho na área de trabalho, o caminho do mesmo estará errado e não abrirá a aplicação. Recomenda-se verificar o local no qual a aplicação foi instalada e criar o atalho manualmente.