参考:
electron 网页TodoList工具打包成win桌面应用exe
https://blog.csdn.net/weixin_42357472/article/details/140648621
electron直接打包exe应用,打开网页上面添加的task在重启后为空,历史没有被保存,需要持久化工具保存之前的操作记录
这里测试用electron-store或electron-conf两个持久化工具运行都ESM报错:
https://zhuanlan.zhihu.com/p/706281785
解决方法:
直接使用 Node.js 的 fs 模块直接读写 JSON 文件。这样可以避免 ES modules 的问题。
1)electron配置文件
main.js
const { app, BrowserWindow, ipcMain } = require('electron')
const path = require('path')
const fs = require('fs')
const STORAGE_PATH = path.join(app.getPath('userData'), 'todos.json')
function saveTodos(todos) {
fs.writeFileSync(STORAGE_PATH, JSON.stringify(todos))
}
function loadTodos() {
try {
return JSON.parse(fs.readFileSync(STORAGE_PATH, 'utf8'))
} catch (error) {
return []
}
}
function createWindow () {
const win = new BrowserWindow({
width: 800,
height: 600,
webPreferences: {
nodeIntegration: true,
contextIsolation: false
}
})
win.loadFile('index.html')
}
app.whenReady().then(() => {
createWindow()
app.on('activate', () => {
if (BrowserWindow.getAllWindows().length === 0) {
createWindow()
}
})
})
app.on('window-all-closed', () => {
if (process.platform !== 'darwin') {
app.quit()
}
})
// 修改这些 IPC 处理器
ipcMain.on('save-todos', (event, todos) => {
saveTodos(todos)
})
ipcMain.handle('load-todos', () => {
return loadTodos()
})
package.json
{
"name": "todolist-app",
"version": "1.0.0",
"main": "main.js",
"build": {
"appId": "com.yourcompany.todolist",
"mac": {
"category": "public.app-category.productivity"
},
"win": {
"icon": "icons/icon.png",
"target": [
"nsis"
]
},
"linux": {
"target": [
"AppImage",
"deb"
]
}
},
"scripts": {
"start": "electron .",
"build": "electron-builder --win"
},
"keywords": [],
"author": "",
"license": "ISC",
"description": "",
"devDependencies": {
"electron": "^31.2.1",
"electron-builder": "^24.13.3"
},
"dependencies": {}
}
2)网页应用
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>TodoList</title>
<link rel="stylesheet" href="styles.css">
</head>
<body>
<h1>TodoList</h1>
<form id="todo-form">
<input type="text" id="todo-input" placeholder="Enter a new task" required>
<button type="submit" id="add-button">Add</button>
</form>
<ul id="todo-list"></ul>
<script src="script.js"></script>
</body>
</html>
styles.css
body {
font-family: Arial, sans-serif;
max-width: 500px;
margin: 0 auto;
padding: 20px;
}
h1 {
text-align: center;
}
#todo-form {
display: flex;
margin-bottom: 20px;
}
#todo-input {
flex-grow: 1;
padding: 10px;
font-size: 16px;
border: 1px solid #ddd;
border-radius: 4px 0 0 4px;
}
#add-button {
padding: 10px 20px;
font-size: 16px;
background-color: #4CAF50;
color: white;
border: none;
border-radius: 0 4px 4px 0;
cursor: pointer;
}
#todo-list {
list-style-type: none;
padding: 0;
}
.todo-item {
display: flex;
align-items: center;
padding: 10px;
background-color: #f9f9f9;
border: 1px solid #ddd;
margin-bottom: 10px;
border-radius: 4px;
}
.todo-item.completed {
text-decoration: line-through;
opacity: 0.6;
}
.todo-item input[type="checkbox"] {
margin-right: 10px;
}
.delete-button {
margin-left: auto;
background-color: #f44336;
color: white;
border: none;
padding: 5px 10px;
border-radius: 4px;
cursor: pointer;
}
script.js
const { ipcRenderer } = require('electron')
const todoForm = document.getElementById('todo-form')
const todoInput = document.getElementById('todo-input')
const todoList = document.getElementById('todo-list')
async function loadTodos() {
const todos = await ipcRenderer.invoke('load-todos')
todos.forEach(todo => {
addTodoToDOM(todo.text, todo.completed)
})
}
function saveTodos() {
const todos = Array.from(todoList.children).map(li => ({
text: li.querySelector('span').textContent,
completed: li.classList.contains('completed')
}))
ipcRenderer.send('save-todos', todos)
}
function addTodoToDOM(text, completed = false) {
const li = document.createElement('li')
li.className = 'todo-item' + (completed ? ' completed' : '')
li.innerHTML = `
<input type="checkbox" ${completed ? 'checked' : ''}>
<span>${text}</span>
<button class="delete-button">Delete</button>
`
li.querySelector('input[type="checkbox"]').addEventListener('change', function() {
li.classList.toggle('completed')
if (li.classList.contains('completed')) {
todoList.appendChild(li)
} else {
todoList.insertBefore(li, todoList.firstChild)
}
saveTodos()
})
li.querySelector('.delete-button').addEventListener('click', function() {
li.remove()
saveTodos()
})
if (completed) {
todoList.appendChild(li)
} else {
todoList.insertBefore(li, todoList.firstChild)
}
}
todoForm.addEventListener('submit', function(e) {
e.preventDefault()
if (todoInput.value.trim() === '') return
addTodoToDOM(todoInput.value)
saveTodos()
todoInput.value = ''
})
loadTodos()
打包:
npm run build
完成在dist下生产安装文件,及win-unpacked 无需安装的解压文件
点击exe运行即可