前面的话
Electron可以让我们使用web开发的技术去开发跨平台的桌面端应用,我们熟悉的VSCode编译器就是使用Electron开发的。这篇文章介绍如何将Electron接入webpack。
主进程
- 启动一个electron应用从一个主进程开始。主进程的启动通过一个JavaScript入口文件实现的。
- 主进程启动后会一直驻留在后台运行,我们操作的窗口并不是主进程,而是由主进程新启动的窗口子进程
- 每一个窗口都是一个单独的网页进程,窗口之间需要借助主进程传递消息。
通过命令 npm init 生成的package.json文件中的main.js就是electron的一个主进程:
在man.js文件中写入下面的内容:
const { app, BrowserWindow } = require('electron')
// 保持对window对象的全局引用,如果不这么做的话,当JavaScript对象被
// 垃圾回收的时候,window对象将会自动的关闭
let win
function createWindow () {
// 创建浏览器窗口。
win = new BrowserWindow({
width: 800,
height: 600,
webPreferences: {
nodeIntegration: true
}
})
// 加载index.html文件
const indexPageURL = `./dist/index.html`;
win.loadFile(indexPageURL)
// 打开开发者工具
win.webContents.openDevTools()
// 当 window 被关闭,这个事件会被触发。
win.on('closed', () => {
// 取消引用 window 对象,如果你的应用支持多窗口的话,
// 通常会把多个 window 对象存放在一个数组里面,
// 与此同时,你应该删除相应的元素。
win = null
})
}
// Electron 会在初始化后并准备
// 创建浏览器窗口时,调用这个函数。
// 部分 API 在 ready 事件触发后才能使用。
app.on('ready', createWindow)
// 当全部窗口关闭时退出。
app.on('window-all-closed', () => {
// 在 macOS 上,除非用户用 Cmd + Q 确定地退出,
// 否则绝大部分应用及其菜单栏会保持激活。
if (process.platform !== 'darwin') {
app.quit()
}
})
app.on('activate', () => {
// 在macOS上,当单击dock图标并且没有其他窗口打开时,
// 通常在应用程序中重新创建一个窗口。
if (win === null) {
createWindow()
}
})
注意: electron升级到5.0系列之后,如果不加上下面的代码就会报出require is not defined的错误,这是因为浏览器本生是不支持require。而5.0将以前版本默认的 nodeIntegration: true改为了false,所以我们要手动开启。
webPreferences: {
nodeIntegration: true, // 解决require is not defined问题
webviewTag: true // 解决webview无法显示问题
}
主进程中打开了一个dis目录下的index.html文件,这是使用webpack自动生成的页面,前面的文章已经介绍过,这里不过多解释。
接入webpack
一个简单的Electron应用,要求在启动后显示一个主窗口,在主窗口里面有一个按钮,点击这个按钮会重新显示一个窗口。
这个例子是基于前面的管理多个页面中的列子来实现的,这里创建了两个页面,一个主窗口,一个login窗口。
使用插件AutoWebPlugin可以自动生成相应的index.html与login.html。(前面已经介绍过)。
在index.js中:创建一个点击按钮,并且点击之后生成一个新的登录窗口:
import React, { Component } from 'react';
import { render } from 'react-dom';
import { remote } from 'electron';
import path from 'path';
import './index.css';
class App extends Component {
// 在按钮被点击时
handleBtnClick() {
// 新窗口对应的页面的 URI 地址
const modalPath = path.join('file://', remote.app.getAppPath(), 'dist/login.html');
// 新窗口的大小
let win = new remote.BrowserWindow({
width: 400,
height: 320,
webPreferences: {
nodeIntegration: true, // 解决require is not defined问题
webviewTag: true // 解决webview无法显示问题
}
})
win.on('close', function () {
// 窗口被关闭时清空资源
win = null
})
// 加载网页
win.loadURL(modalPath);
// 显示窗口
win.show()
}
render() {
return (
<div>
<h1>Page Index</h1>
<button onClick={this.handleBtnClick}>Open Page Login</button>
</div>
)
}
}
render(<App/>, window.document.getElementById('app'));
webpack配置文件:
const path = require('path');
const { AutoWebPlugin } = require('web-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
// 使用AutoWebPlugin自动寻找pages目录下的所有目录,将每一个目录看成一个单页应用
const autoWebPlugin = new AutoWebPlugin('page', {
template: './template.html', // HTML模板文件所在的文件路径
postEntrys:['./common.css'],// 所有的页面都依赖的共用的css样式文件
// 提取所有页面的公共代码
commonsChunk: {
name: 'common'// 提取出公共代码的Chunk名称
}
});
module.exports = {
// AutoWebPlugin会为寻找到的所有单页应用生成对应的入口配置
// autoWebPlugin.entry方法可以获取所有由autoWebPlugin生成的入口配置
entry: autoWebPlugin.entry({
}),
// 构建出用于 Electron 渲染进程用的 JavaScript 代码,也就是这2个窗口需要的代码
target: 'electron-renderer',
output:{
filename: '[name]_[chunkhash:8].js',
path: path.resolve(__dirname, './dist'),
},
module: {
rules: [
{
test: /\.js$/,
use:['babel-loader'],
exclude: path.resolve(__dirname, 'node_modules'),
},
{
test: /\.css/,
use: [
MiniCssExtractPlugin.loader,
'css-loader'
]
}
]
},
plugins: [
autoWebPlugin,
new MiniCssExtractPlugin({
filename: '[name]_[contenthash:8].css'
})
]
}
完成这两个页面相应的代码之后,由于webpack内置支持electon,只需要在Webpackp配置文件中加一行代码:
target:'electron-renderer',
运行项目
完整的项目地址: electron
$ npm install
$ webpack
$ npm start