Woongjae Lee
NHN Dooray - Frontend Team
2woongjae@gmail.com
const firebaseApp: firebase.app.App = firebase.initializeApp({
apiKey: 'AIzaSyDCkophSrnmYtoANl583iyMbS_TM4oHBOM',
authDomain: 'electron-with-typescript.firebaseapp.com',
databaseURL: 'https://electron-with-typescript.firebaseio.com',
projectId: 'electron-with-typescript',
storageBucket: 'electron-with-typescript.appspot.com',
messagingSenderId: '231390164302'
});
function initializeApp (options : Object , name ? : string ) : firebase.app.App ;
declare namespace firebase.app {
interface App {
auth ( ) : firebase.auth.Auth ;
database ( ) : firebase.database.Database ;
delete ( ) : firebase.Promise < any > ;
messaging ( ) : firebase.messaging.Messaging ;
name : string ;
options : Object ;
storage (url ? : string ) : firebase.storage.Storage ;
}
}
import * as firebase from 'firebase';
// firebase.initializeApp 의 두번째 인자를 사용하지 않음.
const defaultApp: firebase.app.App = firebase.initializeApp(defaultAppConfig);
console.log(defaultApp.name); // "[DEFAULT]"
console.log(firebase.app().name); // "[DEFAULT]"
// 이렇게 사용하거나,
const auth = defaultApp.auth();
const database = defaultApp.database();
// 혹은 이렇게도 사용이 가능하다.
const auth = firebase.auth();
const database = firebase.database();
import * as firebase from 'firebase';
// [DEFAULT] 를 셋팅시에는 firebase.initializeApp 의 두번째 인자를 사용하지 않음.
firebase.initializeApp(defaultAppConfig);
// 다른 파이어베이스 프로젝트의 설정을 셋팅시에는, 두번째 인자에 이름을 넣는다.
const otherApp: firebase.app.App = firebase.initializeApp(otherAppConfig, "other");
console.log(firebase.app().name); // "[DEFAULT]"
console.log(otherApp.name); // "other"
// [DEFAULT] 프로젝트의 서비스를 사용할때는
const auth = firebase.auth();
const database = firebase.database();
// other 프로젝트의 서비스를 사용할때는
const otherDatabase = otherApp.database();
firebase.initializeApp({
apiKey: "AIza....", // Auth / General Use
authDomain: "YOUR_APP.firebaseapp.com", // Auth with popup/redirect
databaseURL: "https://YOUR_APP.firebaseio.com", // Realtime Database
storageBucket: "YOUR_APP.appspot.com", // Storage
messagingSenderId: "123456789" // Cloud Messaging
});
import * as firebase from 'firebase';
firebase.initializeApp({
apiKey: 'AIzaSyDCkophSrnmYtoANl583iyMbS_TM4oHBOM',
databaseURL: 'https://electron-with-typescript.firebaseio.com',
projectId: 'electron-with-typescript',
});
const auth = firebase.auth();
const database = firebase.database();
import {app, BrowserWindow} from 'electron';
import * as url from 'url';
import * as path from 'path';
// 둘 중 하나가 참이면 => protocol 뒤에 // 가 붙는다.
// protocol begins with http, https, ftp, gopher, or file
// slashes is true
const html = url.format({
protocol: 'file',
pathname: path.join(__dirname, '../../static/index.html')
});
app.on('ready', () => {
console.log('app ready');
const win = new BrowserWindow();
win.loadURL(html);
});
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Electron with TypeScript</title>
<link rel="stylesheet" href="./style.css" />
</head>
<body>
<h2>랜더러 프로세스</h2>
<script>
require('../output/renderer/index.js');
</script>
</body>
</html>
{
"name": "electron-with-typescript",
"version": "1.0.0",
"description": "텍스트 기반 온라인 메세지 앱 만들기",
"main": "output/browser/index.js",
"scripts": {
"start": "electron .",
"transpile": "tsc",
"transpile:watch": "tsc --watch"
},
"repository": {
"type": "git",
"url": "git+https://github.com/ts-korea/electron-with-typescript.git"
},
"keywords": [],
"author": "",
"license": "ISC",
"bugs": {
"url": "https://github.com/ts-korea/electron-with-typescript/issues"
},
"homepage": "https://github.com/ts-korea/electron-with-typescript#readme",
"devDependencies": {
"electron": "^1.7.5",
"tslint": "^5.7.0",
"typescript": "^2.4.2"
},
"dependencies": {
"firebase": "^4.3.0"
}
}
{
"name": "electron-with-typescript",
"version": "1.0.0",
"description": "텍스트 기반 온라인 메세지 앱 만들기",
"main": "output/browser/index.js",
"scripts": {
"start": "electron .",
"transpile": "tsc",
"transpile:watch": "tsc --watch"
},
"repository": {
"type": "git",
"url": "git+https://github.com/ts-korea/electron-with-typescript.git"
},
"keywords": [],
"author": "",
"license": "ISC",
"bugs": {
"url": "https://github.com/ts-korea/electron-with-typescript/issues"
},
"homepage": "https://github.com/ts-korea/electron-with-typescript#readme",
"devDependencies": {
"electron": "^1.7.5",
"tslint": "^5.7.0",
"typescript": "^2.4.2"
},
"dependencies": {
"bulma": "^0.5.1",
"firebase": "^4.3.0",
"font-awesome": "^4.7.0"
}
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Electron with TypeScript</title>
<link rel="stylesheet" href="../node_modules/font-awesome/css/font-awesome.min.css" />
<link rel="stylesheet" href="../node_modules/bulma/css/bulma.css" />
<link rel="stylesheet" href="./style.css" />
</head>
<body>
<section class="section">
<div class="container">
<h1 class="title">
Renderer Process
</h1>
<p class="subtitle">
My first website with <strong>Bulma</strong>!
</p>
</div>
</section>
<script>
require('../output/renderer/index.js');
</script>
</body>
</html>
app.on('ready', () => {
console.log('app ready');
const win = new BrowserWindow({
width: 500,
minWidth: 500,
maxWidth: 900,
height: 700,
minHeight: 700,
maxHeight: 700,
maximizable: false
});
win.loadURL(html);
// auth.signInWithEmailAndPassword('2woongjae@gmail.com', '2woongjae');
});
<body>
<section class="hero is-primary is-medium" id="nav-section">
<div class="hero-head">
<header class="nav">
<div class="container">
<div class="nav-left">
<a class="nav-item is-active">
Electron with TypeScript Hands-On Labs
</a>
</div>
<span class="nav-toggle">
<span></span>
<span></span>
<span></span>
</span>
<div class="nav-right nav-menu">
<a class="nav-item is-active">
#general
</a>
<span class="nav-item" id="btn-logout">
<a class="button is-primary is-inverted">
<span class="icon">
<i class="fa fa-sign-out"></i>
</span>
<span>Logout</span>
</a>
</span>
</div>
</div>
</header>
</div>
</section>
<section class="section" id="login-section"></section>
<section class="section hero is-primary" id="chat-section"></section>
<section class="section" id="write-section"></section>
</body>
.nav-left a {
cursor: default;
}
#login-section {
display: block;
/*display: none;*/
}
#chat-section {
display: none;
/*display: block;*/
height: 390px;
overflow-y: auto;
padding-top: 20px;
padding-bottom: 20px;
}
#write-section {
display: none;
/*display: block;*/
position: absolute;
width: 100%;
bottom: 0px;
left: 0px;
}
<section class="section" id="login-section">
<div class="container">
<div class="field">
<p class="control has-icons-left has-icons-right">
<input class="input" type="email" id="email" placeholder="Email">
<span class="icon is-small is-left">
<i class="fa fa-envelope"></i>
</span>
<span class="icon is-small is-right">
<i class="fa fa-check"></i>
</span>
</p>
</div>
<div class="field">
<p class="control has-icons-left">
<input class="input" type="password" id="password" placeholder="Password">
<span class="icon is-small is-left">
<i class="fa fa-lock"></i>
</span>
</p>
</div>
<div class="field">
<p class="control">
<button class="button is-success" id="btn-login">Login</button>
</p>
</div>
</div>
</section>
<section class="section hero is-primary" id="chat-section">
<div class="container" id="message-container">
<div class="box">
<article class="media">
<div class="media-content">
<div class="content">
<p>
<strong>John Smith</strong> <small>@johnsmith</small> <small>31m</small>
<br>
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aenean efficitur sit amet massa fringilla egestas. Nullam condimentum luctus turpis.
</p>
</div>
</div>
</article>
</div>
<div class="box">
<article class="media">
<div class="media-content">
<div class="content">
<p>
<strong>John Smith</strong> <small>@johnsmith</small> <small>31m</small>
<br>
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aenean efficitur sit amet massa fringilla egestas. Nullam condimentum luctus turpis.
</p>
</div>
</div>
</article>
</div>
<div class="box">
<article class="media">
<div class="media-content">
<div class="content">
<p>
<strong>John Smith</strong> <small>@johnsmith</small> <small>31m</small>
<br>
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aenean efficitur sit amet massa fringilla egestas. Nullam condimentum luctus turpis.
</p>
</div>
</div>
</article>
</div>
</div>
</section>
<section class="section" id="write-section">
<div class="container">
<div class="field">
<div class="control">
<textarea class="textarea" placeholder="Explain how we can help you"></textarea>
</div>
</div>
<div class="field">
<div class="control">
<button class="button is-primary">Send message</button>
</div>
</div>
</div>
</section>
import {ipcRenderer} from 'electron';
function main() {
const btnLogin = document.querySelector('#btn-login') as HTMLButtonElement;
const btnLogout = document.querySelector('#btn-logout') as HTMLButtonElement;
btnLogin.addEventListener('click', () => {
console.log('#btn-login click');
const input_email = document.querySelector('#email') as HTMLInputElement;
const input_password = document.querySelector('#password') as HTMLInputElement;
const loginObj = {
email: input_email.value,
password: input_password.value
};
ipcRenderer.send('request-login', loginObj);
});
btnLogout.addEventListener('click', () => {
console.log('#btn-logout click');
const input_email = document.querySelector('#email') as HTMLInputElement;
const input_password = document.querySelector('#password') as HTMLInputElement;
input_email.value = '';
input_password.value = '';
ipcRenderer.send('request-logout');
});
}
document.addEventListener('DOMContentLoaded', main);
export interface LoginObj {
email: string;
password: string;
}
ipcMain.on('request-login', async (event, arg: LoginObj) => {
let user = null;
try {
user = await auth.signInWithEmailAndPassword(arg.email, arg.password);
} catch (error) {
if (isFirebaseError(error)) {
console.log(error);
event.sender.send('login-error', error.message);
return;
} else {
throw error;
}
}
if (user) {
event.sender.send('login-success');
}
});
ipcMain.on('request-logout', async event => {
if (auth.currentUser) {
try {
await auth.signOut();
} catch (error) {
console.log(error);
return;
}
event.sender.send('logout-success');
}
});
const loginSection = document.querySelector('#login-section') as HTMLDivElement;
const chatSection = document.querySelector('#chat-section') as HTMLDivElement;
const writeSection = document.querySelector('#write-section') as HTMLDivElement;
ipcRenderer.on('login-success', (event, arg) => {
console.log('receive : login-success');
loginSection.style.display = 'none';
chatSection.style.display = 'block';
writeSection.style.display = 'block';
});
ipcRenderer.on('login-error', (event, arg: string) => {
console.log('receive : login-error');
// arg 를 메세지로 dialog 띄우기
console.error(arg);
});
ipcRenderer.on('logout-success', (event, arg) => {
console.log('receive : logout-success');
loginSection.style.display = 'block';
chatSection.style.display = 'none';
writeSection.style.display = 'none';
});
ipcMain.on('request-login', async (event, arg: LoginObj) => {
let user = null;
try {
user = await auth.signInWithEmailAndPassword(arg.email, arg.password);
} catch (error) {
if (isFirebaseError(error)) {
console.log(error);
event.sender.send('login-error', error.message);
return;
} else {
throw error;
}
}
if (user) {
event.sender.send('login-success');
const ref = database.ref();
ref.child('general').on('value', snapshot => {
if (snapshot) {
console.log(snapshot.val());
}
});
}
});
ipcMain.on('request-login', async (event, arg: LoginObj) => {
let user = null;
try {
user = await auth.signInWithEmailAndPassword(arg.email, arg.password);
} catch (error) {
if (isFirebaseError(error)) {
console.log(error);
event.sender.send('login-error', error.message);
return;
} else {
throw error;
}
}
if (user) {
event.sender.send('login-success');
const ref = database.ref();
ref.child('general').on('value', snapshot => {
if (snapshot) {
const messageObject = snapshot.val();
event.sender.send('general-message', messageObject);
}
});
}
});
ipcRenderer.on('general-message', (event, arg: string) => {
console.log('receive : general-message');
console.error(arg);
});
By Woongjae Lee
타입스크립트 한국 유저 그룹 일렉트론 워크샵 201709