Prepack был недавно открыт в Facebook и уже получил 4К звезды на Github (что здорово, учитывая, что он настолько новый, что им еще нужно выбрать значок для него!). В этом посте мы рассмотрим, что он предлагает и зачем вам это нужно?

Что такое Prepack?

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

Помимо всего этого объяснения, он ускоряет ваш код, заменяя его конечным состоянием переменных. Посмотри на эту магию -

Или этот с веб-сайта Prepack -

Как это работает?

Cop-out: Прочтите это для более подробного объяснения. Далее следует простой взгляд на процесс.

Prepack начинает свою работу с преобразования исходного кода в абстрактное синтаксическое дерево (которое является структурным представлением текста кода). Этот формат позволяет ему находить точки входа, которые инициализируют код вашего модуля. Затем он выполняет выполнение этого кода и определяет возможности оптимизации. Наконец, он заменяет части исходного AST оптимизированными версиями и преобразует их в JavaScript.

Как мне это помогает?

ИМО, Prepack предлагает две очень привлекательные возможности:

  1. Устранение налога на абстракцию:
    Функции ES 6, такие как новое заполнение массива и методы итерации, оператор распределения объектов, деструктуризация аргументов и т. Д., Позволяют писать очень читаемый код инициализации. Но это увеличивает стоимость выполнения каждый раз, когда загружается модуль.
    По возможности предварительно вычисляя экспортируемое состояние, Prepack полностью исключает затраты на эти абстракции во время выполнения, позволяя мне писать код, который приятен для глаз.
    Примечание: для использования Функции синтаксиса ES 6 (например, Object Spread) вам нужно будет перенести исходный код в ES 5, чтобы он работал с Prepack. Поддержка ES 6 находится в планах.
  2. Повышение производительности во время выполнения и размера пакета:
    Prepack делает упор на производительность во время выполнения за счет сокращения частей инициализации. Но полезным побочным эффектом этого процесса является то, что оптимизированный код может * часто * в конечном итоге оказаться меньше исходного кода до минимизации! В сочетании с бандлером, подобным Webpack, вы сможете получать более компактные сборки, которые также загружаются быстрее.

Могу ли я использовать его для производства?

Prepack - это очень новая идея, и она все еще находится в стадии разработки. Вы можете обнаружить подобные проблемы с процессом конвертации :). Попробуйте это в настройках вашего разработчика или воспользуйтесь REPL и поделитесь своим мнением!

Короткий эксперимент

Я создал базовую демонстрацию работы Prepack в простом коде библиотеки ES 6 на базе Webpack 2.0. Сделать репо можно здесь. Код библиотеки довольно скудный, он экспортирует объект регистратора, который создает оболочку вокруг некоторых методов consoleobject. Вот код -

Итак, здесь мы создаем класс Logger, который имеет свойство LOG_STATUS_FLAGS как объект, содержащий константы уровня журнала:

LOG_STATUS_FLAGS: {
    error: "error",
    warn: "warn",
    info: "info",
    debug: "debug",
    silly: "silly"
}

В своем конструкторе класс Logger принимает реальную цель журнала в качестве аргумента, а затем приступает к созданию методов оболочки для каждого значения в LOG_STATUS_FLAGS, которые определены в цели журнала. В коде используются вспомогательные методы из превосходной функциональной библиотеки Ramda для некоторых задач по изменению формы. Он также использует метод curried log для создания оболочек.

Вы можете увидеть результат сценария вывода без Prepack (npm run build). Я встроил его как ссылку Gist, но из-за того, что он занимал 620 строк, сообщение было трудно читать.

Теперь давайте перестроим тот же код с помощью Prepack. В демонстрационном проекте это можно сделать, запустив npm run build:prepack. Вот результат для вашего прочтения -

Сокращение количества строк до 37 из 620, чистая экономия 94% !! Неплохо для неминифицированного кода.

Глядя на код, Prepack сократил экспортированный объект до самого необходимого. Исчезли нерелевантные промежуточные моменты, такие как сам класс Logger! Или несколько импортированных из Ramda! Он также создал предварительные - связанные версии каррированного метода log и создал новый метод с именем $_0, который использует остальные параметры.

Однако здесь мне нужно было поработать с Prepack. Например, в Строке № 21 в index.js я экспортирую экземпляр класса Logger, предварительно привязанный к console:

module.exports = Object.assign({}, new Logger(console));

Это позволило Prepack оценить полученный объект во время сборки, а затем удалить все, что не было его частью. Попробуйте экспортировать класс Logger напрямую, а не экземпляр, и вы увидите гораздо меньшую экономию, если вообще сэкономите.

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