Перейти к основному содержанию

September 2016: New Apps

· 3 мин. прочитано

Here are the new Electron apps and talks that were added to the site in September.


This site is updated with new apps and meetups through pull requests from the community. You can watch the repository to get notifications of new additions or if you're not interested in all of the site's changes, subscribe to the blog RSS feed.

If you've made an Electron app or host a meetup, make a pull request to add it to the site and it will make the next roundup.

New Talks

In September, GitHub held its GitHub Universe conference billed as the event for people building the future of software. There were a couple of interesting Electron talks at the event.

Also, if you happen to be in Paris on December 5, Zeke will be giving an Electron talk at dotJS 2016.

New Apps

PexelsSearch for completely free photos and copy them into your clipboard
TimestampA better macOS menu bar clock with a customizable date/time display and a calendar
HarmonyMusic player compatible with Spotify, Soundcloud, Play Music and your local files
uPhoneWebRTC Desktop Phone
SealTalkInstant-messaging App powered by RongCloud IM Cloud Service and IM SDK
InfinityAn easy way to make presentation
Cycligent Git ToolStraightforward, graphic GUI for your Git projects
FocoStay focused and boost productivity with Foco
StrawberryWin Diners for Life Know and serve them better with the all-in-one restaurant software suite.
MixmaxSee every action on your emails in real-time Compose anywhere.
Firebase AdminA Firebase data management tool
ANoteA Simple Friendly Markdown Note
TempsA simple but smart menubar weather app
AmiumA work collaboration product that brings conversation to your files
SoubeSimple music player
(Un)coloredNext generation desktop rich content editor that saves documents with themes HTML & Markdown compatible. For Windows, OS X & Linux.
quickcalcMenubar Calculator
Forestpin AnalyticsFinancial data analytics tool for businesses
LingREST Client
ShortextsShortcuts for texts you copy frequently, folders and emojis
Front-End BoxSet of front-end-code generators

Electron's API Docs as Structured Data

· 3 мин. прочитано

Сегодня мы объявляем о некоторых улучшениях в документации Electron. Каждый новый релиз теперь включает в себя файл JSON, который описывает всё об публичных API Electron в деталях. Мы создали этот файл, чтобы разработчики могли использовать документацию Electron API новыми интересными способами.


Обзор схемы

Каждое API - это объект со свойствами по типу имени, описания, типа и т.д. Такие классы, как BrowserWindow и Menu имеют дополнительные свойства, описывающие методы, свойства, события и т.п. их экземпляра.

Вот пример из схемы, которая описывает класс BrowserWindow:

{
имя: 'BrowserWindow',
описание: 'Создание и управление окнами браузера. ,
процесс: {
main: true,
renderer: false
},
тип: 'Класс',
exanceName: 'win',
слаг: 'browser-window',
websiteUrl: 'https://electronjs. rg/docs/api/browser-window',
repoUrl: 'https://github.com/electron/electron/blob/v1.4.0/docs/api/browser-window. d',
staticMethods: [...],
instanceMethods: [...],
instanceProperties: [...],
instanceEvents: [...]
}
}

И вот пример описания метода, в данном случае метод apis.BrowserWindow.instanceMethods.setMaximumSize экземпляра:

{
name: 'setMaximumSize',
signature: '(width, height)',
description: 'Устанавливает максимальный размер окна по ширине и высоте.',
parameters: [{
name: 'width',
type: 'Integer'
}, {
name: 'height',
type: 'Integer'
}]
}

Использование новых данных

Чтобы сделать использование этих структурированных данных в своих проектах для разработчиков простым, мы создали electron-docs-api, небольшой пакет npm, который публикуется автоматически с каждым новым релизом Electron.

npm install electron-api-docs --save

Для мгновенного удовлетворения попробуйте модуль в Node.js REPL:

npm i -g trymodule && trymodule electron-api-docs=apis

Как данные собираются

Документация Electron API придерживается стиля кода Electron и гайдов по стилю Electron, поэтому его содержимое может быть автоматически обработан.

