Рубрики
Без рубрики

Как сделать ваше электронное приложение запустить на 1000 мс быстрее

Привет, я Такуя, инди-разработчик, создающий приложение для снятия нот, под названием Inkdrop. Это приложение бу … Tagged with Electron, React, JavaScript, производительность.

Привет, я Такуя , инди-разработчик, создающий приложение с заметками. Inkdrop Анкет Это приложение построено на вершине Электрон , структура, которая позволяет вам создавать кроссплатформенное настольное приложение на основе Nodejs и Chromium (браузер). Это в основном отличная структура, потому что вы можете создавать настольные приложения, не изучая собственные рамки или языки, но с JavaScript, HTML и CSS. Если вы являетесь веб -разработчиком, вы можете быстро создавать настольные приложения. С другой стороны, люди часто упоминают о недостатке электрона – время запуска приложения имеет тенденцию быть медленным. Мое приложение также столкнулось с этой проблемой, так как у меня есть жалобы на медленную скорость запуска от некоторых пользователей. Да, медленный запуск такой стресс. Но я очень рад, что достиг, чтобы решить это. Приложение TTI (время до интерактивного) было увеличено с 4 секунд до 3 секунд на моем Mac. Я бы сказал, что «на 1000 мс быстрее» вместо того, чтобы просто «быстрее», потому что это значительное улучшение, и я очень усердно работал для этого! Взгляните на следующий сравнение скринкаст:

Вы можете чувствовать, что это довольно быстрее, чем предыдущая версия. Как вы можете видеть выше, главное окно приложения показывает немного быстрее, и загрузка пакета приложений в окне браузера также быстро заканчивается. В настоящее время она находится в бета -версии, и пользователи сказали мне, что они довольны улучшенной скоростью запуска. Я не могу дождаться, чтобы официально свернуть его.

Я предполагаю, что есть много разработчиков, пытающихся решить одну и ту же проблему, поэтому я хотел бы поделиться тем, как я это сделал. Давайте повысим ваше электронное приложение!

TL; DR

  • Загрузка JavaScript слишком медленная
  • Не звоните require () пока вам не понадобится (300 мс улучшится)
  • Используйте снимки V8 (улучшены на 700 мс)

Загрузка JavaScript слишком медленная

Итак, почему электронные приложения, как правило, начинаются медленно? Самым большим узким местом в запуске приложения, очевидно, является процесс загрузки JavaScript. Вы можете проверить, как загружается вариант вашего приложения в анализаторе производительности разработчиков.

Пресс CMD-E или кнопку «Запись Red Dot», чтобы начать снимать производительность времени выполнения, затем перезагрузите приложение. И вы увидите временную шкалу что -то вроде этого:

Вы должны видеть, что требование модулей занимает много времени на временной шкале. Сколько времени это займет, зависит от того, сколько модулей/библиотек зависит ваше приложение.

В моем случае, мое приложение имеет огромное количество зависимостей, чтобы обеспечить свои возможности плагина, расширяемую редактор и рендерер, и так далее. Кажется, трудно отказаться от этих зависимостей ради скорости запуска.

Если у вас есть новый проект, вы должны тщательно выбрать библиотеки для производительности. Меньше зависимостей всегда лучше.

Не звоните require (), пока вам не понадобится

Первое, что вы можете сделать, чтобы избежать большого времени загрузки, это отложить вызов require () для ваших зависимостей, пока они не необходимы.

Мое главное окно приложения теперь показывает немного быстрее, чем старая версия. Это потому, что это загружалось JSDOM В основном процессе запуска. Я добавил его в анализ HTML, но обнаружил, что это огромная библиотека, и для загрузки требуется несколько сотен миллисекунд.

Есть несколько способов решить такую проблему.

1. Используйте более легкую альтернативу

Если вам было тяжело загружать, вы можете использовать небольшую альтернативную библиотеку, если существует. Оказалось, что мне не нужно JSDOM анализировать HTML, потому что есть Domparser в веб -API. Вы можете проанализировать HTML с ним так:

const dom = new DOMParser().parseFromString(html, 'text/html')

2. Избегайте требований к временю оценки

Вместо того, чтобы требовать библиотеки при оценке вашего кода:

import { JSDOM } from 'jsdom'

export function parseHTML(html) {
  const dom = new JSDOM(html);
  // ...
}

Отложить требует этого, пока вам не понадобится библиотека:

var jsdom = null

function get_jsdom() {
  if (jsdom === null) {
    jsdom = require('jsdom')
  }
  return jsdom
}

export function parseHTML(html) {
  const { JSDOM } = get_jsdom()
  const dom = new JSDOM(html);
  // ...
}

Это улучшит время вашего запуска, не отбросив зависимость. Обратите внимание, что вы должны исключить эти зависимости из вашего приложения, если вы используете модульный пакет, такой как WebPack.

Используйте снимки V8

