使用 Vue:NW.js 构建桌面应用程序
之前我写过两篇关于使用 Vue 框架构建桌面应用的文章:一篇是关于Vuido 库的,另一篇是关于Electron的。之前有人留言说想写一篇关于NW.js的文章,我答应了……现在终于写完了!迟到总比不到好😅
NW.js(原名 node-webkit)是一个使用 HTML、CSS 和 JavaScript 构建桌面应用程序的框架。它基于Chromium和Node.js。NW.js允许您直接从浏览器调用 Node.js 代码和模块,并在应用中使用 Web 技术。此外,您可以轻松地将 Web 应用程序打包为原生应用程序。
⚛️ 与 Electron 的区别
Electron 和 NW.js 有很多共同的特性:它们都基于 Chromium 和 Node.js 构建,并使用 HTML、CSS 和 JS 来构建桌面应用。但它们也有一些显著的区别:
- 在 NW.js 中,应用程序的主入口点是网页或 JS 脚本。您可以通过
package.json
main
属性指定入口点。在 Electron 中,入口点是 JavaScript 脚本。您无需直接提供 URL,而是手动创建浏览器窗口并使用 API 加载 HTML 文件。 - 在构建过程中,NW.js 构建所有 Chromium;Electron 使用libchromiumcontent访问 Chromium 的内容 API
- NW.js内置支持将源代码编译为受保护的二进制文件。Electron 使用asar打包其应用程序,其中包含应用程序未受保护的源代码。
💻我们要构建什么
现在,当我们了解了它与 Electron 的区别后,我们将构建与上一篇文章相同的应用程序:一个基于OpenWeatherMap API构建的应用程序,用于查看用户所选城市的天气。该项目将使用Vue CLI构建,我推荐使用这种方式来搭建任何 Vue 应用程序。
如果您只想检查最终的 NW.js 应用程序代码,请点击此处。
🛠️ 安装
使用 Vue CLI 创建应用程序
首先,让我们用 Vue CLI 搭建一个应用。请确保你已经在控制台中输入以下命令安装了它:
vue --version
如果你没有版本或者版本低于 3.x,请运行
npm install -g @vue/cli
现在,您可以从控制台创建 Vue 项目了!请运行
vue create <<YOUR-PROJECT-NAME>>
并选择您需要的选项。我将在本项目中使用默认设置。
太好了,现在我们可以添加一些桌面魔法了🧙
添加 NW.js
NW.js 官方文档建议使用以下两个构建器之一来打包您的应用程序:
我选择了 nwjs-builder-phoenix,我将描述进一步的步骤,假设你也会使用它😅
因此,首先需要将其作为依赖项添加到您的项目中:
npm install --save-dev nwjs-builder-phoenix
## OR
yarn add --dev nwjs-builder-phoenix
现在您需要修改package.json
文件以便为打包程序提供正确的条目。
package.json
提示:您可以在应用程序的根文件夹中找到。
打包器条目应在main
属性下指定。我们将在桌面上运行一个开发环境,因此让我们package.json
使用以下内容进行扩展:
"main": "http://localhost:8080"
它是我们搭建的 Web 应用在本地运行的端口。通常情况下main
是这样index.html
,但现在我们希望在每次应用变更时都进行热重载。因此,我们指定了main
一个带有热重载模块的 Vue 应用。
运行应用程序
现在让我们运行我们的 Web 应用程序:
npm run serve
## OR
yarn serve
你可以http://localhost:8080
在浏览器中检查应用是否正在运行。应该显示类似以下内容:
最后,我们准备启动桌面应用程序:
./node_modules/.bin/run .
这将获取指定版本的 NW.js(默认情况下是
sdk
)并运行开发环境。
run
是一个由 和 点添加的命令,表示我们正在从根目录nwjs-builder-phoenix
使用。package.json
现在你应该有一个在桌面上运行的应用程序
让我们稍微自动化一下运行开发环境。关闭你的桌面应用,然后安装 NW.js SDK 版本:
npm install --save-dev nw@sdk
## OR
yarn add --dev nw@sdk
现在,向部分添加一个新任务package.json
scripts
:
"scripts": {
"serve": "vue-cli-service serve",
"build": "vue-cli-service build",
"nw-serve": "nw ." /* <--- here is your new npm task */
},
我们尝试运行它:
npm run nw-serve
## OR
yarn nw-serve
您的应用程序应该可以再次在桌面上运行,但现在无需下载步骤🎉
好消息:你可以像在浏览器中一样轻松打开 DevTools,并使用它们来调试你的应用程序!只需点击Window
->Devtools
🕹️ 搭建应用程序
与 Electron 类似,NW.js 驱动的应用程序的构建方式与通常的 Web 应用程序类似,因此我们将创建一个 Web 应用程序,使用一些 CSS 设置其样式,然后将nwjs-builder-phoenix
其打包到桌面应用程序中。
注意:与 Electron 应用一样,我特意没有安装任何 CSS 框架或组件库:我想在不添加任何依赖项的情况下比较包大小。所有桌面项目使用的唯一库是axios。
打开App.vue
文件并将其内容替换为以下代码:
<template>
<div id="app">
<p>Enter the city name to check current weather in it</p>
<section class="weather-input">
<input type="text" v-model="query">
<button :disabled="!query.length">Check</button>
</section>
</div>
</template>
<script>
export default {
data() {
return {
query: "",
};
}
};
</script>
<style>
#app {
font-family: "Avenir", Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
margin-top: 60px;
}
.button {
color: #000;
}
</style>
现在我们的应用程序看起来是这样的:
🔗 进行 API 调用
我使用了OpenWeatherMap 的当前天气 API。它提供了许多不同的信息,您可以在此处查看 JSON 响应的示例。
我们将使用axios进行 API 调用。显然,我们需要安装它:
npm install axios
## OR
yarn add axios
为了能够在任何 Vue 组件中使用 axios,我们将其导入main.js
,设置基本 URL,然后在 Vue 原型中为其创建一个属性:
//main.js
import axios from 'axios'
axios.defaults.baseURL = 'http://api.openweathermap.org/data/2.5';
Vue.http = Vue.prototype.$http = axios;
现在App.vue
我们将创建一组数据属性来显示不同的天气数据:
// App.vue
data() {
return {
query: '',
error: false,
city: '',
country: '',
weatherDescription: '',
temp: null,
tempMin: null,
tempMax: null,
humidity: null,
icon: '',
};
},
与 Electron 类似,与 Vuido 版本相比,我添加了一个附加属性,即icon
。API 提供了一个天气图标,但我们无法在 Vuido 应用中使用它,因为目前不支持显示图像。
我们还创建一个方法来获取数据:
methods: {
showWeather() {
this.$http
.get(`/weather?q=${this.query}&units=metric&&appid=${API_KEY}`)
.then(response => {
this.city = response.data.name;
this.country = response.data.sys.country;
this.weatherDescription = response.data.weather[0].description;
this.temp = response.data.main.temp;
this.tempMin = response.data.main.temp_min;
this.tempMax = response.data.main.temp_max;
this.humidity = response.data.main.humidity;
this.icon = `http://openweathermap.org/img/w/${
response.data.weather[0].icon
}.png`;
this.error = false;
})
.catch(() => {
this.error = true;
this.city = '';
});
},
},
不要忘记
API_KEY
使用您的 OpenWeather API 密钥创建一个 const!
并将其添加到按钮的点击回调中:
<button :disabled="!query.length" @click="showWeather">Check</button>
现在,如果您在输入字段中输入文本并单击按钮,您可以在选项Network
卡中观察 API 调用:
💅 显示天气数据
让我们将这些数据添加到模板中:
<template>
<main id="app">
<p>Enter the city name to check current weather in it</p>
<section class="weather-input">
<input type="text" v-model="query">
<button :disabled="!query.length" @click="showWeather">Check</button>
</section>
<section v-if="error" class="weather-error">
There is no such city in the database
</section>
<section v-if="city.length" class="weather-result">
<h1>{{city}}, {{country}}</h1>
<p><em>{{weatherDescription}}</em></p>
<div class="weather-result__main">
<img :src="icon" alt="Weather icon">
<div class="weather-result__temp">
{{temp}}°C
</div>
</div>
<div class="weather-result__details">
<p>Min: {{tempMin}}°C</p>
<p>Max: {{tempMax}}°C</p>
<p>Humidity: {{humidity}}%</p>
</div>
</section>
</main>
</template>
我们的应用视图:
它看起来仍然太基础了,所以是时候添加一些 CSS 了。让我们用以下代码替换整个style
部分:App.vue
<style>
* {
margin: 0;
padding: 0;
}
html,
body,
#app {
height: 100%;
}
#app {
font-family: Arial, Helvetica, sans-serif;
font-size: 16px;
padding: 10px;
background: rgb(212, 228, 239);
background: radial-gradient(
ellipse at center,
rgba(212, 228, 239, 1) 0%,
rgba(134, 174, 204, 1) 100%
);
filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#d4e4ef', endColorstr='#86aecc',GradientType=1 ); /* IE6-9 fallback on horizontal gradient */
}
.weather-input {
display: flex;
align-items: center;
padding: 20px 0;
}
.weather-result {
text-align: center;
}
.weather-result__main {
display: flex;
align-items: center;
justify-content: center;
padding-top: 5px;
font-size: 1.3rem;
font-weight: bold;
}
.weather-result__details {
display: flex;
align-items: center;
justify-content: space-around;
color: dimgray;
}
.weather-error {
color: red;
font-weight: bold;
}
input {
width: 75%;
outline: none;
height: 20px;
font-size: 0.8rem;
}
button {
display: block;
width: 25%;
height: 25px;
outline: none;
border-radius: 5px;
white-space: nowrap;
margin: 0 10px;
font-size: 0.8rem;
}
</style>
最后,我们得到了一个美观且功能齐全的应用程序:
打包之前要做的最后一件事是缩小窗口大小。为此,我们需要添加一个window
属性package.json
:
"window": {
"width": 600,
"height": 400
},
📦包装
要打包 NW.js 应用,nwjs-builder-phoenix
您需要运行带有适当参数的构建命令。我将在 Mac 上构建它,以便将其大小与 Electron 和 Vuido 应用进行比较。
首先,我们需要指定构建过程中使用的 NW.js 版本。我们可以build
通过package.json
"build": {
"nwVersion": "0.35.3"
},
然后我们在终端中运行一个构建命令:
./node_modules/.bin/build --tasks mac-x64 .
再次强调,命令中的点表示我们正在使用
package.json
位于根项目文件夹中的文件
让我们检查一下包大小...233 MB😱!
哇,好多啊!比 Electron 应用还大!
🌟 结论
优点:
- 真的很容易上手
- 可以通过 CSS 样式进行定制
- 好的文档
- 支持受保护的二进制文件
缺点
- 包装尺寸非常大
- 命名不太好(也许只是我的看法,但 Electron/Vuido 比 NW.js 更容易记住)
- 小生态系统。
💖 特别感谢
我要感谢Jared Wilcurt ,他帮助我解答了 NW.js 方面的问题。Jared 是NW.js Vue devtools的作者,该工具可以直接在桌面上调试 Vue 应用程序。
更新:如果您想知道如何显著减少包的大小,这里有一篇由 Jared Wilcurt 撰写的文章。
文章来源:https://dev.to/n_tepluhina/building-a-desktop-app-with-vue-nwjs-1f9e