The electron-docs-linter is a new development dependency of the electron/electron repository. It is a command-line tool that lints all the markdown files and enforces the rules of the styleguide. If errors are found, they are listed and the release process is halted. If the API docs are valid, the electron-json.api file is created and uploaded to GitHub as part of the Electron release.

Standard Javascript and Standard Markdown

Earlier this year, Electron's codebase was updated to use the standard linter for all JavaScript. Standard's README sums up the reasoning behind this choice:

Adopting standard style means ranking the importance of code clarity and community conventions higher than personal style. This might not make sense for 100% of projects and development cultures, however open source can be a hostile place for newbies. Setting up clear, automated contributor expectations makes a project healthier.

We also recently created standard-markdown to verify that all the JavaScript code snippets in our documentation are valid and consistent with the style in the codebase itself.

Together these tools help us use continuous integration (CI) to automatically find errors in pull requests. This reduces the burden placed on humans doing code review, and gives us more confidence about the accuracy of our documentation.

A community effort

Electron's documentation is constantly improving, and we have our awesome open-source community to thank for it. As of this writing, nearly 300 people have contributed to the docs.

We're excited to see what people do with this new structured data. Possible uses include:

Electron Internals: Weak References

· 6 мин. прочитано

As a language with garbage collection, JavaScript frees users from managing resources manually. But because Electron hosts this environment, it has to be very careful avoiding both memory and resources leaks.

This post introduces the concept of weak references and how they are used to manage resources in Electron.


Weak references

In JavaScript, whenever you assign an object to a variable, you are adding a reference to the object. As long as there is a reference to the object, it will always be kept in memory. Once all references to the object are gone, i.e. there are no longer variables storing the object, the JavaScript engine will recoup the memory on next garbage collection.

A weak reference is a reference to an object that allows you to get the object without effecting whether it will be garbage collected or not. You will also get notified when the object is garbage collected. It then becomes possible to manage resources with JavaScript.

Using the NativeImage class in Electron as an example, every time you call the nativeImage.create() API, a NativeImage instance is returned and it is storing the image data in C++. Once you are done with the instance and the JavaScript engine (V8) has garbage collected the object, code in C++ will be called to free the image data in memory, so there is no need for users manage this manually.

Another example is the window disappearing problem, which visually shows how the window is garbage collected when all the references to it are gone.

Testing weak references in Electron

There is no way to directly test weak references in raw JavaScript since the language doesn't have a way to assign weak references. The only API in JavaScript related to weak references is WeakMap, but since it only creates weak-reference keys, it is impossible to know when an object has been garbage collected.

In versions of Electron prior to v0.37.8, you can use the internal v8Util.setDestructor API to test weak references, which adds a weak reference to the passed object and calls the callback when the object is garbage collected:

// Code below can only run on Electron < v0.37.8.
var v8Util = process.atomBinding('v8_util');

var object = {};
v8Util.setDestructor(object, function () {
console.log('The object is garbage collected');
});

// Remove all references to the object.
object = undefined;
// Manually starts a GC.
gc();
// Console prints "The object is garbage collected".

Note that you have to start Electron with the --js-flags="--expose_gc" command switch to expose the internal gc function.

The API was removed in later versions because V8 actually does not allow running JavaScript code in the destructor and in later versions doing so would cause random crashes.

Weak references in the remote module

Apart from managing native resources with C++, Electron also needs weak references to manage JavaScript resources. Примером является удаленный модуль Electron, который является модуль Remote Procedure Call (RPC) , который позволяет использовать объекты в основном процессе из процессов визуализации.

One key challenge with the remote module is to avoid memory leaks. When users acquire a remote object in the renderer process, the remote module must guarantee the object continues to live in the main process until the references in the renderer process are gone. Additionally, it also has to make sure the object can be garbage collected when there are no longer any reference to it in renderer processes.

For example, without proper implementation, following code would cause memory leaks quickly:

const { remote } = require('electron');

for (let i = 0; i < 10000; ++i) {
remote.nativeImage.createEmpty();
}