Теперь мое приложение запускается на 200-300 мс быстрее, но все еще медленно загружается в процессе рендеринга. Большинство зависимостей нельзя отложить, чтобы потребоваться, поскольку они используются немедленно.

Хром должен читать и оценивать ваши JS и модули, которые требуют много времени, чем вы представляете, даже когда из локальной файловой системы (1-2 секунды в моем приложении). Большинству местных приложений не нужно это делать, потому что они уже находятся в двоичном коде, и ваша ОС может запускать их без перевода на машинный язык.

Двигатель JavaScript от Chromium – V8. И в V8 есть техника, чтобы ускорить вещи: Снимки V8 . Снимки V8 позволяют электронным приложениям выполнять какой -то произвольный код JavaScript и выводить двоичный файл, содержащий сериализованную кучу со всеми данными, которые остаются в памяти после запуска GC в конце предоставленного сценария.

Редактор Atom использовал снимки V8 и улучшенное время запуска 3 года назад:

Команда Atom совершила, чтобы увеличить время запуска на 500 мс на своей машине. Выглядит многообещающе.

Как работают снимки V8

Позвольте мне сразу добраться до сути – это отлично работало и для моего приложения. Например, загрузка Замечание-Парс был резко сократился.

Без снимков V8:

С снимками V8:

Прохладный!!!

Я мог бы улучшить время загрузки при оценке Браузер-Main.js из:

К:

Вот экрановый окно настройки загрузки, иллюстрируя, сколько снимков V8 улучшила скорость загрузки пакета приложений:

Но как загружать модули с снимков V8? В электронном приложении со своими пользовательскими снимками V8 вы получаете Snapshotresult переменная в глобальном объеме. Он содержит предварительно загруженные данные кэша JavaScript, которые уже выполняются заранее в следующем:

Вы можете использовать эти модули, не вызывая require () Анкет Вот почему снимки V8 работают очень быстро.

В следующем разделе я объясню, как создать ваши пользовательские снимки V8.

Как создать пользовательские снимки V8

Вы должны сделать следующие шаги:

  1. Установить инструменты
  2. Предварительно обрабатывать исходный файл JavaScript с Электронно-линк
  3. Создайте снимки V8 с mksnapshot
  4. Загрузите снимки в электроне

Я создал простой пример проекта для этого урока. Проверьте мой хранилище здесь:

Установить инструменты

Необходимы следующие пакеты:

электрон Время выполнения
Электронно-линк Предварительно обрабатывать исходные файлы JavaScript
Электрон-мксапшот Скачать двоичные файлы Mksnapshot

mksnapshot это инструмент для создания снимков V8 из вашего предварительного файла JavaScript с Электрон-Линк Анкет Electron-mksnapshot Помогает скачать совместимый mksnapshot двоичные файлы для электронов. Но если вы используете старую версию Electron, вы должны установить Electron_custom_version Переменная среда для вашей электронной версии:

# Install mksnapshot for Electron v8.3.0
ELECTRON_CUSTOM_VERSION=8.3.0 npm install

Загрузка двоичных файлов займет много времени. Вы можете использовать электронное зеркало, установив Electron_mirror переменные среды следующим образом:

# Electron mirror for China
ELECTRON_MIRROR="https://npm.taobao.org/mirrors/electron/"

Предварительно обрабатывать исходный файл JavaScript с помощью электронного соединения

Электрон-Линк Помогает вам сгенерировать файл JavaScript, который может быть снят снимком. Зачем вам это нужно, что вы не можете Требуется Некоторые модули, такие как встроенные модули Nodejs и собственные модули в контексте V8. Если у вас есть простое приложение, вы можете передать точку записи вашего приложения. В моем случае мое приложение было слишком сложным, чтобы сгенерировать файл, способный снимка. Итак, я решил создать еще один файл JS для создания снимков, которые просто требуют некоторых библиотек, когда они следующие:

// snapshot.js
require('react')
require('react-dom')
// ...require more libraries

Затем сохраните его как Snapshot.js в вашем каталоге проекта. Создайте следующий скрипт, который передает файл JS в Электрон-Линк :

const vm = require('vm')
const path = require('path')
const fs = require('fs')
const electronLink = require('electron-link')

const excludedModules = {}

async function main () {
  const baseDirPath = path.resolve(__dirname, '..')

  console.log('Creating a linked script..')
  const result = await electronLink({
    baseDirPath: baseDirPath,
    mainPath: `${baseDirPath}/snapshot.js`,
    cachePath: `${baseDirPath}/cache`,
    shouldExcludeModule: (modulePath) => excludedModules.hasOwnProperty(modulePath)
  })

  const snapshotScriptPath = `${baseDirPath}/cache/snapshot.js`
  fs.writeFileSync(snapshotScriptPath, result.snapshotScript)

  // Verify if we will be able to use this in `mksnapshot`
  vm.runInNewContext(result.snapshotScript, undefined, {filename: snapshotScriptPath, displayErrors: true})
}

