Preferences
const { app, BrowserWindow, ipcMain } = require('electron')
const path = require('path')
const createWindow = () => {
// Create the browser window.
const mainWindow = new BrowserWindow({
width: 800,
height: 600,
webPreferences: {
preload: path.join(__dirname, 'preload.js')
},
})
mainWindow.removeMenu(); // remove Menu
// and load the index.html of the app.
mainWindow.loadFile('index.html')
}
mainWindow.removeMenu() 구문을 통해 메뉴 삭제를 구현했다. 하지만 이렇게 하고 나면 메뉴에 있던 DevTools를 on/off 하는 기능을 사용할 수 없어서 불편하다. 이를 해결하기 위해 단축키를 이용하여 Devtools를 열 수 있는 기능을 추가해보자.
npm install electron-localshortcut
electron-localshortcut이란 모듈을 npm을 사용해 설치하자.
//main.js
const electronLocalshortcut = require('electron-localshortcut')
electronLocalshortcut.register(mainWindow, 'F12', () => {
console.log("F12 is pressed")
mainWindow.webContents.toggleDevTools()
})
위 코드를 main.js에 추가하면 된다.
또한 나중에 exe 파일로 만들었을 때를 위해 exe 창이 하나만 뜨게 만들어주자.
//main.js
const onlyOne = app.requestSingleInstanceLock();
if (!onlyOne) {
app.quit();
app.exit();
} else {
//...
});
Todo CRUD
우선 레이아웃부터 짜보도록 하자.
<!--index.html-->
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<!-- https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP -->
<meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src 'self'">
<meta http-equiv="X-Content-Security-Policy" content="default-src 'self'; script-src 'self'">
<link rel="stylesheet" href="./style.css">
<title>ToDo With Cat</title>
</head>
<body>
<div class="app">
<div class="center">
<h1 id="clock">00:00</h1>
<!-- login page -->
<div class="hidden" id="login">
<form id="login-form">
<h1>Hello</h1>
<h3>What your name?</h3>
<div class="control">
<input id="name-input" type="text" required maxlength="15" type="text"
placeholder="What is your name?" />
<br>
<input id="submit-input" type="submit" value="Log in" />
</div>
</form>
</div>
<div class="todos">
<h1 class="hidden" id="greeting"></h1>
<form class="hidden" id="todo-form">
<input type="text" id="todo-input" placeholder="Write a To Do and Press Enter" required />
</form>
</div>
<ul id="todo-list"></ul>
</div>
<div class="container">
<svg id="bongo-cat" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
viewBox="0 0 787.3 433.8">
<defs>
<symbol id="eye" data-name="eye" viewBox="0 0 19.2 18.7">
<circle cx="9.4" cy="9.1" r="8"></circle>
<path
d="M16.3,5.1a1.3,1.3,0,0,1-1.4-.3,7.2,7.2,0,0,0-4.5-2.6A7.2,7.2,0,0,0,5.5,3.5,6.8,6.8,0,0,0,2.8,7.8a6.8,6.8,0,0,0,1,4.8,6.2,6.2,0,0,0,4,2.7,6.1,6.1,0,0,0,4.6-.7,6.7,6.7,0,0,0,2.9-3.7,6.4,6.4,0,0,0-.5-4.5c-.1-.2.8-1,1.5-1.3s2.2,0,2.3.5a9.4,9.4,0,0,1-.2,7.2,9.4,9.4,0,0,1-5.1,5.1,9,9,0,0,1-7,.2A9.6,9.6,0,0,1,1,13.5,9.2,9.2,0,0,1,.4,6.6,8.9,8.9,0,0,1,4.6,1.3,9,9,0,0,1,11.2.2,9.3,9.3,0,0,1,16.7,4C16.9,4.3,17,4.8,16.3,5.1Z">
</path>
</symbol>
<symbol id="paw-pads" data-name="paw-pads" viewBox="0 0 31.4 33.9">
<path
d="M6.8,16a3.7,3.7,0,0,1,1.1,2.8,3.2,3.2,0,0,1-1.6,2.6L5,21.8H4.4a2.8,2.8,0,0,1-1.8.3A4.2,4.2,0,0,1,.2,19.1,7.7,7.7,0,0,1,0,17.6a2.8,2.8,0,0,1,.6-2,3.2,3.2,0,0,1,2.1-.8H4A5,5,0,0,1,6.8,16Zm7.3-4.8a1.8,1.8,0,0,0,.7-.5l.7-.4a3.5,3.5,0,0,0,1.1-1,3.2,3.2,0,0,0,.3-1.4,1.4,1.4,0,0,0-.2-.6,3.4,3.4,0,0,0-.3-2.4,3.2,3.2,0,0,0-2.1-1.5H13.1a4.7,4.7,0,0,0-1.6.4,2,2,0,0,0-.9.9l-.4.6v.4a6.1,6.1,0,0,0-.5,1.2,4.3,4.3,0,0,0,0,1.6,3.5,3.5,0,0,0,.5,2l.7.6a3.3,3.3,0,0,0,1.7.7A3,3,0,0,0,14.1,11.2ZM22.7,7l.6.2h.3A2.3,2.3,0,0,0,25,6.8l.4-.3.6-.3a7.5,7.5,0,0,0,1.5-.9,4.2,4.2,0,0,0,.8-1.2,1.9,1.9,0,0,0,.1-1.5A2.6,2.6,0,0,0,27.5,1,3.5,3.5,0,0,0,23.6.3a3.8,3.8,0,0,0-2,1.5,4.8,4.8,0,0,0-.7,2,3.6,3.6,0,0,0,.9,2.6ZM31,24.1a13.5,13.5,0,0,0-2.2-4.7,36.6,36.6,0,0,0-3.2-3.9,5.3,5.3,0,0,0-5-1.9,10.5,10.5,0,0,0-4.5,2.2A5.6,5.6,0,0,0,13.5,20a15.1,15.1,0,0,0,1.2,6.3c.8,2,1.7,4,2.6,5.9a1.6,1.6,0,0,0,1.5.8,1.7,1.7,0,0,0,1.9.9,17.1,17.1,0,0,0,8.7-4.8,8.2,8.2,0,0,0,1.7-2C31.6,26.3,31.3,25,31,24.1Z"
fill="#ef97b0"></path>
</symbol>
</defs>
<g id="head">
<g id="head__outline">
<path
d="M303.2,186.3c4-7,14.8-20.2,20-26,17-19,34.6-34.9,43-41l12-8s16.6-32,21-33c9-2,33,22,33,22s20-9,79,7c41,11.1,47,14,57,22,7.5,6,18,16,18,16s33.7-19.5,41-15-2,66-2,66,5.9,12.9,11,22c9.1,16.2,13.6,20.2,19,31,3.6,7.2,8.4,28.5,10.5,43.5l-385-62Z"
fill="#fff"></path>
<path
d="M302.9,186.9c-1.2,3-5.9,12.6-9,18.8l-12.5,25.5-.6-1.2c32.2,4.8,64.4,9.2,96.6,13.6s64.4,8.9,96.5,13.7,64.3,9.7,96.4,14.9,64.1,10.5,96.2,15.8l-5.6,5.5c-1.2-8.5-2.8-17.1-4.8-25.6-1-4.1-2.1-8.4-3.4-12.3l-.5-1.4-.5-1.4-.6-1.3-.7-1.3a59.5,59.5,0,0,0-3.1-5.5c-2.2-3.6-4.7-7.2-7.1-11s-4.8-7.6-7-11.5c-4.5-7.9-8.3-15.9-12.1-24a4,4,0,0,1-.3-2.6h0c1.4-9.1,2.7-18.2,3.7-27.4.5-4.5.9-9.1,1.2-13.7s.4-9.1.2-13.4a26.4,26.4,0,0,0-.8-6,8.1,8.1,0,0,0-.3-1.1c-.1-.3-.2-.4-.1-.3h.3c0,.1.1.1,0,.1h-.6a11.9,11.9,0,0,0-2.5.2,16.3,16.3,0,0,0-3,.7,56.7,56.7,0,0,0-6.2,2.1,212.6,212.6,0,0,0-24.5,11.9h-.1a3.9,3.9,0,0,1-4.7-.6c-4.9-4.7-10-9.4-15.1-13.8a86.6,86.6,0,0,0-7.9-6,46.1,46.1,0,0,0-8.5-4.6c-6-2.6-12.6-4.6-19.2-6.7l-19.8-5.7a324.9,324.9,0,0,0-40-8.9,196.8,196.8,0,0,0-20.2-1.8c-1.7,0-3.4-.1-5.1,0h-2.5l-2.5.2-2.5.2-2.4.4-2.4.5-1.1.3h-.5l-.4.2H433a2.5,2.5,0,0,1-2.6-.7c-4.6-4.6-9.5-9.1-14.5-13.2a82.7,82.7,0,0,0-7.9-5.7L403.9,81a10.8,10.8,0,0,0-4-.9c-.1,0-.3,0-.3.1h0l-.7.5-1.5,1.7c-1,1.2-2,2.6-2.9,3.9s-3.6,5.5-5.3,8.3c-3.5,5.7-6.8,11.4-9.9,17.3h0l-.4.4-10.2,6.6a53.6,53.6,0,0,0-4.9,3.4l-4.6,3.8c-6.2,5.1-12.1,10.6-17.9,16.2s-11.3,11.4-16.7,17.4c-2.7,3-5.3,6.1-7.8,9.2s-5,6.3-7.4,9.5c-4.2,5.6-7,10-5.7,7.1a34.1,34.1,0,0,1,2.1-3.8l3.8-5.6c2.9-4,6.3-8.3,8.5-10.9s4.4-5.2,6.7-7.7l6.9-7.4c4.7-4.9,9.4-9.7,14.3-14.3s9.8-9.3,15-13.7l4-3.2,4.2-2.9,8.3-5.7-.4.4c3-5.9,6.1-11.8,9.4-17.7,1.6-2.9,3.3-5.8,5.1-8.6l2.9-4.3,1.8-2a7.5,7.5,0,0,1,1.3-1.1c.1-.2.6-.4,1-.5l.9-.2h1.7l1.4.2,2.7.8c1.7.7,3.3,1.5,4.8,2.3a84,84,0,0,1,8.5,5.7A175.7,175.7,0,0,1,434,98.5l-2.9-.6.8-.3.7-.2L434,97l2.7-.7,2.7-.5a23,23,0,0,1,2.6-.3l2.7-.3,2.7-.2h5.3a182.1,182.1,0,0,1,21,1.3,332.5,332.5,0,0,1,41.1,8.4l20,5.5c6.7,2,13.4,4,20.1,6.7a65.3,65.3,0,0,1,9.8,5.1c3.1,2.1,5.9,4.3,8.6,6.5,5.4,4.5,10.6,9.2,15.7,14l-4.8-.6c4.1-2.4,8.2-4.6,12.4-6.7s8.6-4.2,13-6c2.3-.9,4.6-1.7,7-2.4a23.4,23.4,0,0,1,3.8-.9,20,20,0,0,1,4.4-.4h1.3l1.5.4a5.1,5.1,0,0,1,1.7.7l.9.7.8.7a8.3,8.3,0,0,1,1.6,2.6,12.7,12.7,0,0,1,.8,2.3,44.6,44.6,0,0,1,1.1,7.7c.2,5,.1,9.7-.1,14.4s-.7,9.5-1.2,14.1c-.9,9.4-2.1,18.6-3.6,27.9l-.3-2.6c3.7,7.9,7.5,15.8,11.8,23.3,2.1,3.7,4.4,7.4,6.8,11s4.9,7.2,7.3,11.1c1.3,2,2.4,4,3.5,6.1a10.9,10.9,0,0,0,.8,1.5l.8,1.8.7,1.7.6,1.7c1.5,4.4,2.6,8.7,3.7,13.1a262,262,0,0,1,5.2,26.4,4.9,4.9,0,0,1-4.1,5.6h-1.5c-32.1-5-64.2-9.9-96.3-15.1s-64.1-10.6-96.1-16.1-64-11.4-96-17.4-63.9-11.9-95.9-17.4h-.1a.8.8,0,0,1-.6-.9v-.2l16.6-32.1C299.8,192.2,304.1,183.9,302.9,186.9Z">
</path>
</g>
<g id="head__face">
<g id="eyes">
<use width="19.2" height="18.7" transform="translate(474.8 195.2)" xlink:href="#eye">
</use>
<use width="19.2" height="18.7" transform="matrix(-0.51, -0.85, 0.82, -0.5, 370.39, 192.59)"
xlink:href="#eye">
</use>
</g>
<g id="mouth">
<path d="M399.2,186.3c.9,3.6,2.6,7.8,6,9,6.4,2.3,19-6,19-6s4.1,12.4,10,15,10.7-1.7,16-6"
fill="#fff"></path>
<path
d="M450.2,198.3c.6,1.2.2,1.9-.2,2.2a36.7,36.7,0,0,1-7.6,4.9,14.9,14.9,0,0,1-4.8,1.4h-1.4l-1.3-.2-1.4-.4-1.3-.6a21.6,21.6,0,0,1-6.4-7.2,52.8,52.8,0,0,1-4-8.3l3.8,1.3a62.3,62.3,0,0,1-7.1,4.1,32.1,32.1,0,0,1-7.9,2.8,13.2,13.2,0,0,1-4.9.2l-1.4-.3a7.5,7.5,0,0,1-1.3-.6,7.9,7.9,0,0,1-2.3-1.6,16.8,16.8,0,0,1-2.9-4,24.1,24.1,0,0,1-1.6-4.2c-.1-.5,1.6-1.3,3-1.4s3.5.2,3.6.6a10.3,10.3,0,0,0,2.6,4.9l.7.5h2.4l1.5-.2a28.4,28.4,0,0,0,6.5-2c2.1-1,4.3-2.1,6.3-3.3h.1a2.5,2.5,0,0,1,3.4.9l.3.5a43.1,43.1,0,0,0,3.2,7.7,19.8,19.8,0,0,0,2.2,3.4,8.1,8.1,0,0,0,2.6,2.6,5,5,0,0,0,3,.7,10.8,10.8,0,0,0,3.7-1,33.4,33.4,0,0,0,7.2-4.3C448.8,197.4,449.5,197.2,450.2,198.3Z">
</path>
</g>
</g>
</g>
<g id="table">
<path d="M65.7,181.8l714,124c0,74-2,54-2,128l-673-161Z" fill="beige"></path>
<path
d="M786.7,304.2c-2.7,1.2-10.8,0-16.1-.9L31.1,176.4c-5.2-.9-8.9-3.8-6.2-5s14.3-1.4,19.5-.5L777.1,300.6C782.3,301.6,789.4,303.1,786.7,304.2Z">
</path>
</g>
<g id="laptop">
<g id="laptop__base">
<polygon points="641.9 304.1 454.7 348.2 103.8 271.3 254.6 230.3 641.9 304.1" fill="#f2f2f2">
</polygon>
<path
d="M641.9,304.1c1.5-.1-2.3,1.5-10.3,3.6-28.9,7.5-58.1,15.2-87.7,22.6s-59.1,14.5-88.4,21.3l-.8.2-.8-.2-349.5-78-1.1-.2-8.7-1.9,8.6-2.3,150.6-41.5.6-.2h.7c62.5,11.7,125.5,23.6,188.4,35.9s125.6,25.1,188,37.6c8,1.6,11.9,3,10.4,3a185.6,185.6,0,0,1-18.4-2.6c-61.9-11.2-123.6-22.2-185-33.5s-122.7-23.1-184.4-35h1.2L104.4,273.4h-.1v-4.3l351.2,75.7h-1.5c28.3-6.7,56.3-13.3,84.3-19.5s56.5-12,85.2-18.1C631.3,305.6,640.4,304.1,641.9,304.1Z"
fill="#231f20"></path>
</g>
<g id="laptop__keyboard">
<polygon
points="371.1 274.8 256.8 253.5 257 252.7 266.2 251.1 382.4 271.5 382.3 272.3 371.1 274.8"
fill="#3e3e54"></polygon>
<polygon
points="237.4 265.6 221.3 262.4 221.4 261.7 230.2 260.2 246.8 262.6 246.6 263.4 237.4 265.6"
fill="#3e3e54"></polygon>
<polygon
points="474.6 312.9 249.9 268.1 250.1 267.3 259.2 265.8 487.7 309.6 487.5 310.5 474.6 312.9"
fill="#3e3e54"></polygon>
<polygon
points="411.8 309.4 204.2 266.7 204.4 266 212.9 264.5 423.9 306.3 423.7 307.2 411.8 309.4"
fill="#3e3e54"></polygon>
<polygon points="450 317.3 428.5 312.9 428.8 312 440.7 310.6 462.7 314.1 462.5 315 450 317.3"
fill="#3e3e54"></polygon>
<polygon
points="201.6 273.9 187.5 270.9 187.7 270.2 196 268.7 210.4 271 210.3 271.7 201.6 273.9"
fill="#3e3e54"></polygon>
<polygon
points="222.6 278.3 208.1 275.3 208.3 274.5 216.9 273.1 231.8 275.4 231.6 276.2 222.6 278.3"
fill="#3e3e54"></polygon>
<polygon
points="362.9 308.1 231.5 280.2 231.7 279.5 240.7 278.1 374.2 305.1 374 305.9 362.9 308.1"
fill="#3e3e54"></polygon>
<polygon
points="444.3 288.4 385.2 277.4 385.4 276.5 396.6 274.9 456.9 285.1 456.7 285.9 444.3 288.4"
fill="#3e3e54"></polygon>
<polygon
points="526.1 303.6 460.1 291.3 460.3 290.4 472.8 288.9 540.1 300.2 539.9 301.1 526.1 303.6"
fill="#3e3e54"></polygon>
<polygon
points="426.2 321.6 376.1 310.9 376.3 310.1 387.4 308.7 438.5 318.5 438.3 319.4 426.2 321.6"
fill="#3e3e54"></polygon>
<g>
<polygon
points="410.6 286.5 399.1 288 398.9 288.8 499.9 308.3 513.3 305.9 513.5 305 410.6 286.5"
fill="#3e3e54"></polygon>
<polygon
points="395.7 283.7 395.9 282.8 248.2 255.7 239.2 257.3 239 258 384.3 286 395.7 283.7"
fill="#3e3e54"></polygon>
</g>
<polygon points="371.3 273.9 256.9 252.7 266.4 250.3 382.4 271.5 371.3 273.9" stroke="#000"
stroke-linecap="round" stroke-linejoin="round" stroke-width="1.2"></polygon>
<polygon points="237.6 264.9 221.4 261.7 230.4 259.4 246.8 262.6 237.6 264.9" stroke="#000"
stroke-linecap="round" stroke-linejoin="round" stroke-width="1.2"></polygon>
<polygon points="474.8 312 250 267.3 259.4 265.1 487.7 309.6 474.8 312" stroke="#000"
stroke-linecap="round" stroke-linejoin="round" stroke-width="1.2"></polygon>
<polygon points="412 308.5 204.4 266 213.1 263.8 423.9 306.3 412 308.5" stroke="#000"
stroke-linecap="round" stroke-linejoin="round" stroke-width="1.2"></polygon>
<polygon points="450.2 316.4 428.8 312 440.9 309.7 462.8 314.1 450.2 316.4" stroke="#000"
stroke-linecap="round" stroke-linejoin="round" stroke-width="1.2"></polygon>
<polygon points="201.7 273.1 187.7 270.2 196.2 268 210.4 271 201.7 273.1" stroke="#000"
stroke-linecap="round" stroke-linejoin="round" stroke-width="1.2"></polygon>
<polygon points="222.8 277.6 208.3 274.5 217.1 272.4 231.8 275.4 222.8 277.6" stroke="#000"
stroke-linecap="round" stroke-linejoin="round" stroke-width="1.2"></polygon>
<polygon points="363.1 307.3 231.7 279.5 240.9 277.3 374.2 305.1 363.1 307.3" stroke="#000"
stroke-linecap="round" stroke-linejoin="round" stroke-width="1.2"></polygon>
<polygon points="444.6 287.5 385.4 276.5 396.8 274.1 456.9 285 444.6 287.5" stroke="#000"
stroke-linecap="round" stroke-linejoin="round" stroke-width="1.2"></polygon>
<polygon points="526.3 302.7 460.3 290.4 473 288 540.1 300.2 526.3 302.7" stroke="#000"
stroke-linecap="round" stroke-linejoin="round" stroke-width="1.2"></polygon>
<polygon points="426.4 320.7 376.3 310.1 387.6 307.9 438.5 318.5 426.4 320.7" stroke="#000"
stroke-linecap="round" stroke-linejoin="round" stroke-width="1.2"></polygon>
<g>
<polygon points="410.7 285.6 399.1 288 500.1 307.4 513.5 305 410.7 285.6" stroke="#000"
stroke-linecap="round" stroke-linejoin="round" stroke-width="1.2"></polygon>
<polygon points="395.9 282.8 248.4 255 239.2 257.3 384.5 285.2 395.9 282.8" stroke="#000"
stroke-linecap="round" stroke-linejoin="round" stroke-width="1.2">
</polygon>
</g>
</g>
<g id="paw-right">
<g id="paw-right--down">
<path
d="M293.2,191.3l10-7s-18.4,11.1-24,20-13,20.4-9,31c4.7,12.4,20.5,15.7,22,16,20,3.8,47.8-24.3,47.8-24.3s1.9-3.3,2.2-3.7"
fill="#fff"></path>
<path
d="M342.1,223.4c.9,1.2.2,2.8-.3,3.7l-.4.7-.3.3a118.1,118.1,0,0,1-14.2,12.3,83.2,83.2,0,0,1-16.2,9.8,43.9,43.9,0,0,1-9.3,3,26.3,26.3,0,0,1-10.1.2,44.5,44.5,0,0,1-9.3-3.2,34.2,34.2,0,0,1-8.3-5.5,23,23,0,0,1-5.8-8.5,21.3,21.3,0,0,1-1.3-10.3,34.9,34.9,0,0,1,2.7-9.7,76.1,76.1,0,0,1,4.5-8.5l2.4-4,.6-1,.8-1.1a15.6,15.6,0,0,1,1.6-2,49.9,49.9,0,0,1,7-6.8,136.1,136.1,0,0,1,15.3-11.2,3.1,3.1,0,0,1,4.4,1,3,3,0,0,1-.8,4.2H305l-8.6,6.2c-.9.6-2.7-.5-3.1-1.9s.5-4.4,1.5-5l6.6-4.5,3.5,5.3A131.9,131.9,0,0,0,290,197.4a52.7,52.7,0,0,0-6.4,6,6.5,6.5,0,0,0-1.3,1.6l-.6.8-.7,1-2.4,3.8c-1.6,2.6-3.1,5.2-4.4,7.8a27.7,27.7,0,0,0-2.4,8.1,15.6,15.6,0,0,0,.8,8,17.4,17.4,0,0,0,4.4,6.7,27.2,27.2,0,0,0,7.1,4.9,39.5,39.5,0,0,0,8.1,3,21.6,21.6,0,0,0,8.4,0,37.8,37.8,0,0,0,8.5-2.6,84.9,84.9,0,0,0,15.7-9,142.4,142.4,0,0,0,14.1-11.6l-.3.3,1.1-1.8C340.3,223.4,341.3,222.2,342.1,223.4Z">
</path>
</g>
<g id="paw-right--up">
<g>
<path
d="M282.2,215.2c-1.6-1.6-12.8-17.9-14-34.3-.1-2.5,1.7-16,12.9-22.4s22.3-1.9,26.2.4c12.2,7.3,21.2,19.1,22.8,22.4"
fill="#fff"></path>
<path
d="M330,181.2a2.4,2.4,0,0,1-2.6-1.3,71.4,71.4,0,0,0-9.8-10.8,64,64,0,0,0-11.7-8.6,26.3,26.3,0,0,0-6.5-2.3,26.9,26.9,0,0,0-6.9-.6,24.9,24.9,0,0,0-6.7,1.3,20.8,20.8,0,0,0-5.8,3.3,23.1,23.1,0,0,0-7.6,11,32.5,32.5,0,0,0-1.4,6.6,6.6,6.6,0,0,0,.1,1.4l.2,1.8c.1,1.2.4,2.3.6,3.5a65,65,0,0,0,4.8,13.4c1,2.2,2.2,4.3,3.4,6.4a43.1,43.1,0,0,0,3.9,5.9.6.6,0,0,1,0,.6c0,.2-.2.4-.4.7a5.7,5.7,0,0,1-1.5,1.6c-1.3.6-4.1.1-4.6-.6a89.5,89.5,0,0,1-7.2-13.7,63.7,63.7,0,0,1-4.3-14.9,25.7,25.7,0,0,1-.5-4c0-.3-.1-.6-.1-1v-1.2a12.5,12.5,0,0,1,.2-2.1,35.2,35.2,0,0,1,2.4-7.8,28.6,28.6,0,0,1,4.1-6.9,24.6,24.6,0,0,1,6.1-5.5,26.2,26.2,0,0,1,15.5-4.2,28.9,28.9,0,0,1,7.8,1.2l3.8,1.3,1.8.9,1.8,1a78.2,78.2,0,0,1,11.9,9.6,80.2,80.2,0,0,1,9.7,11.8C331.1,179.7,331.4,181,330,181.2Z">
</path>
</g>
<use width="31.4" height="33.93" transform="translate(273.2 166.1) rotate(-5.6)"
xlink:href="#paw-pads"></use>
</g>
</g>
<g id="laptop__terminal">
<path
d="M316.9,238.7,153.5,205.2a5.1,5.1,0,0,1-4-3.5L109.8,75.4c-1-3.3,1.9-6.6,5.6-6.3L277.9,84.5a5.2,5.2,0,0,1,4.6,3.7l40.7,144.4C324.2,236.2,320.8,239.5,316.9,238.7Z">
</path>
<path
d="M317.3,238.7a7.9,7.9,0,0,0,2.2-.7,5,5,0,0,0,2.2-1.9,3.7,3.7,0,0,0,.6-2.9l-.3-.8-.2-.9a15.4,15.4,0,0,1-.5-1.7L300,154.6l-10.7-37.5L284,98.3l-2.6-9.4a7.9,7.9,0,0,0-.4-.9,4.3,4.3,0,0,0-.4-.7,3.3,3.3,0,0,0-1.5-1.1l-.9-.3h-1.1l-2.4-.2L119.2,71.2l-2.4-.3h-2.2a3.3,3.3,0,0,0-2.8,1.6,2.4,2.4,0,0,0-.5,1.4v.8c.1.1.1.2.1.4l.2.6,1.5,4.6L119,98.8l11.8,37.3,11.7,37.2,5.9,18.6,2.9,9.3a3.4,3.4,0,0,0,2.2,2h1l1.2.3,2.4.4,153,31.1c4.3.9,7.4,2.9,5.2,3.3s-11.7-.1-16-1l-75.8-15.7L186.6,214l-19-3.9-9.5-2-4.7-1h-.7l-.8-.3a6.1,6.1,0,0,1-1.4-.7,7.6,7.6,0,0,1-2.3-2.4l-.4-.8a1.9,1.9,0,0,1-.2-.7l-.4-1.2-.7-2.3-1.4-4.6-2.9-9.2-5.8-18.5-11.5-36.9-11.5-37-2.9-9.2L109,78.5l-.7-2.3v-.6c0-.3-.1-.6-.1-.8a4.8,4.8,0,0,1,0-1.7,6.8,6.8,0,0,1,3.8-5,10.1,10.1,0,0,1,3-.7h2.6l9.6,1L204.1,76l38.5,3.7,19.3,1.9,9.6.9,4.8.5h2.6a6.6,6.6,0,0,1,2.7,1.2,7.2,7.2,0,0,1,1.9,2.4,12.1,12.1,0,0,1,.5,1.4l.3,1.1,1.3,4.7,2.6,9.3,5.2,18.6,10.4,37.3,10.4,37.3,5.3,18.6,2.6,9.4,1.3,4.6.6,2.4a7,7,0,0,1,.4,2.7,5.7,5.7,0,0,1-1.8,3.7,5.9,5.9,0,0,1-3.4,1.6,3.5,3.5,0,0,1-2.1-.4C316.7,239,316.8,238.9,317.3,238.7Z">
</path>
</g>
<g id="laptop__terminal_code_scene">
<g id="laptop__code">
<g stroke="#3DE0E8" stroke-width="6" transform="matrix(-1 0 0 1 278 103)">
<g id="f3" transform="translate(0 76)">
<path class="typing-animation" id="f3-l9" d="M8,25L8,25" stroke-dasharray="60,10">
</path>
<path class="typing-animation" id="f3-l8" d="M8,13L8,13" stroke-dasharray="50,10">
</path>
<path class="typing-animation" id="f3-l7" d="M0,1L0,1" stroke-dasharray="25,10">
</path>
</g>
<g id="f2" transform="translate(0 38)">
<path class="typing-animation" id="f2-l6" d="M8,25L8,25" stroke-dasharray="40,10">
</path>
<path class="typing-animation" id="f2-l5" d="M8,13L8,13" stroke-dasharray="60,10">
</path>
<path class="typing-animation" id="f2-l4" d="M0,1L0,1" stroke-dasharray="30,10">
</path>
</g>
<g id="f1">
<path class="typing-animation" id="f1-l3" d="M8,25L8,25" stroke-dasharray="60,10">
</path>
<path class="typing-animation" id="f1-l2" d="M8,13L8,13" stroke-dasharray="60,10">
</path>
<path class="typing-animation" id="f1-l1" d="M0,1L0,1" stroke-dasharray="60,10">
</path>
</g>
</g>
</g>
</g>
<g id="laptop__cover" style="mix-blend-mode: hard-light">
<polygon points="440.7 347.2 90.3 275.6 4.7 3.8 353 36.7 440.7 347.2" fill="#f2f2f2">
</polygon>
<path
d="M440.4,346.4c-2.5-5.3-6.5-18.8-9-27.4L390.7,178c-13.6-46.8-26.9-93.7-40.3-140.6l2.3,2L4.4,7.1,7.9,2.8,94,274.5l-2.9-2.6q83.7,16.8,166.8,34.2t166.8,35.4c8.8,1.9,17.5,5.1,14.7,5.5s-6.3-.2-12-.9-12.3-1.5-16.8-2.3Q330.5,328.1,250,312.1c-53.5-10.8-107.1-21.7-160.4-32.7l-2.3-.5-.6-2.1L1.5,4.8,0,0,5,.5,353.3,34l1.8.2.5,1.8q20.7,73.8,41.2,147.8l40.6,147.5C439.8,340.1,442.9,351.7,440.4,346.4Z">
</path>
</g>
</g>
<g id="paw-left">
<g id="paw-left--up">
<g>
<path
d="M545.4,261.9c-7.1-13-12.9-31.1-13.3-37.6-.6-9,0-15.6,5.2-22.2s15-9.8,22.7-8.8a26.7,26.7,0,0,1,17.3,9.4c5.3,5.8,9.4,12.9,11.6,16.6"
fill="#fff"></path>
<path
d="M588.9,219.2c-1.4.4-2.3-.7-2.8-1.4a93.9,93.9,0,0,0-8.9-12.5c-3.3-3.9-7.1-7-11.7-8.6a24.2,24.2,0,0,0-7.1-1.4,24.5,24.5,0,0,0-7.1.7,27,27,0,0,0-6.6,2.7,21,21,0,0,0-5.2,4.6,20.6,20.6,0,0,0-3.5,6.1,22.2,22.2,0,0,0-1.3,6.9,47.3,47.3,0,0,0,.1,7.5,52.2,52.2,0,0,0,1.4,7.1c1.4,4.8,3.1,9.7,5,14.4a147.7,147.7,0,0,0,6.5,13.9c.4.7-1,2.3-2.4,2.6s-4-.6-4.4-1.4c-2.3-4.8-4.3-9.7-6.1-14.6a128.8,128.8,0,0,1-4.6-15.3c-.3-1.3-.5-2.6-.7-4a16.4,16.4,0,0,1-.2-2.2v-2a57,57,0,0,1,.4-8.2,27.2,27.2,0,0,1,2.3-8.2c.7-1.3,1.4-2.5,2.2-3.7l1.3-1.7,1.4-1.6a28.8,28.8,0,0,1,7-5,27.6,27.6,0,0,1,8-2.5,25.6,25.6,0,0,1,8.3-.2,27.4,27.4,0,0,1,15.1,6.7,50.6,50.6,0,0,1,5.5,5.9,111.3,111.3,0,0,1,8.7,13.2C589.8,217.7,590.3,218.9,588.9,219.2Z">
</path>
</g>
<use width="31.4" height="33.93" transform="matrix(0.99, -0.03, 0.04, 1, 539.85, 203.52)"
xlink:href="#paw-pads"></use>
</g>
<g id="paw-left--down">
<path
d="M538.2,239.3c-3.2,1.6-33,10.8-37,28-.4,1.8-2.1,18.9,7,26,5.5,4.3,12.7,2.8,25,0,10.3-2.3,19-5.8,40-16,9.1-4.4,16.6-8.2,22-11"
fill="#fff"></path>
<path
d="M595.1,266.4c.1,1.4-1.4,2.4-2.4,2.9l-18.3,9.4c-6.2,3.1-12.3,6.1-18.6,9a120.8,120.8,0,0,1-19.6,7.2l-5.1,1.2-5.1,1.1a43.4,43.4,0,0,1-5.2.9,33.8,33.8,0,0,1-5.6.3,17.8,17.8,0,0,1-5.8-1.5,6.1,6.1,0,0,1-1.4-.7l-1.3-.9-2.2-2a23.6,23.6,0,0,1-5.2-10.2,44.5,44.5,0,0,1-1.3-10.9c0-.9.1-1.8.1-2.7a6.6,6.6,0,0,0,.1-1.4v-.7c.1-.3.1-.7.2-.9a21.6,21.6,0,0,1,2.1-5.5,33.4,33.4,0,0,1,7.1-8.7,67.1,67.1,0,0,1,8.7-6.4,121.7,121.7,0,0,1,19-9,1.5,1.5,0,0,1,1.7.6,3.4,3.4,0,0,1,.9,1.9c.1,1.5-1.6,4.2-2.6,4.6a91.1,91.1,0,0,0-17.8,8.5,40.1,40.1,0,0,0-7.6,5.8,22.8,22.8,0,0,0-5.2,7.3l-.4,1-.3,1a1.7,1.7,0,0,0-.2.5v.4c-.1.4-.1.8-.2,1.2s-.1,3.1-.1,4.7a35.4,35.4,0,0,0,1.4,9.3,15.6,15.6,0,0,0,4.5,7.3c2,1.9,4.7,2.6,7.8,2.5a55.9,55.9,0,0,0,9.7-1.2l4.9-1.1,4.9-1.1a121,121,0,0,0,18.8-6.8c12.4-5.3,24.6-11.5,36.8-17.4C593.4,265.4,595,264.9,595.1,266.4Z">
</path>
</g>
</g>
</svg>
</div>
</div>
<!-- You can also require other files to run in this process -->
<script src="./renderer.js"></script>
<script src="./function.js"></script>
</body>
<!-- Copyright (c) 2022 by Anika Sharma (https://codepen.io/arff/pen/pojMymP)
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -->
</html>
/* style.css */
html,
body {
margin: 0;
padding: 0;
height: 100vh;
width: 100vw;
overflow: hidden;
background-color: beige;
}
ul {
list-style: none;
}
button {
background: none;
border: none;
}
.app {
height: 100vh;
width: 100vw;
}
.hidden {
display: none;
}
.container {
top: 0;
bottom: 0;
left: 0;
right: 0;
}
.center {
text-align: center;
}
#login {
margin-top: 20vh;
}
.todos {
margin-top: 0;
}
#todo-form #todo-input {
height: 5vh;
}
#submit-input {
border: none;
background-color: beige;
font-size: large;
margin-top: 20px;
}
#submit-input:hover {
border: 1px solid bisque;
}
#name-input {
height: 4vh;
}
input::-webkit-input-placeholder {
text-align: center;
}
input::-moz-placeholder {
text-align: center;
}
input:-ms-input-placeholder {
text-align: center;
}
input:-moz-placeholder {
text-align: center;
}
input::placeholder {
text-align: center;
}
#name-input,
#todo-input {
width: 50vw;
border: none;
border-radius: 5px;
}
#bongo-cat {
position: absolute;
height: 40vh;
width: 40vw;
top: 70vh;
bottom: 0;
left: 0;
right: 0;
margin: auto;
}
.typing-animation {
-webkit-animation-timing-function: linear;
animation-timing-function: linear;
-webkit-animation-iteration-count: infinite;
animation-iteration-count: infinite;
-webkit-animation-duration: 1200ms;
animation-duration: 1200ms;
}
path#f1-l1 {
-webkit-animation-name: typing-f1-l1;
animation-name: typing-f1-l1;
}
path#f1-l2 {
-webkit-animation-name: typing-f1-l2;
animation-name: typing-f1-l2;
}
path#f1-l3 {
-webkit-animation-name: typing-f1-l3;
animation-name: typing-f1-l3;
}
path#f2-l4 {
-webkit-animation-name: typing-f2-l4;
animation-name: typing-f2-l4;
}
path#f2-l5 {
-webkit-animation-name: typing-f2-l5;
animation-name: typing-f2-l5;
}
path#f2-l6 {
-webkit-animation-name: typing-f2-l6;
animation-name: typing-f2-l6;
}
path#f3-l7 {
-webkit-animation-name: typing-f3-l7;
animation-name: typing-f3-l7;
}
path#f3-l8 {
-webkit-animation-name: typing-f3-l8;
animation-name: typing-f3-l8;
}
path#f3-l9 {
-webkit-animation-name: typing-f3-l9;
animation-name: typing-f3-l9;
}
@-webkit-keyframes typing-f3-l9 {
0% {
d: path("M8,25L8,25");
}
82% {
d: path("M8,25L8,25");
}
92% {
d: path("M8,25L96,25");
}
100% {
d: path("M8,25L96,25");
}
}
@keyframes typing-f3-l9 {
0% {
d: path("M8,25L8,25");
}
82% {
d: path("M8,25L8,25");
}
92% {
d: path("M8,25L96,25");
}
100% {
d: path("M8,25L96,25");
}
}
@-webkit-keyframes typing-f3-l8 {
0% {
d: path("M8,13L8,13");
}
68% {
d: path("M8,13L8,13");
}
82% {
d: path("M8,13L146,13");
}
100% {
d: path("M8,13L146,13");
}
}
@keyframes typing-f3-l8 {
0% {
d: path("M8,13L8,13");
}
68% {
d: path("M8,13L8,13");
}
82% {
d: path("M8,13L146,13");
}
100% {
d: path("M8,13L146,13");
}
}
@-webkit-keyframes typing-f3-l7 {
0% {
d: path("M0,1L0,1");
}
60% {
d: path("M0,1L0,1");
}
68% {
d: path("M0,1L96,1");
}
100% {
d: path("M0,1L96,1");
}
}
@keyframes typing-f3-l7 {
0% {
d: path("M0,1L0,1");
}
60% {
d: path("M0,1L0,1");
}
68% {
d: path("M0,1L96,1");
}
100% {
d: path("M0,1L96,1");
}
}
@-webkit-keyframes typing-f2-l6 {
0% {
d: path("M8,25L8,25");
}
54% {
d: path("M8,25L8,25");
}
60% {
d: path("M8,25L69,25");
}
100% {
d: path("M8,25L69,25");
}
}
@keyframes typing-f2-l6 {
0% {
d: path("M8,25L8,25");
}
54% {
d: path("M8,25L8,25");
}
60% {
d: path("M8,25L69,25");
}
100% {
d: path("M8,25L69,25");
}
}
@-webkit-keyframes typing-f2-l5 {
0% {
d: path("M8,13L8,13");
}
44% {
d: path("M8,13L8,13");
}
54% {
d: path("M8,13L114,13");
}
100% {
d: path("M8,13L114,13");
}
}
@keyframes typing-f2-l5 {
0% {
d: path("M8,13L8,13");
}
44% {
d: path("M8,13L8,13");
}
54% {
d: path("M8,13L114,13");
}
100% {
d: path("M8,13L114,13");
}
}
@-webkit-keyframes typing-f2-l4 {
0% {
d: path("M0,1L0,1");
}
30% {
d: path("M0,1L0,1");
}
44% {
d: path("M0,1L136,1");
}
100% {
d: path("M0,1L136,1");
}
}
@keyframes typing-f2-l4 {
0% {
d: path("M0,1L0,1");
}
30% {
d: path("M0,1L0,1");
}
44% {
d: path("M0,1L136,1");
}
100% {
d: path("M0,1L136,1");
}
}
@-webkit-keyframes typing-f1-l3 {
0% {
d: path("M8,25L8,25");
}
24% {
d: path("M8,25L8,25");
}
30% {
d: path("M8,25L61,25");
}
100% {
d: path("M8,25L61,25");
}
}
@keyframes typing-f1-l3 {
0% {
d: path("M8,25L8,25");
}
24% {
d: path("M8,25L8,25");
}
30% {
d: path("M8,25L61,25");
}
100% {
d: path("M8,25L61,25");
}
}
@-webkit-keyframes typing-f1-l2 {
0% {
d: path("M8,13L8,13");
}
14% {
d: path("M8,13L8,13");
}
24% {
d: path("M8,13L124,13");
}
100% {
d: path("M8,13L124,13");
}
}
@keyframes typing-f1-l2 {
0% {
d: path("M8,13L8,13");
}
14% {
d: path("M8,13L8,13");
}
24% {
d: path("M8,13L124,13");
}
100% {
d: path("M8,13L124,13");
}
}
@-webkit-keyframes typing-f1-l1 {
0% {
d: path("M0,1L0,1");
}
14% {
d: path("M0,1L160,1");
}
100% {
d: path("M0,1L160,1");
}
}
@keyframes typing-f1-l1 {
0% {
d: path("M0,1L0,1");
}
14% {
d: path("M0,1L160,1");
}
100% {
d: path("M0,1L160,1");
}
}
#paw-right--up,
#paw-right--down,
#paw-left--up,
#paw-left--down {
-webkit-animation: blink 300ms infinite;
animation: blink 300ms infinite;
}
#paw-right--up,
#paw-left--down {
-webkit-animation-delay: 150ms;
animation-delay: 150ms;
}
@-webkit-keyframes blink {
0% {
opacity: 0;
}
49% {
opacity: 0;
}
50% {
opacity: 1;
}
}
@keyframes blink {
0% {
opacity: 0;
}
49% {
opacity: 0;
}
50% {
opacity: 1;
}
}
#laptop__code {
transform: rotateX(-37deg) rotateY(-46deg) rotateZ(-23deg) translateX(8px)
translateY(20px) translateZ(-50px);
}
어찌저찌 개발하다 보니 계획이 많이 수정되었다. preload.js나 renderer.js는 사용하지도 않고 정말 웹 앱을 그대로 데스크탑 앱으로 옮겼다.
//function.js
const loginForm = document.querySelector("#login");
const loginInput = document.querySelector("#login-form input");
const greeting = document.querySelector("#greeting");
const toDoForm = document.querySelector("#todo-form");
const toDoInput = toDoForm.querySelector("input");
const toDoList = document.getElementById("todo-list");
const HIDDEN_CLASSNAME = "hidden";
const USERNAME_KEY = "username";
const TODOS_KEY = "todos";
function onLoginSubmit(event) {
event.preventDefault();
loginForm.classList.add(HIDDEN_CLASSNAME);
const username = loginInput.value;
localStorage.setItem("username", username);
localStorage.setItem(USERNAME_KEY, username);
paintGreetings(username);
}
function paintGreetings(username) {
greeting.innerText = `Hello ${username}.`;
greeting.classList.remove(HIDDEN_CLASSNAME);
toDoForm.classList.remove(HIDDEN_CLASSNAME);
}
loginForm.addEventListener("submit", onLoginSubmit);
const savedUsername = localStorage.getItem(USERNAME_KEY);
if (savedUsername === null) {
loginForm.classList.remove(HIDDEN_CLASSNAME);
loginForm.addEventListener("submit", onLoginSubmit);
} else {
paintGreetings(savedUsername);
}
const clock = document.querySelector("h1#clock");
const getClock = () => {
const date = new Date();
const hour = String(date.getHours()).padStart(2, "0");
const min = String(date.getMinutes()).padStart(2, "0");
const sec = String(date.getSeconds()).padStart(2, "0");
clock.innerText = `${hour}:${min}:${sec}`;
};
getClock();
setInterval(getClock, 1000);
let toDos = [];
const saveToDos = () => {
localStorage.setItem(TODOS_KEY, JSON.stringify(toDos));
};
const deleteToDo = (event) => {
const li = event.target.parentElement;
li.remove();
toDos = toDos.filter((toDo) => toDo.id !== parseInt(li.id));
saveToDos();
};
const paintToDo = (newTodo) => {
const li = document.createElement("li");
li.id = newTodo.id;
const span = document.createElement("span");
span.innerText = newTodo.text;
const button = document.createElement("button");
button.innerText = "X";
button.addEventListener("click", deleteToDo);
li.appendChild(span);
li.appendChild(button);
toDoList.appendChild(li);
};
const handleToDoSubmit = (event) => {
event.preventDefault();
const newTodo = toDoInput.value;
toDoInput.value = "";
const newTodoObj = {
text: newTodo,
id: Date.now(),
};
toDos.push(newTodoObj);
paintToDo(newTodoObj);
saveToDos();
};
toDoForm.addEventListener("submit", handleToDoSubmit);
const savedTodos = localStorage.getItem(TODOS_KEY);
if (savedTodos) {
const parsedToDos = JSON.parse(savedTodos);
toDos = parsedToDos;
parsedToDos.forEach(paintToDo);
}
앱의 고양이는 개인적으로 좋아하는 동물이라 넣어보았다.
이제 만든 앱을 배포해보자.
터미널에 아래 명령어를 입력하여 electron-builder를 설치하자.
npm i --save-dev electron-builder
배포와 관련한 옵션을 package.json에 추가한다.
{
"name": "todo",
"version": "1.0.0",
"description": "Todo App with electron",
"main": "main.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"start": "electron .",
"deploy:osx": "electron-builder --mac",
"deploy:win": "npm run deploy:win32 && npm run deploy:win64",
"deploy:win32": "electron-builder --win nsis:ia32",
"deploy:win64": "electron-builder --win nsis:x64"
},
"build": {
"productName": "ToDo With Nyan",
"appId": "net.jetalab.ex.startelectron",
"asar": true,
"mac": {
"target": [
"default"
]
},
"dmg": {
"title": "ToDo With Nyan"
},
"win": {
"target": [
{
"target": "nsis",
"arch": [
"x64",
"ia32"
]
}
]
},
"nsis": {
"oneClick": false,
"allowToChangeInstallationDirectory": false,
"createDesktopShortcut": true
},
"directories": {
"buildResources": "./resources/installer/",
"output": "./dist/",
"app": "."
}
},
"repository": {
"type": "git",
"url": "git+https://github.com/balhyo-younjisang/TodoApp.git"
},
"author": "balhyo-younjisang",
"license": "MIT",
"bugs": {
"url": "https://github.com/balhyo-younjisang/TodoApp/issues"
},
"homepage": "https://github.com/balhyo-younjisang/TodoApp#readme",
"devDependencies": {
"electron": "^22.0.0",
"electron-builder": "^23.6.0"
},
"dependencies": {
"bootstrap": "^5.2.3",
"electron-better-ipc": "^2.0.1",
"electron-localshortcut": "^3.2.1",
"electron-store": "^8.1.0"
}
}
9~12번째 줄: npm run 스크립트를 정의
14~47번째 줄: 배포를 위한 옵션을 정의
15번째 줄: Application 이름
16번째 줄: Application ID입니다. 도메인의 반대 순서를 관습적으로 사용
24번째 줄: dmg 파일을 열었을 때 제목 표시줄에 표시할 이름을 지정
29번째 줄: Nullsoft Scriptable Install System을 사용한다는 뜻입니다. 옛날 WinAmp 설치 프로그램
31~32번째 줄: 32bit와 64bit 아키텍쳐를 의미
42~45번째 줄: 배포와 관련된 리소스가 저장된 경로, 배포 파일을 만들어 저장할 경로 등을 지정
터미널에 아래 명령어를 입력하여 설치 프로그램을 생성하자.
npm run deploy:osx # macOS
npm run deploy:win # Windows 32bit & 64bit
npm run deploy:win32 # Windows 32bit
npm run deploy:win64 # Windows 64bit
macOS는 dmg, Windows는 exe로 생성된다.
'Programming Language > electron' 카테고리의 다른 글
[Electron] require is not defined 해결 방법 (0) | 2022.12.13 |
---|---|
[Electron] Electron을 사용하여 Desktop Todo App 만들기( 1 ) - Setup, Dark mode (0) | 2022.12.08 |