The resource management in the remote module is simple. Whenever an object is requested, a message is sent to the main process and Electron will store the object in a map and assign an ID for it, then send the ID back to the renderer process. In the renderer process, the remote module will receive the ID and wrap it with a proxy object and when the proxy object is garbage collected, a message will be sent to the main process to free the object.

Using remote.require API as an example, a simplified implementation looks like this:

remote.require = function (name) {
// Tell the main process to return the metadata of the module.
const meta = ipcRenderer.sendSync('REQUIRE', name);
// Create a proxy object.
const object = metaToValue(meta);
// Tell the main process to free the object when the proxy object is garbage
// collected.
v8Util.setDestructor(object, function () {
ipcRenderer.send('FREE', meta.id);
});
return object;
};

В основном процессе:

const map = {};
const id = 0;

ipcMain.on('REQUIRE', function (event, name) {
const object = require(name);
// Add a reference to the object.
map[++id] = object;
// Convert the object to metadata.
event.returnValue = valueToMeta(id, object);
});

ipcMain.on('FREE', function (event, id) {
delete map[id];
});

Maps with weak values

With the previous simple implementation, every call in the remote module will return a new remote object from the main process, and each remote object represents a reference to the object in the main process.

The design itself is fine, but the problem is when there are multiple calls to receive the same object, multiple proxy objects will be created and for complicated objects this can add huge pressure on memory usage and garbage collection.

For example, the following code:

const { remote } = require('electron');

for (let i = 0; i < 10000; ++i) {
remote.getCurrentWindow();
}

It first uses a lot of memory creating proxy objects and then occupies the CPU (Central Processing Unit) for garbage collecting them and sending IPC messages.

An obvious optimization is to cache the remote objects: when there is already a remote object with the same ID, the previous remote object will be returned instead of creating a new one.

This is not possible with the API in JavaScript core. Using the normal map to cache objects will prevent V8 from garbage collecting the objects, while the WeakMap class can only use objects as weak keys.

To solve this, a map type with values as weak references is added, which is perfect for caching objects with IDs. Now the remote.require looks like this:

const remoteObjectCache = v8Util.createIDWeakMap()

remote.require = function (name) {
// Tell the main process to return the meta data of the module.
...
if (remoteObjectCache.has(meta.id))
return remoteObjectCache.get(meta.id)
// Create a proxy object.
...
remoteObjectCache.set(meta.id, object)
return object
}

Note that the remoteObjectCache stores objects as weak references, so there is no need to delete the key when the object is garbage collected.

Native code

For people interested in the C++ code of weak references in Electron, it can be found in following files:

The setDestructor API:

The createIDWeakMap API:

August 2016: New Apps

· 3 мин. прочитано

Here are the new Electron apps that were added to the site in August.


The site is updated with new apps and meetups through pull requests from the community. You can watch the repository to get notifications of new additions or if you're not interested in all of the site's changes, subscribe to the blog RSS feed.

If you've made an Electron app or host a meetup, make a pull request to add it to the site and it will make the next roundup.

New Apps

Code RPGifyRPG style coding application
PamFaxA cross-platform app for sending and receiving faxes
BlankUpMarkdown editor witch clarity +1
RamboxFree and Open Source messaging and emailing app that combines common web applications into one
GordieThe best app for your card collections
Ionic CreatorBuild amazing mobile apps, faster
TwitchAlertsKeep your viewers happy with beautiful alerts and notifications
MuseeksA simple, clean and cross-platform music player
SeaPigA converter from markdown to html
GroupMeUnofficial GroupMe App
MoeditorYour all-purpose markdown editor
SoundnodeSoundnode App is the Soundcloud for desktop
QMUI WebQMUI Web Desktop is an application for managing projects based on QMUI Web Framework
SvgsusOrganize, clean and transform your SVGs
RammeUnofficial Instagram Desktop App
InsomniaREST API Client
CorreoA menubar/taskbar Gmail App for Windows, macOS and Linux
KongDashDesktop client for Kong Admin API
Translation EditorTranslation files editor for INTL ICU messages (see formatjsio)
5EClient5EPlay CSGO Client
Theme JuiceLocal WordPress development made easy