main().catch(err => console.error(err))

Он выведет снимки снимка в /cache/snapshot.js Анкет Этот файл JS получен из Электрон-Линк Содержит библиотеки напрямую, как и пакет, который генерирует WebPack. На выводе запрещенные модули (то есть path ) отложены, чтобы они не были загружены в контексте V8 (для более подробной информации о документе Electron-Link для более подробной информации см. В документе, см. Electron-Link.

Создайте снимки V8 с помощью mksnapshot

Теперь у нас есть снимки снимка для создания снимков V8. Запустите приведенный ниже скрипт для этого:

const outputBlobPath = baseDirPath
console.log(`Generating startup blob in "${outputBlobPath}"`)
childProcess.execFileSync(
  path.resolve(
    __dirname,
    '..',
    'node_modules',
    '.bin',
    'mksnapshot' + (process.platform === 'win32' ? '.cmd' : '')
  ),
  [snapshotScriptPath, '--output_dir', outputBlobPath]
)

Проверьте весь скрипт Здесь, в примере репозитория Анкет

Наконец, вы получите v8_context_snapshot.bin файл в свой каталог проекта.

Загрузите снимки в электроне

Давайте загрузим ваши снимки V8 в приложение для электронов. Electron имеет файл снимка V8 по умолчанию в своем двоичном файле. Вы должны перезаписать это своим. Вот путь к снимкам V8 в электроне:

  • macOS: node_modules/electron/dist/electron.app/contents/frameworks/electron framework.framework/verions/a/resources/
  • Windows/Linux: node_modules/electron/dist/

Вы можете скопировать свой v8_context_snapshot.bin туда. Здесь это скрипт для копирования файла. Затем начните свое приложение, и вы должны получить снимки переменная в глобальном контексте. Тип Snapshotresult в консоли проверить, существует ли она.

Теперь у вас есть пользовательские снимки, загруженные в ваше электронное приложение. Как загрузить библиотеки зависимостей от них?

Вы должны переопределить по умолчанию Требуется функция как следующее:

const path = require('path')

console.log('snapshotResult:', snapshotResult)
if (typeof snapshotResult !== 'undefined') {
  console.log('snapshotResult available!', snapshotResult)

  const Module = require('module')
  const entryPointDirPath = path.resolve(
    global.require.resolve('react'),
    '..',
    '..',
    '..'
  )
  console.log('entryPointDirPath:', entryPointDirPath)

  Module.prototype.require = function (module) {
    const absoluteFilePath = Module._resolveFilename(module, this, false)
    let relativeFilePath = path.relative(entryPointDirPath, absoluteFilePath)
    if (!relativeFilePath.startsWith('./')) {
      relativeFilePath = `./${relativeFilePath}`
    }
    if (process.platform === 'win32') {
      relativeFilePath = relativeFilePath.replace(/\\/g, '/')
    }
    let cachedModule = snapshotResult.customRequire.cache[relativeFilePath]
    if (snapshotResult.customRequire.cache[relativeFilePath]) {
      console.log('Snapshot cache hit:', relativeFilePath)
    }
    if (!cachedModule) {
      console.log('Uncached module:', module, relativeFilePath)
      cachedModule = { exports: Module._load(module, this, false) }
      snapshotResult.customRequire.cache[relativeFilePath] = cachedModule
    }
    return cachedModule.exports
  }

  snapshotResult.setGlobals(
    global,
    process,
    window,
    document,
    console,
    global.require
  )
}

Обратите внимание, что вы должны запустить его перед загрузкой библиотек. Вы должны увидеть такие выходы, как «Кэш -кэш -снимки: реагировать» в консоли разработчика, если он работает должным образом. В примере проекта вы должны увидеть результат что -то вроде:

Поздравляю! У вас загружены зависимости вашего приложения с снимков V8.

Обоснованно построить экземпляр вашего приложения

Не только загрузка зависимостей из кэша, вы также можете использовать снимки для построения экземпляра вашего приложения, например Атом делает Анкет Некоторые из задач построения приложений будут статичными и могут быть снимками, даже если другие задачи, такие как чтение конфигурации пользователя, являются динамическими. Предварительно выполняя эти задачи инициализации с использованием снимков, скорость запуска может быть улучшена дальше. Но это зависит от вашей кодовой базы. Например, вы можете предварительно строить компоненты React в снимках.

Вот и все! Надеюсь, это полезно для разработки вашего приложения. Спасибо за чтение этого.

Я готовлюсь развернуть новую версию Inkdrop с этим улучшением. Надеюсь, тебе это понравится!

Смотрите также

Спасибо за вашу поддержку!

Оригинал: “https://dev.to/craftzdog/how-to-make-your-electron-app-launch-1-000ms-faster-3e0l”