翻译 | 《JavaScript Everywhere》第19章 将现有的Web应用程序与Electron集成
写在最前面
大家好呀,我是毛小悠,是一位前端开发工程师。正在翻译一本英文技术书籍。
为了提高大家的阅读体验,对语句的结构和内容略有调整。如果发现本文中有存在瑕疵的地方,或者你有任何意见或者建议,可以在评论区留言,或者加我的微信:code
_maomao,欢迎相互沟通交流学习。
(σ゚∀゚)σ..:*☆哎哟不错哦
第19章 将现有的Web应用程序与Electron集成
我喜欢收集浏览器书签,就像一个小孩在沙滩上收集贝壳一样。我不是一定要收集它们,但是到一天结束时,我已经在几个浏览器窗口中打开了许多选项卡。我并不是炫耀,但我怀疑应该不止我一个人是这样。所以,我使用了一些最常用的Web
应用程序的桌面版本。通常,这些应用程序对比网页版并没有什么优势,但是独立应用程序的便利性使它们全天易于访问、查找和切换。
在本章中,我们将研究如何获取现有的Web
应用程序并将其包装在Electron Shell
中。在继续之前,你将需要安装示例API
和Web
应用程序的本地副本。如果你还没有阅读整本书,请访问附录A
和附录B
进行操作。
集成我们的Web应用程序
在上一章中,我们设置了Electron
应用程序加载index.html
文件。我们也可以加载特定的URL
。在本例中,我们将从加载本地运行的Web
应用程序的URL
开始。首先,请确保你的Web
应用程序和API
在本地运行。然后我们可以更新src/index.js
文件,首先将BrowserWindow
中的nodeIntegration
设置为false
。这将避免本地运行的节点应用程序访问外部站点的安全风险。
webPreferences: { nodeIntegration: false
},
现在,更改window.loadFile
('index.html
');,如下:
window.loadURL('http://localhost:1234');
运行Web应用程序
你的Web
应用程序的本地实例将需要在1234
端口上运行。如果你一直在阅读本书,请从Web
应用程序目录的根目录运行npm start
来启动开发服务器。
这将指示Electron
加载URL
,而不是文件。现在,如果你使用npm start
运行该应用程序,你会看到它已加载到Electron
窗口中,但有一些警告。
警告和错误
Electron
浏览器开发者工具和我们的终端显示了大量警告和错误。让我们看一下其中的每一个(见图19-1
)。
图19-1
。我们的应用程序正在运行,但显示大量错误和警告。
首先,我们的终端显示了大量SyntaxError
:Unexpected Token errors.
此外,我们的开发者工具会显示几个相应的警告,指出DevTools
无法解析SourceMap
。这两个错误与Parcel
生成source map
和Electron
读取source map
的方式有关。不幸的是,结合我们正在使用的技术,似乎没有针对此问题的合理解决方案。最好的选择是禁用JavaScript
源映射。在应用程序窗口的开发人员工具中,单击“设置”,然后取消选中“启用JavaScript
源映射”(请参见图19-2
)。
图19-2
。禁用源映射将减少错误和警告的数量
现在,如果退出并重新启动应用程序,将不再看到与源地图有关的问题。这样做的代价是,在Electron
内调试客户端JavaScript
可能会更加困难,但是值得庆幸的是,我们仍然可以在Web
浏览器中访问此功能和我们的应用程序。
最后两个警告与Electron
的安全性有关。在将生产应用程序捆绑在一起之前,我们将解决这些问题,但是现在值得探讨这些警告是什么。
Electron Security Warning
(Insecure Resources
)电子安全警告(资源不安全)
此警告通知我们,我们正在通过http
连接加载Web
资源。在生产中,我们应始终通过https
加载资源,以确保隐私和安全。在开发中,通过http
加载本地主机不是问题,因为我们将引用托管网站,该网站在捆绑的应用程序中使用https
。
Electron Security Warning
(Insecure Content-Security-Policy
)电子安全警告(不安全的内容安全策略)
此警告通知我们我们尚未设置内容安全策略(CSP
)。CSP
允许我们指定允许我们的应用程序从哪个域加载资源,从而大大降低了跨站点脚本(XSS
)攻击的风险。同样,在本地开发期间这不是问题,但在生产中很重要。我们将在本章稍后部分使用CSP
。
解决了我们的错误后,我们就可以设置应用程序的配置文件了。
配置
在本地进行开发时,我们希望能够运行Web
应用程序的本地版本,但是在将应用程序捆绑以供其他人使用时,我们希望它引用公共可用的URL
。我们可以设置一个简单的配置文件来处理此问题。
在我们的 ./ src
目录,我们将添加一个 config.js
文件,我们可以在其中存储特定于应用程序的属性。我已包含一个配置模板。你可用于从终端轻松复制它:
cp src/config.example.js src/config.js
现在我们可以填写应用程序的属性:
const config = {
LOCAL_WEB_URL: 'http://localhost:1234/',
PRODUCTION_WEB_URL: 'https://YOUR_DEPLOYED_WEB_APP_URL',
PRODUCTION_API_URL: 'https://YOUR_DEPLOYED_API_URL'
};
module.exports = config;
为什么不使用.env?
在以前的环境中,我们使用.env
文件来管理特定于环境的设置。在这种情况下,由于Electron
应用程序捆绑其依赖项的方式,我们使用了JavaScript
配置文件。
现在在Electron
应用程序的主要过程中,我们可以使用配置文件来指定我们要在开发和生产中加载的URL
。在src/index.js
,首先导入config.js
文件:
const config = require('./config');
现在,我们可以更新loadURL
功能以为每种环境加载不同的URL
:
// load the URL
if (is.development) {
window.loadURL(config.LOCAL_WEB_URL);
} else {
window.loadURL(config.PRODUCTION_WEB_URL);
}
通过使用配置文件,我们可以轻松地为Electron
提供特定于环境的设置。
内容安全政策
如本章前面所述,CSP
允许我们限制应用程序是否有权从中加载资源的域名。这有助于限制潜在的XSS
和数据注入攻击。在Electron
中,我们可以指定CSP
设置来帮助提高应用程序的安全性。要了解有关电子和Web
应用程序的CSP
的更多信息,我建议你有关该主题的MDN
文章。
Electron
提供了用于CSP
的内置API
,但是electronic-util
库提供了更简单,更简洁的语法。在我们的src/index.js
的顶部,更新electronic-util
导入语句以包含setContentSecurityPolicy
:
const { is, setContentSecurityPolicy } = require('electron-util');
现在,我们可以为应用程序的生产版本设置CSP
:
// set the CSP in production mode
if (!is.development) {
setContentSecurityPolicy(`
default-src 'none';
script-src 'self';
img-src 'self' https://www.gravatar.com;
style-src 'self' 'unsafe-inline';
font-src 'self';
connect-src 'self' ${config.PRODUCTION_API_URL};
base-uri 'none';
form-action 'none';
frame-ancestors 'none';
`);
}
通过编写CSP
,我们可以使用CSP
评估程序工具检查错误。如果我们有意通过其他URL
访问资源,则可以将其添加到CSP
规则集中。
我们最终的src/index.js
文件的内容如下:
const { app, BrowserWindow } = require('electron');
const { is, setContentSecurityPolicy } = require('electron-util');
const config = require('./config');
// to avoid garbage collection, declare the window as a variable
let window;
// specify the details of the browser window
function createWindow() {
window = new BrowserWindow({
width: 800,
height: 600,
webPreferences: {
nodeIntegration: false
}
});
// load the URL
if (is.development) {
window.loadURL(config.LOCAL_WEB_URL);
} else {
window.loadURL(config.PRODUCTION_WEB_URL);
}
// if in development mode, open the browser dev tools
if (is.development) {
window.webContents.openDevTools();
}
// set the CSP in production mode
if (!is.development) {
setContentSecurityPolicy(` default-src 'none';
script-src 'self';
img-src 'self' https://www.gravatar.com;
style-src 'self' 'unsafe-inline';
font-src 'self';
connect-src 'self' ${config.PRODUCTION_API_URL};
base-uri 'none';
form-action 'none';
frame-ancestors 'none'; `);
}
// when the window is closed, dereference the window object
window.on('closed', () => {
window = null;
});
}
// when electron is ready, create the application window
app.on('ready', createWindow);
// quit when all windows are closed.
app.on('window-all-closed', () => {
// On macOS only quit when a user explicitly quits the application
if (process.platform !== 'darwin') {
app.quit();
}
});
app.on('activate', () => {
// on macOS, re-create the window when the icon is clicked in the dock
if (window === null) {
createWindow();
}
});
这样,我们就可以在Electron Shell
中运行Web
应用程序(如图19-3
所示)。
图19-3
。我们在Electron
应用程序shell
中运行的Web
应用程序
结论
在本章中,我们将现有的Web
应用程序集成到Electron
桌面应用程序中,这使我们能够快速将桌面应用程序推向市场。值得注意的是,这种方法需要权衡取舍,因为它提供了特定于桌面的优势,并且需要Internet
连接才能访问应用程序的全部功能。对于希望将台式机应用程序推向市场的我们来说,这些缺点可能值得。在下一章中,我们将研究如何构建和分发Electron
应用程序。
如果有理解不到位的地方,欢迎大家纠错。如果觉得还可以,麻烦您点赞收藏或者分享一下,希望可以帮到更多人。