Специальные возможности

· 2 мин. прочитано

Создание доступных приложений важно и мы рады представить новые функции Devtron и Spectron, что дает разработчикам возможность делать свои приложения лучше для всех.


Проблемы с доступностью в приложениях Electron аналогичны веб-сайтам, поскольку они оба в конечном итоге являются HTML. Однако в приложениях Electron вы не можете использовать онлайн-ресурсы для аудита доступности, потому что ваше приложение не имеет URL-адреса, чтобы указать аудитору.

Эти новые функции приносят эти инструменты аудита в ваше приложение Electron. Эти новые возможности приносят эти инструменты аудита в ваше приложение Electron. Прочитайте сводки инструментов или проверки нашей доступной документации для получения дополнительной информации.

Spectron

В тестовом фреймворке Spectron, вы можете совершить аудит каждого окна и <webview> в вашем приложении. Например:

app.client.auditAccessibility().then(function (audit) {
if (audit.failed) {
console.error(audit.message);
}
});

Вы можете прочитать больше об этой функции в Spectron документации.

Devtron

В Devtron есть новая вкладка доступности, которая позволит вам совершить аудит страницы в вашем приложении, сортировать и фильтровать результаты.

devtron скриншот

Оба эти средства используют Accessibility Developer Tools библиотеки, построенных для Google Chrome. Вы можете узнать больше о доступности правила аудита, которые эта библиотека использует в этих репозиториях wiki.

Если вы знаете другие инструменты доступности для Electron, добавьте их к accessibility documentation pull request'том.

npm install electron

· 3 мин. прочитано

Начиная с версии Electron 1.3.1, вы можете выполнить npm install electron --save-dev для установки последней скомпилированной версии Electron в ваше приложение.


npm install electron

The prebuilt Electron binary

If you've ever worked on an Electron app before, you've likely come across the electron-prebuilt npm package. This package is an indispensable part of nearly every Electron project. When installed, it detects your operating system and downloads a prebuilt binary that is compiled to work on your system's architecture.

The new name

The Electron installation process was often a stumbling block for new developers. Many brave people tried to get started developing an Electron by app by running npm install electron instead of npm install electron-prebuilt, only to discover (often after much confusion) that it was not the electron they were looking for.

This was because there was an existing electron project on npm, created before GitHub's Electron project existed. To help make Electron development easier and more intuitive for new developers, we reached out to the owner of the existing electron npm package to ask if he'd be willing to let us use the name. Luckily he was a fan of our project, and agreed to help us repurpose the name.

Prebuilt lives on

As of version 1.3.1, we have begun publishing electron and electron-prebuilt packages to npm in tandem. The two packages are identical. We chose to continue publishing the package under both names for a while so as not to inconvenience the thousands of developers who are currently using electron-prebuilt in their projects. We recommend updating your package.json files to use the new electron dependency, but we will continue releasing new versions of electron-prebuilt until the end of 2016.

The electron-userland/electron-prebuilt repository will remain the canonical home of the electron npm package.

Many thanks

We owe a special thanks to @mafintosh, @maxogden, and many other contributors for creating and maintaining electron-prebuilt, and for their tireless service to the JavaScript, Node.js, and Electron communities.

And thanks to @logicalparadox for allowing us to take over the electron package on npm.

Updating your projects

We've worked with the community to update popular packages that are affected by this change. Packages like electron-packager, electron-rebuild, and electron-builder have already been updated to work with the new name while continuing to support the old name.

If you encounter any problems installing this new package, please let us know by opening an issue on the electron-userland/electron-prebuilt repository.

For any other issues with Electron, please use the electron/electron repository.

Electron Internals: Using Node as a Library

· 4 мин. прочитано

This is the second post in an ongoing series explaining the internals of Electron. Посмотрите первый пост о интеграции цикла событий , если вы еще этого не сделали.

Most people use Node for server-side applications, but because of Node's rich API set and thriving community, it is also a great fit for an embedded library. This post explains how Node is used as a library in Electron.


Build system

Узел и Electron используют GYP в качестве их систем сборки. If you want to embed Node inside your app, you have to use it as your build system too.

