Создание настольных приложений с помощью Electron и Vue
Опубликовано: 2022-03-10Раньше JavaScript был известен как язык для создания веб-сайтов и веб-приложений, особенно с некоторыми его фреймворками, такими как React, Vue и Angular, но со временем (уже в 2009 году) JavaScript стал работать вне браузера с помощью появление Node.js, кроссплатформенной среды выполнения JavaScript с открытым исходным кодом, которая выполняет код JavaScript вне веб-браузера. Это привело к возможности использовать JavaScript не только для веб-приложений, и одним из них является создание настольных приложений с использованием Electron.js.
Electron позволяет создавать настольные приложения на чистом JavaScript, предоставляя среду выполнения с богатыми собственными (операционными системами) API. Вы можете рассматривать его как вариант среды выполнения Node.js, ориентированный на настольные приложения, а не на веб-серверы.
В этом руководстве мы узнаем, как создавать настольные приложения с помощью Electron, а также узнаем, как использовать Vuejs для создания приложений Electron.
Примечание . Для выполнения этого руководства необходимы базовые знания Vue.js и Vue CLI. Весь код, используемый в этом руководстве, можно найти на моем GitHub. Не стесняйтесь клонировать и играть с ним!
Что такое настольные приложения?
Настольные приложения — это приложения, которые работают автономно на настольных или портативных компьютерах. Это приложения, которые выполняют определенные задачи и устанавливаются исключительно для этой цели.
Примером настольного приложения является ваш Microsoft Word, который используется для создания и ввода документов. Другими примерами распространенных настольных приложений являются веб-браузеры, Visual Studio Code и Adobe Photoshop. Настольные приложения отличаются от веб-приложений, потому что вам необходимо установить настольное приложение, чтобы получить к нему доступ и использовать его, и иногда для их работы не требуется доступ в Интернет. С другой стороны, к веб-приложениям можно получить доступ, просто посетив URL-адрес, на котором размещено такое приложение, и всегда требуется доступ в Интернет, прежде чем вы сможете получить к ним доступ.
Примеры фреймворков, используемых при создании настольных приложений, включают:
- Джава
Java — это язык программирования общего назначения, основанный на классах, объектно-ориентированный и спроектированный таким образом, чтобы иметь как можно меньше зависимостей от реализации. Он предназначен для того, чтобы разработчики приложений могли написать один раз и запустить где угодно (WORA). Это означает, что скомпилированный код Java может работать на всех платформах, поддерживающих Java, без необходимости перекомпиляции. - JavaFX
Согласно их официальной документации, это платформа клиентских приложений следующего поколения с открытым исходным кодом для настольных, мобильных и встроенных систем, построенная на Java. - С#
C# — это мультипарадигменный язык программирования общего назначения, охватывающий строго типизированный, лексически ограниченный, императивный, декларативный, функциональный, универсальный, объектно-ориентированный и компонентно-ориентированный язык программирования. - .СЕТЬ
.NET — это бесплатная кроссплатформенная платформа для разработчиков с открытым исходным кодом для создания множества различных типов приложений. С .NET вы можете использовать несколько языков, редакторов и библиотек для создания приложений для Интернета, мобильных устройств, компьютеров, игр и Интернета вещей.
Что такое электрон?
Electron — это фреймворк с открытым исходным кодом для создания настольных приложений. Ранее он был известен как «оболочка Atom», разрабатывается и поддерживается GitHub. Он позволяет писать кроссплатформенные настольные приложения с использованием HTML, CSS и JavaScript. Это означает, что вы можете создавать настольные приложения для Windows, MacOS и других платформ, используя одну кодовую базу. Он основан на Node.js и Chromium. Примеры приложений, созданных с помощью Electron, включают популярный редактор Atom, Visual Studio Code, Wordpress для настольных компьютеров и Slack.
Установка
Вы можете установить Electron в свой проект с помощью NPM:
npm install electron --save-dev
Вы также можете установить его глобально, если собираетесь много работать с электронными приложениями, используя эту команду:
npm install electron -g
Создание приложений Vuejs для рабочего стола с помощью Electron
Если вы знакомы с созданием веб-приложений с помощью Vuejs, вы можете создавать настольные приложения с помощью Vuejs. Все, что вам нужно для этого, — это Vue CLI Plugin Electron Builder.
Электронный конструктор плагинов Vue CLI
Этот инструмент позволяет вам создавать приложения Vue для настольных компьютеров с помощью Electron, это означает, что он заставляет ваше приложение Vue работать как электронное приложение. Это означает, что ваше приложение Vue, которое, возможно, является веб-приложением, может быть расширено для работы в настольных средах без необходимости создавать отдельное настольное приложение в другой среде. Это дает разработчикам Vue возможность выйти за пределы Интернета. В будущем вы можете поработать над этой идеей и предоставить пользователям вариант настольного приложения, которое может работать в Windows, macOS и Linux.
Чтобы увидеть это в действии, мы собираемся создать приложение новостей с использованием API новостей. Приложение будет предоставлять заголовки последних новостей и позволит вам искать статьи из источников новостей и блогов по всему Интернету с их API. Все, что вам нужно, чтобы начать работу с ними, — это ваш личный ключ API, который можно получить здесь.
Мы создадим простое приложение, которое предлагает следующее:
- Страница, на которой отображаются главные и последние заголовки из выбранной страны с возможностью выбора страны с помощью конечной точки
/top-headlines
. News API предоставляет новости из списка стран, которые они поддерживают, список можно найти здесь. - Новости из выбранной категории, используя комбинацию их конечной точки
/everything
Everything и параметра запросаq
, с помощью которого мы укажем нашу категорию.
Получив ваш API-ключ, мы можем создать наше приложение с помощью Vue CLI. Убедитесь, что в вашей системе установлен Vue CLI, если нет, установите его с помощью этой команды:
npm install -g @vue/cli # OR yarn global add @vue/cli
Как только это будет сделано, создайте приложение новостей с помощью CLI:
vue create news-app
Мы будем получать данные из News API с помощью Axios для этого руководства, но вы можете использовать любой удобный для вас вариант. Вы можете установить Axios с помощью любой из следующих команд:
//NPM npm install axios // YARN yarn add axios
Следующим шагом будет настройка экземпляра Axios для глобальной конфигурации в нашем приложении. Мы собираемся создать папку plugins в папке src , где мы создадим этот файл axios.js . После создания файла добавьте следующие строки кода:
import axios from "axios"; let baseURL = `https://newsapi.org/v2`; let apiKey = process.env.VUE_APP_APIKEY; const instance = axios.create({ baseURL: baseURL, timeout: 30000, headers: { "X-Api-Key": apiKey, }, }); export default instance;
Здесь мы определяем наш baseURL
и apiKey
, которые мы получили от News API, и передаем их новому экземпляру Axios. Этот экземпляр принимает baseURL
и apiKey
вместе со свойством timeout
-аута. News API требует, чтобы вы добавили свой API-ключ при отправке запроса к их API, и предлагает 3 способа прикрепить его к вашему запросу, но здесь мы добавляем его в свойство заголовка X-Api-Key
, после чего мы экспортируем instance
. Как только это будет сделано, мы теперь можем использовать эту конфигурацию для всех наших запросов Axios в нашем приложении.
Когда это будет сделано, вы можете добавить сборщик плагинов Electron с помощью CLI, используя эту команду:
vue add electron-builder
Вам будет предложено выбрать предпочтительную версию Electron, я выбрал версию 9.0.0
потому что это последняя версия Electron (на момент написания).
Когда это будет сделано, теперь вы можете обслуживать свое приложение с помощью этой команды:
Using Yarn(strongly recommended) yarn electron:serve OR NPM npm run electron:serve
Это займет некоторое время для компиляции и обслуживания вашего приложения. Когда это будет сделано, ваше приложение откроется в вашей системе, это должно выглядеть так:
Если вы закроете devtools своего приложения, оно должно выглядеть так:
Этот электронный плагин очень полезен и прост в использовании, потому что каждая часть разработки этого приложения работает так же, как приложение Vue. Это означает, что у вас может быть одна кодовая база как для веб-приложения, так и для настольного приложения. Наше приложение будет состоять из трех частей:
- Целевая страница, на которой отображаются главные новости страны, выбранной случайным образом.
- Страница для отображения главных новостей из выбранной пользователем страны.
- Страница, отображающая главные новости из категории, выбранной пользователем.
Для этого нам понадобится компонент заголовка для всех наших навигационных ссылок. Итак, давайте создадим файл в папке компонентов и назовем его header.vue , а затем добавим в него следующие строки кода:
<template> <header class="header"> <div class="logo"> <div class="logo__container"> <img src="../assets/logo.png" alt="News app logo" class="logo__image" /> </div> <h1>News App</h1> </div> <nav class="nav"> <h4 class="nav__link"> <router-link to="/home">Home</router-link> </h4> <h4 class="nav__link"> <router-link to="/top-news">Top News</router-link> </h4> <h4 class="nav__link"> <router-link to="/categories">News By Category</router-link> </h4> </nav> </header> </template> <script> export default { name: "app-header", }; </script> <style> .header { display: flex; flex-wrap: wrap; justify-content: space-between; } .logo { display: flex; flex-wrap: nowrap; justify-content: space-between; align-items: center; height: 50px; } .logo__container { width: 50px; height: 50px; } .logo__image { max-width: 100%; max-height: 100%; } .nav { display: flex; flex-wrap: wrap; width: 350px; justify-content: space-between; } </style>
Здесь мы создаем компонент заголовка с названием и логотипом нашего приложения (изображение можно найти на моем GitHub) вместе с разделом навигации, который содержит ссылки на другие части нашего приложения. Следующим шагом будет импорт этой страницы на нашу страницу макета — App.vue , чтобы мы могли видеть наш заголовок на каждой странице.
<template> <div> <app-header /> <router-view /> </div> </template> <script> import appHeader from "@/components/Header.vue"; export default { name: "layout", components: { appHeader, }, }; </script> <style> @import url("https://fonts.googleapis.com/css2?family=Abel&family=Staatliches&display=swap"); html, #app { min-height: 100vh; } #app { font-family: "Abel", sans-serif; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; text-align: center; color: #2c3e50; background-color: #fff; } #app h1 { font-family: "Staatliches", cursive; } a { font-weight: bold; color: #2c3e50; text-decoration: none; } a:hover { text-decoration: underline; } a.router-link-exact-active { color: #42b983; } </style>
Здесь мы заменяем содержимое по умолчанию в разделе шаблона нашим вновь созданным компонентом заголовка после того, как мы импортировали и объявили его в разделе сценария. Наконец, мы добавляем стили для всего приложения в разделе стилей.
Теперь, если мы попытаемся просмотреть наше приложение, оно должно выглядеть так:
Следующим шагом будет добавление контента в наш файл Home.vue . На этой странице будет размещаться первый раздел нашего приложения; Лучшие новости из страны, выбранной случайным образом. Обновите файл Home.vue , добавив следующие строки кода:
<template> <section class="home"> <h1>Welcome to News App</h1> <h4>Displaying Top News from {{ countryInfo.name }}</h4> <div class="articles__div" v-if="articles"> <news-card v-for="(article, index) in articles" :key="index" :article="article" ></news-card> </div> </section> </template> <script> import { mapActions, mapState } from "vuex"; import NewsCard from "../components/NewsCard"; export default { data() { return { articles: "", countryInfo: "", }; }, components: { NewsCard, }, mounted() { this.fetchTopNews(); }, computed: { ...mapState(["countries"]), }, methods: { ...mapActions(["getTopNews"]), async fetchTopNews() { let countriesLength = this.countries.length; let countryIndex = Math.floor( Math.random() * (countriesLength - 1) + 1 ); this.countryInfo = this.countries[countryIndex]; let { data } = await this.getTopNews( this.countries[countryIndex].value ); this.articles = data.articles; }, }, }; </script> <style> .articles__div { display: flex; flex-wrap: wrap; justify-content: center; } </style>
В разделе script этого файла мы импортируем mapState
и mapActions
из Vuex, которые мы будем использовать позже в этом файле. Мы также импортируем компонент NewsCard
(мы создадим его далее), который будет отображать все заголовки новостей на этой странице. Затем мы используем метод fetchTopNews
для получения последних новостей из страны, выбранной случайным образом из множества countries
в нашем магазине. Эта страна передается нашему действию getTopNews
, оно будет добавлено к baseURL
в качестве запроса для страны, например baseURL/top-news?country=${randomCountry}
. Как только это будет сделано, мы прокручиваем эти данные и передаем их в реквизит article
нашего компонента Newscard
в разделе шаблона. У нас также есть абзац, в котором указано, из какой страны главные новости.
Следующим шагом будет настройка нашего компонента NewsCard
, который будет отображать эту новость. Создайте новый файл в папке компонентов , назовите его NewsCard.vue и добавьте в него следующие строки кода:
<template> <section class="news"> <div class="news__section"> <h1 class="news__title"> <a class="article__link" :href="article.url" target="_blank"> {{ article.title }} </a> </h1> <h3 class="news__author" v-if="article.author">{{ article.author }}</h3> <!-- <p class="article__paragraph">{{ article.description }}</p> --> <h5 class="article__published">{{ new Date(article.publishedAt) }}</h5> </div> <div class="image__container"> <img class="news__img" src="../assets/logo.png" :data-src="article.urlToImage" :alt="article.title" /> </div> </section> </template> <script> export default { name: "news-card", props: { article: Object, }, mounted() { this.lazyLoadImages(); }, methods: { lazyLoadImages() { const images = document.querySelectorAll(".news__img"); const options = { // If the image gets within 50px in the Y axis, start the download. root: null, // Page as root rootMargin: "0px", threshold: 0.1, }; const fetchImage = (url) => { return new Promise((resolve, reject) => { const image = new Image(); image.src = url; image.onload = resolve; image.onerror = reject; }); }; const loadImage = (image) => { const src = image.dataset.src; fetchImage(src).then(() => { image.src = src; }); }; const handleIntersection = (entries) => { entries.forEach((entry) => { if (entry.intersectionRatio > 0) { loadImage(entry.target); } }); }; // The observer for the images on the page const observer = new IntersectionObserver(handleIntersection, options); images.forEach((img) => { observer.observe(img); }); }, }, }; </script> <style> .news { width: 100%; display: flex; flex-direction: row; align-items: flex-start; max-width: 550px; box-shadow: 2px 1px 7px 1px #eee; padding: 20px 5px; box-sizing: border-box; margin: 15px 5px; border-radius: 4px; } .news__section { width: 100%; max-width: 350px; margin-right: 5px; } .news__title { font-size: 15px; text-align: left; margin-top: 0; } .news__author { font-size: 14px; text-align: left; font-weight: normal; } .article__published { text-align: left; } .image__container { width: 100%; max-width: 180px; max-height: 180px; } .news__img { transition: max-width 300ms cubic-bezier(0.4, 0, 1, 1), max-height 300ms cubic-bezier(0.4, 0, 1, 1); max-width: 150px; max-height: 150px; } .news__img:hover { max-width: 180px; max-height: 180px; } .article__link { text-decoration: none; color: inherit; } </style>
Здесь мы отображаем данные, переданные в этот компонент, используя свойство объекта article
. У нас также есть метод, который лениво загружает изображения, прикрепленные к каждой статье. Этот метод перебирает количество изображений статей, которые у нас есть, и лениво загружает их, когда они становятся видимыми. Наконец, у нас есть стили, предназначенные для этого компонента в разделе стилей.
Следующим шагом будет создание нашего магазина, чтобы мы могли начать получать последние новости. Добавьте следующие строки кода в файл index.js :
import Vue from "vue"; import Vuex from "vuex"; import axios from "../plugins/axios"; Vue.use(Vuex); const store = new Vuex.Store({ state: { countries: [{ name: "United States of America", value: "us", }, { name: "Nigeria", value: "ng", }, { name: "Argentina", value: "ar", }, { name: "Canada", value: "ca", }, { name: "South Africa", value: "za", }, ], categories: [ "entertainment", "general", "health", "science", "business", "sports", "technology", ], }, mutations: {}, actions: { async getTopNews(context, country) { let res = await axios({ url: `/top-headlines?country=${country}`, method: "GET", }); return res; }, }, }); export default store;
Мы добавляем два свойства в наш магазин, одно из этих свойств — countries
. Это свойство содержит массив объектов стран. У нас также есть свойство categories
; он содержит массив доступных категорий в News API. Читателю понравится свобода просмотра главных новостей из конкретных стран и категорий; это также потребуется более чем в одной части приложения, и именно поэтому мы используем магазин. В разделе действий нашего магазина у нас есть метод getTopNews
, который извлекает главные новости из страны (эта страна была передана из компонента, вызвавшего это действие).
На этом этапе, если мы откроем наше приложение, мы должны увидеть нашу целевую страницу, которая выглядит так:
Файл background.js
Этот файл является точкой входа для Electron в ваше приложение. Он управляет всеми настройками настольного приложения для этого приложения. Состояние этого файла по умолчанию можно найти на моем GitHub.
В этом файле у нас есть некоторые предопределенные конфигурации, установленные для приложения, такие как height
и width
по умолчанию для вашего приложения. Давайте взглянем на некоторые вещи, которые вы можете сделать в этом файле.
Включение инструментов разработки Vuejs
По умолчанию у вас есть доступ к инструментам разработки в Electron, но он не включается после установки. Это связано с существующей ошибкой в Windows 10, поэтому, если вы откроете файл background.js , вы найдете некоторый закомментированный код с комментариями, в которых указано, почему они закомментированы:
// Install Vue Devtools // Devtools extensions are broken in Electron 6.0.0 and greater // See https://github.com/nklayman/vue-cli-plugin-electron-builder/issues/378 for more info // Electron will not launch with Devtools extensions installed on Windows 10 with dark mode // If you are not using Windows 10 dark mode, you may uncomment these lines // In addition, if the linked issue is closed, you can upgrade electron and uncomment these lines // try { // await installVueDevtools() // } catch (e) { // console.error('Vue Devtools failed to install:', e.toString()) // }
Поэтому, если вас не затронула эта ошибка, вы можете раскомментировать блок try/catch
, а также найти installVueDevtools
в этом же файле (строка 5) и также раскомментировать его. Как только это будет сделано, ваше приложение автоматически перезапустится, и когда вы проверите свои инструменты разработки, вы должны увидеть Vuejs Devtools.
Выбор пользовательского значка для вашего приложения
По умолчанию значок Electron установлен в качестве значка по умолчанию для вашего приложения, и в большинстве случаев вы, вероятно, захотите установить свой собственный значок. Для этого переместите значок в общую папку и переименуйте его в icon.png . Следующее, что нужно сделать, это добавить необходимую зависимость, electron-icon-builder
.
Вы можете установить его с помощью любой из следующих команд:
// With Yarn: yarn add --dev electron-icon-builder // or with NPM: npm install --save-dev electron-icon-builder
Как только это будет сделано, вы можете запустить следующую команду. Он преобразует вашу иконку в формат Electron и распечатает следующее в вашей консоли, когда это будет сделано.
Следующим шагом будет установка параметра значка в файле background.js . Эта опция находится внутри опции BrowserWindow
, которая импортируется из Electron
. Для этого обновите BrowserWindow
, чтобы он выглядел следующим образом:
// Add this to the top of your file /* global __static */ // import path import path from 'path' // Replace win = new BrowserWindow({ width: 800, height: 600 }) // With win = new BrowserWindow({ width: 800, height: 600, icon: path.join(__static, 'icon.png') })
Теперь, если мы запустим yarn run electron:build
и просмотрим наше приложение, мы должны увидеть обновленный значок, используемый в качестве значка приложения, но он не изменится в процессе разработки. Эта проблема помогает исправить ее вручную в macOS.
Настройка заголовка для вашего приложения
Вы заметите, что название вашего приложения установлено на имя приложения (в данном случае приложение новостей), и нам нужно его изменить. Для этого нам нужно добавить свойство title
в метод BrowserWindow
в нашем файле background.js
следующим образом:
win = new BrowserWindow({ width: 600, height: 500, title: "News App", icon: path.join(__static, "icon.png"), webPreferences: { // Use pluginOptions.nodeIntegration, leave this alone // See nklayman.github.io/vue-cli-plugin-electron-builder/guide/security.html#node-integration for more info nodeIntegration: process.env.ELECTRON_NODE_INTEGRATION, }, });
Здесь мы устанавливаем название нашего приложения на «Новостное приложение». Но если в вашем файле index.html выбран заголовок или ваш заголовок не меняется на этот, попробуйте добавить в файл этот код:
win.on("page-title-updated", (event) => event.preventDefault());
Мы ожидаем события, которое запускается, когда наш title
обновляется из BrowserWindow
. Когда это событие срабатывает, мы говорим Electron не обновлять заголовок тем, который находится в файле index.html .
Еще одна вещь, которую, возможно, стоит изменить, это productName
, это определяет, какое имя появляется при наведении курсора на значок вашего приложения или как ваш компьютер распознает приложение. Сейчас наше приложение называется Electron
. Чтобы изменить это имя в рабочей среде, создайте файл vue.config.js и добавьте в него следующие строки кода:
module.exports = { pluginOptions: { electronBuilder: { builderOptions: { productName: "News App", }, }, }, };
Здесь мы определяем productName
как «Новостное приложение», чтобы при запуске команды сборки для нашего приложения имя менялось с «Электрон» на «Новостное приложение».
Многоплатформенная сборка
По умолчанию, когда вы запускаете команду сборки, создаваемое приложение зависит от платформы, на которой оно выполняется. Это означает, что если вы запустите команду сборки в Linux, созданное приложение будет настольным приложением Linux. То же самое относится и к другим платформам (macOS и Windows). Но у Electron есть возможность указать платформу (или две платформы), которую вы хотите сгенерировать. Доступные варианты:
-
mac
-
win
-
linux
Итак, чтобы собрать версию вашего приложения для Windows, выполните следующую команду:
// NPM npm electron:build -- --win nsis // YARN yarn electron:build --win nsis
Заключение
Готовое приложение можно найти на моем GitHub. Официальная документация Electron содержит информацию и руководство, которое поможет вам настроить настольное приложение так, как вы хотите. Некоторые из вещей, которые я опробовал, но не включены в это руководство:
- Настройка док-станции в macOS — https://www.electronjs.org/docs/tutorial/macos-dock.
- Настройка изменяемого размера, максимизации и многого другого — https://github.com/electron/electron/blob/master/docs/api/browser-window.md#new-browserwindowoptions.
Поэтому, если вы хотите сделать гораздо больше с вашим приложением Electron, их официальная документация — хорошее место для начала.
Связанные ресурсы
- Node.jshttps://en.wikipedia.org/wiki/Node.js
- Java (язык программирования)https://en.wikipedia.org/wiki/Java_(язык_программирования)
- Электрон (программный фреймворк)
- JavaFX 14
- электронные
- Электронная документация
- Плагин Vue CLI Electron Builder
- Ленивая загрузка изображений для повышения производительности с использованием Intersection Observer, Крис Нвамба
- аксиомы
- Начало работы с Axios в Nuxthttps://www.smashingmagazine.com/2020/05/getting-started-axios-nuxt/) Тими Омоени