react+electron使应用窗口相互独立
听说99%的前端同学都来这里充电吖!
欢迎关注前端小北,我是亚北!
前两篇文章我们介绍了react+electron构建桌面应用和如何加载本地的静态资源。然后现在有个需求,是要使应用里的弹窗独立于主窗口,今天来实现这个需求。
在之前我们知道electron通过main.js这个文件里new一个BrowserWindow来新建一个窗口,同样的,这个应用的弹窗,也可以通过new一个BrowserWindow来新建:
const { app, BrowserWindow } = require('electron')
function createWindow () {
// 创建浏览器窗口
const win = new BrowserWindow({
width: 800,
height: 600,
webPreferences: {
nodeIntegration: true,
webSecurity: false,
preload: `${__dirname}/preLoad.js`
}
})
// 并且为你的应用加载index.html
win.loadURL(url.format({
pathname: path.join(__dirname, 'dist/index.html'),
protocol: 'file:',
slashes: true
}))
// 创建第二个窗口
const win2 = new BrowserWindow({
width: 400,
height: 300,
webPreferences: {
nodeIntegration: true,
webSecurity: false,
preload: `${__dirname}/preLoad.js`
}
})
}
到这里新的弹窗已经有了,那里面的内容要如何填充呢?我们可以参照第一个窗口的做法用win.loadURL()来决定加载html文件。但是react项目打完包只有一个index.html啊,新的窗口应该从哪里加载html呢。接下来我们就来解决这一问题。
首先,在config/webpack.config.js里找到entry。如果没有config文件夹需要先运行命令把我们的config配置文件给暴露出来:
npm run eject
如果你运行了之后报如下错误:
这是因为我们使用脚手架创建一个项目的时候,自动给我们增加了一个.gitignore文件,但是我们本地却没有文件仓库。需要在终端输入如下命令:
git add .
git commit -am "Save before ejecting"
就是用git将项目添加到我们的本地仓库,接下来再执行npm run eject就没有问题了。
然后项目下会多出两个文件夹,config和scripts,我们开发中一般只需关心config文件下的webpack.config.js,paths.js,webpackDevServer.config.js,其他多出来的文件不要管他。下面就是config/webpack.config.js里entry的代码:
这里面就只是显示index的路径,我们需要在config/paths.js里添加我们几个模块的路径:
module.exports = {
appIndexJs: resolveModule(resolveApp, 'src/index/index'),
// 添加的模块路径
appModalJs: resolveModule(resolveApp, 'src/Modal/index'),
}
修改config/webpack.config.js的entry为对象形式:
entry: {
index: [paths.appIndexJs, isEnvDevelopment && require.resolve('react-dev-utils/webpackHotDevClient')].filter(Boolean),
modal: [paths.appModalJs, isEnvDevelopment && require.resolve('react-dev-utils/webpackHotDevClient')].filter(Boolean)
},
添加html配置,同样在config/paths.js里面添加:
appHtml: resolveApp('public/index.html'),
// 新增的html
appModalHtml: resolveApp('public/modal.html'),
config/paths.js里完整的module.exports如下:
module.exports = {
dotenv: resolveApp('.env'),
appPath: resolveApp('.'),
appBuild: resolveApp('build'),
appPublic: resolveApp('public'),
appHtml: resolveApp('public/index.html'),
// 新增的html
appModalHtml: resolveApp('public/modal.html'),
appIndexJs: resolveModule(resolveApp, 'src/index'),
// 添加的模块路径
appModalJs: resolveModule(resolveApp, 'src/Modal/index'),
appPackageJson: resolveApp('package.json'),
appSrc: resolveApp('src'),
appTsConfig: resolveApp('tsconfig.json'),
appJsConfig: resolveApp('jsconfig.json'),
yarnLockFile: resolveApp('yarn.lock'),
testsSetup: resolveModule(resolveApp, 'src/setupTests'),
proxySetup: resolveApp('src/setupProxy.js'),
appNodeModules: resolveApp('node_modules'),
publicUrlOrPath,
};
在config/webpack.config.js里处理html,在plugins中将原来的HtmlWebpackPlugin进行配置修改,添加一个filename和chunks:
Object.assign(
{},
{
filename: 'index.html',// 添加filename
chunks: ['index'] //添加chunks
},
对之前配置的每个页面都复制一个改一下它的template和filename以及chunks:
new HtmlWebpackPlugin(
Object.assign(
{},
{
inject: true,
template: paths.appHtml,
filename: 'index.html',
chunks: ['index']
},
isEnvProduction
? {
minify: {
removeComments: true,
collapseWhitespace: true,
removeRedundantAttributes: true,
useShortDoctype: true,
removeEmptyAttributes: true,
removeStyleLinkTypeAttributes: true,
keepClosingSlash: true,
minifyJS: true,
minifyCSS: true,
minifyURLs: true,
},
}
: undefined
)
),
new HtmlWebpackPlugin(
Object.assign(
{},
{
inject: true,
template: paths.appTicketHtml,
filename: 'ticket.html',
chunks: ['ticket']
},
isEnvProduction
? {
minify: {
removeComments: true,
collapseWhitespace: true,
removeRedundantAttributes: true,
useShortDoctype: true,
removeEmptyAttributes: true,
removeStyleLinkTypeAttributes: true,
keepClosingSlash: true,
minifyJS: true,
minifyCSS: true,
minifyURLs: true,
},
}
: undefined
)
)
然后我们运行npm run build来对react项目进行打包。如果build后报Cannot read property 'filter' of undefined,那么就需要把new ManifestPlugin里的generate属性删掉,这个问题我不是很清楚,从网上也是只搜到了解决方案而没有搜到原因,如果有前端小伙伴明白其中的原因,希望可以指点一二,不胜感激!
至此,我们的react项目已经可以打包出两个html文件和其对应的资源了,我们就用win2.loadURL()使其拥有两个独立的窗口。如下:
// 创建第二个窗口
const win2 = new BrowserWindow({
width: 400,
height: 300,
webPreferences: {
nodeIntegration: true,
webSecurity: false,
preload: `${__dirname}/preLoad.js`
}
})
win2.loadURL(url.format({
pathname: path.join(__dirname, 'dist/index.html'),
protocol: 'file:',
slashes: true
}))
窗口相对独立了我们可以通过electron进程间通讯来控制两个窗口何时打开关闭,达到一个交互效果。当然了,如果要做更多页面也是可以的,我们可以继续优化webpack的配置,做到可以自动打包多个页面,这些我们将来再做介绍。
经过几天的更新,目前算是较为完整的实现了将一个基于react的web应用利用electron变成了一个桌面应用。中间也包含了很多由此引出的问题以及解决思路,当然也存在还没有搞明白的问题,技术略菜,欢迎各位前端小伙伴一起探讨...
- Linux网络工具之Ping命令
- Linux DNS之nslookup命令
- 【LEETCODE】模拟面试-108-Convert Sorted Array to Binary Search Tree
- javascript单线程环境实现真正的setTimeout
- 利用pipework与OVS构建跨主机容器网络
- Docker系列教程07-Dockerfile指令详解
- Docker系列教程06-实战:修改Nginx首页
- prompt() 方法,弹框带输入框
- Docker系列教程05-容器常用命令
- 数据分析利器-NumPy
- 【LEETCODE】模拟面试-134-Gas Station
- Docker系列教程17-默认bridge网络中配置DNS
- Docker系列教程16-network命令
- 【LEETCODE】模拟面试-206. Reverse Linked List
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- Hash 算法有哪些?
- Cordova 运行 Web 应用
- SSH 端口转发小结
- Hive实现自增序列及元数据问题
- 手工将项目升级至 Angular 9 记录
- 备份和恢复 timescaledb 的超级表 (hypertables)
- CVE-2020-14644 weblogic iiop反序列化漏洞
- Ubuntu 17.10 安装折腾记录
- charles工具使用
- 干货 | 从0到1,搭建一个体系完善的前端React组件库
- LeetCode 01两数之和&02两数相加
- 给GitHub "彩蛋" readme 生成自定义统计信息
- Android |《看完不忘系列》之okhttp
- pt-osc改表过程中的中文乱码问题
- Hive Query生命周期 —— 钩子(Hook)函数篇