New to GYP? Прочтите это руководство прежде чем вы продолжите работу в этом сообщении.

Node's flags

узел. yp файл в директории исходного кода узла описывает, как строится узел , вместе со множеством переменных GYP управляет какими частями узла и открывают ли некоторые конфигурации.

To change the build flags, you need to set the variables in the .gypi file of your project. The configure script in Node can generate some common configurations for you, for example running ./configure --shared will generate a config.gypi with variables instructing Node to be built as a shared library.

Electron does not use the configure script since it has its own build scripts. Конфигурации для узла определены в файле common.gypi в корневом каталоге исходного кода Electron.

In Electron, Node is being linked as a shared library by setting the GYP variable node_shared to true, so Node's build type will be changed from executable to shared_library, and the source code containing the Node's main entry point will not be compiled.

Since Electron uses the V8 library shipped with Chromium, the V8 library included in Node's source code is not used. This is done by setting both node_use_v8_platform and node_use_bundled_v8 to false.

Shared library or static library

When linking with Node, there are two options: you can either build Node as a static library and include it in the final executable, or you can build it as a shared library and ship it alongside the final executable.

In Electron, Node was built as a static library for a long time. This made the build simple, enabled the best compiler optimizations, and allowed Electron to be distributed without an extra node.dll file.

Тем не менее, это изменилось после того, как Chrome переключился на использование BoringSSL. BoringSSL — это ответвление OpenSSL , которое удаляет несколько неиспользуемых API и изменяет многие существующие интерфейсы. Because Node still uses OpenSSL, the compiler would generate numerous linking errors due to conflicting symbols if they were linked together.

Electron не смог использовать BoringSSL в узле или использовать OpenSSL в Chromium, чтобы единственный вариант заключался в том, чтобы переключиться на построение узла в качестве разделяемой библиотеки, и скрыть символы BoringSSL и OpenSSL в компонентах каждого из них.

This change brought Electron some positive side effects. Before this change, you could not rename the executable file of Electron on Windows if you used native modules because the name of the executable was hard coded in the import library. After Node was built as a shared library, this limitation was gone because all native modules were linked to node.dll, whose name didn't need to be changed.

Supporting native modules

Нативные модули в работе узла определяют функцию ввода для загрузки узла, и затем поиск символов V8 и libuv из узла. This is a bit troublesome for embedders because by default the symbols of V8 and libuv are hidden when building Node as a library and native modules will fail to load because they cannot find the symbols.

So in order to make native modules work, the V8 and libuv symbols were exposed in Electron. For V8 this is done by forcing all symbols in Chromium's configuration file to be exposed. For libuv, it is achieved by setting the BUILDING_UV_SHARED=1 definition.

Starting Node in your app

After all the work of building and linking with Node, the final step is to run Node in your app.

Node doesn't provide many public APIs for embedding itself into other apps. Обычно вы можете просто вызвать узел::Start и узел::Init , чтобы запустить новый экземпляр узла. However, if you are building a complex app based on Node, you have to use APIs like node::CreateEnvironment to precisely control every step.

In Electron, Node is started in two modes: the standalone mode that runs in the main process, which is similar to official Node binaries, and the embedded mode which inserts Node APIs into web pages. The details of this will be explained in a future post.

July 2016: New Apps and Meetups

· 2 мин. прочитано

We're starting a monthly roundup to highlight activity in the Electron community. Each roundup will feature things like new apps, upcoming meetups, tools, videos, etc.


This site is updated with new apps and meetups through pull requests from the community. You can watch the repository to get notifications of new additions or if you're not interested in all of the site's changes, subscribe to the blog RSS feed.

If you've made an Electron app or host a meetup, make a pull request to add it to the site and it will make the next roundup.

New Apps

DemioA Webinar platform built for inbound sales and marketing
ElectorrentA remote client app for uTorrent server
PhoneGapThe open source framework that gets you building amazing mobile apps using web technology
WordMarkA lightweight blog publishing editor for Markdown writers
UbAuthApp to help developers create access tokens for Uber applications with OAuth 2.0
HyperTermHTML/JS/CSS terminal
MarpMarkdown presentation writer
Glyphr StudioA free, web based font designer, focusing on font design for hobbyists
BitCryptA simple file encryption application for Windows Encrypt your bits
TrymBeautiful small app for macOS to help you view, optimize and convert SVG icons
BookerText editor with the power of Markdown
PhonePresenterThe smartest presentation clicker
YoutThe new way to watch your playlists from YouTube on desktop

New Meetups

Electron Open Source Desktop FrameworkLondon, UK

Electron Internals: Message Loop Integration

· 3 мин. прочитано

This is the first post of a series that explains the internals of Electron. This post introduces how Node's event loop is integrated with Chromium in Electron.


Было сделано много попыток использовать узел для программирования GUI, как node-gui для привязки GTK+ и node-qt для привязки QT. But none of them work in production because GUI toolkits have their own message loops while Node uses libuv for its own event loop, and the main thread can only run one loop at the same time. So the common trick to run GUI message loop in Node is to pump the message loop in a timer with very small interval, which makes GUI interface response slow and occupies lots of CPU resources.

During the development of Electron we met the same problem, though in a reversed way: we had to integrate Node's event loop into Chromium's message loop.

The main process and renderer process

Before we dive into the details of message loop integration, I'll first explain the multi-process architecture of Chromium.

В Electron есть два типа процессов: главный процесс и процесс обработчика (это на самом деле чрезвычайно упрощено, полностью, см. Многопроцессорная архитектура). The main process is responsible for GUI work like creating windows, while the renderer process only deals with running and rendering web pages.

Electron allows using JavaScript to control both the main process and renderer process, which means we have to integrate Node into both processes.

Replacing Chromium's message loop with libuv

My first try was reimplementing Chromium's message loop with libuv.

It was easy for the renderer process, since its message loop only listened to file descriptors and timers, and I only needed to implement the interface with libuv.

However it was significantly more difficult for the main process. Each platform has its own kind of GUI message loops. macOS Chromium uses NSRunLoop, whereas Linux uses glib. I tried lots of hacks to extract the underlying file descriptors out of the native GUI message loops, and then fed them to libuv for iteration, but I still met edge cases that did not work.

So finally I added a timer to poll the GUI message loop in a small interval. As a result the process took a constant CPU usage, and certain operations had long delays.

Polling Node's event loop in a separate thread

As libuv matured, it was then possible to take another approach.

The concept of backend fd was introduced into libuv, which is a file descriptor (or handle) that libuv polls for its event loop. So by polling the backend fd it is possible to get notified when there is a new event in libuv.

So in Electron I created a separate thread to poll the backend fd, and since I was using the system calls for polling instead of libuv APIs, it was thread safe. And whenever there was a new event in libuv's event loop, a message would be posted to Chromium's message loop, and the events of libuv would then be processed in the main thread.

In this way I avoided patching Chromium and Node, and the same code was used in both the main and renderer processes.

The code

Вы можете найти реализацию интеграции цикла сообщений в node_bindings файлах в electron/atom/common/. It can be easily reused for projects that want to integrate Node.

Update: Implementation moved to electron/shell/common/node_bindings.cc.

Electron Podcasts

· Одна мин. чтения

Looking for an introduction to Electron? Two new podcasts have just been released that give a great overview of what it is, why it was built, and how it is being used.


Out now:

Hanselminutes: Creating cross-platform Electron apps

Is Electron "just Chrome in a frame" or is it so much more? Jessica sets Scott on the right path and explains exactly where the Electron platform fits into your development world.


JavaScript Air: Electron Apps

Electron is becoming more and more of a relevant and popular way of building multi-platform desktop apps with web technologies. Let's get a dive into this awesome tech and see how we can use it to enhance our own experience and our user's experience on the desktop.


If you're looking for an introduction to Electron, give the first a listen. The second goes into more detail about building apps with great tips from Nylas's Evan Morikawa.

We are currently working on two more podcasts that should come out next month, keep an eye on the @ElectronJS Twitter account for updates.