Вторая часть: скрипт сборки и генерация ассетов.

Это вторая часть сообщения о создании конвейера, который может принимать файл Sketch и экспортировать все значки, включенные в файл, в разных форматах, для разных платформ, с возможностью AB-тестирования каждого значка.

Вы можете прочитать первую часть сообщения здесь: https://medium.com/@didoo/generating-multi-brand-multi-platform-icons-with-sketch-and-a-node-js-script-part1 -82f438c7e16c

Файлы Sketch со всеми собранными иконками, стилизованными и названными должным образом, были готовы. Пришло время писать код.

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

Скрипт сборки

Сценарий сборки, написанный на Node.js, относительно прост в своем потоке: после импорта зависимостей объявляется список файлов Sketch для обработки (в виде списка брендов, а для каждого бренда список файлов для этого бренда) и проверил, что Sketch установлен на клиенте, скрипт зацикливается на массиве брендов и для каждого из них последовательно выполняет следующие шаги:

  1. получить жетоны дизайна для бренда (нам нужны значения цвета)
  2. клонировать файлы Sketch, связанные с брендом, разархивировать их, чтобы открыть внутренние файлы JSON, и управлять некоторыми внутренними значениями этих файлов JSON (подробнее об этом позже)
  3. считывать соответствующие метаданные из файлов Sketch JSON (document.json, meta.json и pages / pageUniqueID.json); в частности, нам нужен список общих стилей и список ресурсов / значков, содержащихся в файлах.
  4. после нескольких дополнительных манипуляций с файлами Sketch JSON, заархивируйте их обратно и, используя (клонированные и обновленные) файлы Sketch, экспортируйте и сгенерируйте окончательные выходные файлы для трех платформ (iOS, Android, Mobile Web)

Вы можете просмотреть соответствующие части основного скрипта сборки здесь:

// ... modules imports here
const SKETCH_FILES = {
  badoo: ['icons_common'],
  blendr: ['icons_common', 'icons_blendr'],
  fiesta: ['icons_common', 'icons_fiesta'],
  hotornot: ['icons_common', 'icons_hotornot'],
};
const SKETCH_FOLDER_PATH = path.resolve(__dirname, '../src/');
const SKETCH_TEMP_PATH = path.resolve(SKETCH_FOLDER_PATH, 'tmp');
const DESTINATION_PATH = path.resolve(__dirname, '../dist');
console.log('Build started...');
if (sketchtool.check()) {
  console.log(`Processing Sketch file via ${sketchtool.version()}`);
  build();
} else {
  console.info('You need Sketch installed to run this script');
  process.exit(1);
}
// ----------------------------------------
function build() {
  // be sure to start with a blank slate
  del.sync([SKETCH_TEMP_PATH, DESTINATION_PATH]);
  // process all the brands declared in the list of Sketch files
  Object.keys(SKETCH_FILES).forEach(async (brand) => {
    // get the design tokens for the brand
    const brandTokens = getDesignTokens(brand);
    
    // prepare the Sketch files (unzipped) and get a list of them
    const sketchUnzipFolders = await prepareSketchFiles({
      brand,
      sketchFileNames: SKETCH_FILES[brand],
      sketchFolder: SKETCH_FOLDER_PATH,
      sketchTempFolder: SKETCH_TEMP_PATH
    });
    // get the Sketch metadata
    const sketchMetadata = getSketchMetadata(sketchUnzipFolders);
    const sketchDataSharedStyles = sketchMetadata.sharedStyles;
    const sketchDataAssets = sketchMetadata.assetsMetadata;
    generateAssetsPDF({
      platform: 'ios',
      brand,
      brandTokens,
      sketchDataSharedStyles,
      sketchDataAssets
    });
    generateAssetsSVGDynamicMobileWeb({
      platform: 'mw',
      brand,
      brandTokens,
      sketchDataSharedStyles,
      sketchDataAssets
    });
    generateAssetsVectorDrawableDynamicAndroid({
      platform: 'android',
      brand,
      brandTokens,
      sketchDataSharedStyles,
      sketchDataAssets
    });
  });
}

На самом деле весь код конвейера намного сложнее, чем этот, и сложность заключается в функциях prepareSketchFiles, getSketchMetadata и generateAssets [format] [platform]. Я постараюсь объяснить их более подробно ниже.

Подготовка файлов Sketch

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

Файлы, связанные с брендом - например, для Blendr файлы icons_common.sketch и icons_blendr.sketch - изначально клонируются во временную папку (точнее, в вложенная папка, названная в честь обрабатываемого бренда) и разархивируйте.

Затем внутренние файлы JSON обрабатываются с добавлением префикса к активам, которые должны пройти тестирование AB, так что при экспорте они будут сохранены в подпапке с предопределенным именем (уникальное имя эксперимента). Чтобы понять, какие ресурсы предназначены для тестирования, мы просто проверяем, имеет ли имя страницы, на которой они хранятся в Sketch, префикс «XP_».

В приведенном выше примере при экспорте ресурсы будут сохранены в подпапке «this__is_an_experiment» с именем файла «имя-значка [имя-варианта] .ext».

Чтение метаданных Sketch

Второй важный шаг в процессе - получить все соответствующие метаданные из файлов Sketch, в частности из их внутренних файлов JSON. Как объяснялось выше, это два основных файла (document.json и meta.json) и файлы страниц (pages / pageUniqueId.json ).

Файл document.json используется для получения списка общих стилей, которые отображаются под свойством объекта layerStyles:

{
  "_class": "document",
  "do_objectID": "45D2DA82-B3F4-49D1-A886-9530678D71DC",
  "colorSpace": 1,
  ...
  "layerStyles": {
    "_class": "sharedStyleContainer",
    "objects": [
      {
        "_class": "sharedStyle",
        "do_objectID": "9BC39AAD-CDE6-4698-8EA5-689C3C942DB4",
        "name": "features/feature-like",
        "value": {
          "_class": "style",
          "fills": [
            {
              "_class": "fill",
              "isEnabled": true,
              "color": {
                "_class": "color",
                "alpha": 1,
                "blue": 0.10588235408067703,
                "green": 0.4000000059604645,
                "red": 1
              },
              "fillType": 0,
              "noiseIndex": 0,
              "noiseIntensity": 0,
              "patternFillType": 1,
              "patternTileScale": 1
            }
          ],
          "blur": {...},
          "startMarkerType": 0,
          "endMarkerType": 0,
          "miterLimit": 10,
          "windingRule": 1
        }
      },
      ...

Для каждого стиля мы храним некоторую базовую информацию в объекте "ключ-значение". Это будет использоваться позже, когда нам нужно будет получить имя стиля на основе его уникального идентификатора (в Sketch свойство do_objectID):

const parsedSharedStyles = {};
parsedDocument.layerStyles.objects.forEach((object) => {
  parsedSharedStyles[object.do_objectID] = {
    name: object.name,
    isFill: _.get(object, 'value.fills[0].color') !== undefined,
    isBorder: _.get(object, 'value.borders[0].color') !== undefined,
  };
});

На этом этапе мы переходим к файлу meta.json, чтобы получить список страниц, в частности, нам нужны их unique-id и name. :

{
  "commit": "623a23f2c4848acdbb1a38c2689e571eb73eb823",
  "pagesAndArtboards": {
    "EE6BE8D9-9FAD-4976-B0D8-AB33D2B5DBB7": {
      "name": "Icons",
      "artboards": {
        "3275987C-CE1B-4369-B789-06366EDA4C98": {
          "name": "badge-feature-like"
        },
        "C6992142-8439-45E7-A346-FC35FA01440F": {
          "name": "badge-feature-crush"
        },
        ...
        "7F58A1C4-D624-40E3-A8C6-6AF15FD0C32D": {
          "name": "tabbar-livestream"
        }
        ...
      }
    },
    "ACF82F4E-4B92-4BE1-A31C-DDEB2E54D761": {
      "name": "XP_this__is_an_experiment",
      "artboards": {
        "31A812E8-D960-499F-A10F-C2006DDAEB65": {
          "name": "this__is_an_experiment/tabbar-livestream[variant1]"
        },
        "20F03053-ED77-486B-9770-32E6BA73A0B8": {
          "name": "this__is_an_experiment/tabbar-livestream[variant2]"
        },
        "801E65A4-3CC6-411B-B097-B1DBD33EC6CC": {
          "name": "this__is_an_experiment/tabbar-livestream[control]"
        }
      }
    },

Затем для каждой страницы мы читаем соответствующий файл JSON в папке pages (как уже было сказано, имя файла - [pageUniqueId] .json) и просматриваем ресурсы. содержащиеся на этой странице (они отображаются как слои). Таким образом, для каждого значка мы получаем его имя, его ширину / высоту, метаданные скетча для этого значка слоя, и если он находится на странице эксперимента, название рассматриваемого теста AB и название варианта для этого значка.

Обратите внимание: объект page.json очень сложен, поэтому я не буду здесь вдаваться в подробности. Если вам интересно, и вы хотите посмотреть, как это выглядит, я предлагаю вам создать новый пустой файл Sketch, добавить в него некоторое содержимое и сохранить его; затем переименуйте его расширение в zip, разархивируйте его и откройте один из файлов, находящихся в папке «Pages».

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

Для каждого обрабатываемого файла Sketch, связанного с брендом, мы создаем объект assetsMetadata, который выглядит следующим образом:

{
  "navigation-bar-edit": {
    "do_objectID": "86321895-37CE-4B3B-9AA6-6838BEDB0977",
    ...sketch_artboard_properties,
    "name": "navigation-bar-edit",
    "assetname": "navigation-bar-edit",
    "source": "icons_common",
    "width": 48,
    "height": 48
    "layers": [
      {
        "do_objectID": "A15FA03C-DEA6-4732-9F85-CA0412A57DF4",
        "name": "Path",
        ...sketch_layer_properties,
        "sharedStyleID": "6A3C0FEE-C8A3-4629-AC48-4FC6005796F5",
        "style": {
          ...
          "fills": [
            {
              "_class": "fill",
              "isEnabled": true,
              "color": {
                "_class": "color",
                "alpha": 1,
                "blue": 0.8784313725490196,
                "green": 0.8784313725490196,
                "red": 0.8784313725490196
              },
            }
          ],
          "miterLimit": 10,
          "startMarkerType": 0,
          "windingRule": 1
        },
      },
    ],
    ...
  },
  "experiment-name/navigation-bar-edit[variant]": {
    "do_objectID": "00C0A829-D8ED-4E62-8346-E7EFBC04A7C7",
    ...sketch_artboard_properties,
    "name": "experiment-name/navigation-bar-edit[variant]",
    "assetname": "navigation-bar-edit",
    "source": "icons_common",
    "width": 48,
    "height": 48
    ...

Как видите, один и тот же «значок» (в данном случае navigation-bar-edit) может иметь несколько связанных с ним «ресурсов» в терминах экспериментов. Но тот же значок может отображаться с тем же именем во втором файле Sketch, связанном с брендом, и это очень полезно: мы использовали этот трюк, чтобы скомпилировать общий набор значков, а затем определить конкретные различные варианты значков в зависимости от бренда. Вот почему мы объявили файлы Sketch, связанные с каждым конкретным брендом, в виде массива:

const SKETCH_FILES = {
  badoo: ['icons_common'],
  blendr: ['icons_common', 'icons_blendr'],
  fiesta: ['icons_common', 'icons_fiesta'],
  hotornot: ['icons_common', 'icons_hotornot'],
};

Потому что в этом случае порядок имеет значение. Фактически, в функции getSketchMetadata, вызываемой сценарием сборки, мы не возвращаем объекты assetsMetadata (по одному на файл) в виде списка, а делаем глубокое слияние каждого объекта друг с другом, а затем мы возвращаем один объединенный объект assetsMetadata.

Это не что иное, как «логическое» слияние файлов Sketch и их ресурсов в один файл. Но логика на самом деле не так проста, как кажется. Вот схема, которую нам пришлось создать, чтобы выяснить, что происходит, когда есть значки с одинаковым именем (возможно, при тестировании AB) в разных файлах, связанных с одним и тем же брендом:

Генерация финальных файлов в разных форматах для разных платформ

Последний шаг процесса - фактическое создание файлов значков в разных форматах для разных платформ (PDF для iOS, SVG / JSX для Интернета и VectorDrawable для Android).

Как видно из количества параметров, переданных функциям generateAssets [format] [platform], это самая сложная часть конвейера. Здесь процесс начинает разделяться и расходиться для разных платформ. См. Ниже полный логический поток скрипта и то, как часть, связанная с генерацией ресурсов, разделяется на три похожих, но не идентичных потока:

Чтобы сгенерировать окончательные активы с правильными цветами, соответствующими обрабатываемому бренду, нам нужно выполнить еще один набор манипуляций с файлами Sketch JSON: мы итеративно переберите каждый слой, к которому применен общий стиль, и замените значения цвета цветами из маркеров дизайна для бренда.

Для поколения Android требуется дополнительная манипуляция (подробнее об этом позже): мы меняем свойство правила заполнения каждого слоя с четный-нечетный на ненулевое (это контролируется свойством «windingRule» в объекте JSON, где «1» означает «четно-нечетное», а «0» означает «не -нуль").

Завершив эти манипуляции, мы сжимаем файлы Sketch JSON обратно в стандартный файл Sketch, чтобы его можно было обработать для экспорта ресурсов с обновленными свойствами (клонированные и обновленные файлы являются абсолютно обычными файлами Sketch: их можно открывать в Sketch. , просмотрены, отредактированы, сохранены и т. д.).

На этом этапе мы можем использовать sketchtool (в оболочке узла) для автоматического экспорта всех ресурсов в определенные форматы для определенных платформ. Для каждого файла, связанного с брендом (точнее, его клонированной и обновленной версии) мы запускаем эту команду:

sketchtool.run(`export slices ${cloneSketchFile} --formats=svg --scales=1 --output=${destinationFolder} --overwriting`);

Как вы могли догадаться, эта команда экспортирует ресурсы в определенном формате, применяя дополнительное масштабирование (пока мы всегда сохраняем исходный масштаб) в папку назначения. Параметр --overwriting является здесь ключевым: точно так же, как мы выполняем «глубокое слияние» объектов assetsMetadata (которое представляет собой «логическое слияние» файлов Sketch), когда мы экспортируем мы делаем это из нескольких файлов в одну и ту же папку (уникальную для каждой марки / платформы). Это означает, что если актив, идентифицируемый по имени слоя, уже существовал в предыдущем файле Sketch, он будет перезаписан при следующем экспорте. Что, опять же, не более чем операция «слияния».

Однако в этом случае у нас могут быть некоторые активы, которые являются «призраками». Это происходит, когда значок AB-тестируется в файле, но перезаписывается в следующем файле. В таких случаях файлы вариантов экспортируются в папку назначения, указанную в объекте assetsMetadata как актив (с его ключом и свойствами), но не связанные ни с одним «базовым» активом (из-за глубокого слияние объектов assetsMetadata). Эти файлы будут удалены на более позднем этапе до завершения процесса.

Как упоминалось выше, нам нужны разные конечные форматы для разных платформ. Для iOS нам нужны файлы PDF, и мы можем экспортировать их напрямую с помощью команды sketchtool. В то время как для мобильного Интернета нам нужны файлы JSX, а для Android - файлы VectorDrawable; по этой причине мы экспортируем активы в формате SVG в промежуточную папку, а затем подвергаем их дальнейшей обработке.

PDF-файлы для iOS

Как ни странно, PDF - это (единственный?) Формат, поддерживаемый Xcode и OS / iOS для импорта и рендеринга векторных ресурсов (вот краткое объяснение технических причин этого выбора Apple).

Поскольку мы можем экспортировать напрямую в PDF через Sketchtool, для этой платформы нет необходимости в дополнительных действиях: мы просто сохраняем файлы прямо в папке назначения, и все.

Файлы React / JSX для Интернета

В случае Web мы используем библиотеку узлов под названием svgr, которая преобразует простые файлы SVG в компоненты React. Но мы хотим сделать что-то еще более мощное: мы хотим динамически раскрашивать значок во время выполнения, используя цвета из маркеров дизайна. По этой причине непосредственно перед преобразованием мы заменяем в SVG значения fill путей, к которым изначально был применен общий стиль, на соответствующее значение токена, связанное с этим стилем.

Итак, если это файл badge-feature-like.svg, экспортированный из Sketch:

<?xml version="1.0" encoding="UTF-8"?>
<svg width="128px" height="128px" viewBox="0 0 128 128" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
  <!-- Generator: sketchtool 52.2 (67145) - http://www.bohemiancoding.com/sketch -->
  <title>badge-feature-like</title>
  <desc>Created with sketchtool.</desc>
  <g id="Icons" fill="none" fill-rule="evenodd">
    <g id="badge-feature-like">
      <circle id="circle" fill="#E71032" cx="64" cy="64" r="64">
      <path id="Shape" fill="#FFFFFF" d="M80.4061668,..."></path>
    </g>
  </g>
</svg>

последний объект / значок badge-feature-like.js будет выглядеть так:

/* This file is generated automatically - DO NOT EDIT */
/* eslint-disable max-lines,max-len,camelcase */
const React = require('react');
module.exports = function badge_feature_like({ tokens }) {
  return (
    <svg data-origin="pipeline" viewBox="0 0 128 128">
      <g fill="none" fillRule="evenodd">
        <circle fill={tokens.TOKEN_COLOR_FEATURE_LIKED_YOU} cx={64} cy={64} r={64} />
        <path fill="#FFF" d="M80.4061668,..." />
      </g>
    </svg>
  );
};

Как видите, мы заменили статическое значение для цвета заливки круга на динамическое, значение которого берется из токенов дизайна (они будут доступны для React ‹Icon /› через Context API, но это уже другая история).

Эта замена стала возможной благодаря метаданным Sketch для ресурса, хранящегося в объекте assetsMetadata: рекурсивно перебирая слои ресурса, можно создать селектор DOM (в приведенном выше случае это будет #Icons # badge-feature-like #circle) и используйте его, чтобы найти узел в дереве SVG и заменить значение его атрибута fill (для этой операции мы воспользуйтесь библиотекой cheerio).

Файлы VectorDrawable для Android

Android поддерживает векторную графику, используя собственный векторный формат, называемый VectorDrawable. Обычно преобразование из SVG в VectorDrawable выполняется разработчиками непосредственно в Android Studio. Но здесь мы хотели автоматизировать весь процесс, поэтому нам нужно было найти способ конвертировать их с помощью кода.

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

Дело в том, что VectorDrawable не соответствует функциям SVG: некоторые из расширенных функций SVG (например, радиальные градиенты, сложные маски и т. Д.) Не поддерживаются, а некоторые из них получили поддержку только недавно (с Android API 24 и выше). Одним из недостатков этого является то, что в Android до 24 правило заполнения« четно-нечетное не поддерживается». Но в Badoo нам необходимо поддерживать Android 5 и выше. Вот почему, как объяснялось выше, для Android нам нужно преобразовать каждый путь в файлах Sketch в ненулевую заливку.

Потенциально дизайнеры могли бы сделать это вручную:

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

По этой причине мы добавили дополнительный шаг в наш процесс для Android, на котором мы автоматически конвертируем все пути в ненулевые в Sketch JSON. Это значит, что когда мы экспортируем значки в SVG, они уже находятся в этом формате, и каждый созданный VectorDrawable также совместим с устройствами Android 5.

Последний файл badge-feature-like.xml в этом случае выглядит так:

<!-- This file is generated automatically - DO NOT EDIT -->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
  android:width="128dp"
  android:height="128dp"
  android:viewportWidth="128"
  android:viewportHeight="128">
  <path
    android:fillColor="?color_feature_liked_you"
    android:pathData="M64 1a63 63 0 1 0 0 126A63 63 0 1 0 64 1z"
  />
  <path
    android:fillColor="#FFFFFF"
    android:pathData="M80.406 ..."
  />
</vector>

Как видите, также в файлы VectorDrawable мы добавляем имена переменных для цветов заливки, которые связаны с маркерами дизайна через пользовательские стили в приложениях Android.

Вот как выглядит VectorDrawable после импорта в Android Studio:

В этом случае следует отметить одну вещь: Android Studio имеет очень строгий и предписывающий способ организации ресурсов: нет вложенных папок и все имена в нижнем регистре! Это означало, что нам пришлось придумать немного другой формат для их имен значков: в случае объекта, находящегося в эксперименте, его имя будет примерно таким: ic_icon-name__experiment-name__variant-name.

Словарь JSON как библиотека активов

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

После извлечения плоского списка значков из объекта assetsMetadata мы перебираем его и для каждого проверяемого элемента:

  • если это обычный актив (например, tabbar-livestream), и если это так, мы просто сохраняем его;
  • если это вариант в тесте AB (например, эксперимент / tabbar-livestream [вариант]), мы связываем его имя, путь, тест AB и имена вариантов со свойством abtests «базового» ресурса (в данном случае tabbar-livestream), а затем мы удаляем вариантную запись из списка / объекта (учитывается только «базовый» );
  • если это «призрачный» вариант, мы удаляем файл, а затем удаляем запись из списка / объекта.

После завершения цикла словарь будет содержать список всех и только «базовых» значков (и их AB-тестов, если они находятся в эксперименте). Для каждого из них он будет содержать его имя, размер, путь и, если значок находится под AB-тестированием, информацию о разные варианты объекта.

Затем этот словарь сохраняется в формате JSON в папке назначения для бренда и платформы. Вот, например, файл assets.json, созданный для приложения «Blendr» в «мобильном Интернете»:

{
  "platform": "mw",
  "brand": "blendr",
  "assets": {
      "badge-feature-like": {
      "assetname": "badge-feature-like",
      "path": "assets/badge-feature-like.jsx",
      "width": 64,
      "height": 64,
      "source": "icons_common"
    },
    "navigation-bar-edit": {
      "assetname": "navigation-bar-edit",
      "path": "assets/navigation-bar-edit.jsx",
      "width": 48,
      "height": 48,
      "source": "icons_common"
    },
    "tabbar-livestream": {
      "assetname": "tabbar-livestream",
      "path": "assets/tabbar-livestream.jsx",
      "width": 128,
      "height": 128,
      "source": "icons_blendr",
      "abtest": {
        "this__is_an_experiment": {
          "control": "assets/this__is_an_experiment/tabbar-livestream__control.jsx",
          "variant1": "assets/this__is_an_experiment/tabbar-livestream__variant1.jsx",
          "variant2": "assets/this__is_an_experiment/tabbar-livestream__variant2.jsx"
        },
        "a_second-experiment": {
          "control": "assets/a_second-experiment/tabbar-livestream__control.jsx",
          "variantA": "assets/a_second-experiment/tabbar-livestream__variantA.jsx"
        }
      }
    },
    ...
  }
}

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

Конечный результат

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

Ниже приведен снимок экрана, на котором показана структура папок src и dist после завершения процесса сборки:

На этом этапе с помощью одной простой команды можно загрузить все ресурсы (файлы JSON, файлы ZIP и файлы ресурсов) в удаленный репозиторий и сделать их доступными для всех различных платформ для загрузки и использования в их базах кода.

(То, как реальные платформы извлекают и обрабатывают ресурсы - с помощью специальных сценариев, специально созданных для этой цели, - выходит за рамки данной статьи. Но это, вероятно, очень скоро будет рассмотрено в других специальных сообщениях блога, автор: один из других разработчиков, которые работали со мной над этим проектом).

Выводы (и извлеченные уроки)

Мне всегда нравился Скетч. В течение многих лет это был де-факто инструмент выбора для веб-дизайна (и разработки). Поэтому мне было очень интересно и любопытно изучить возможные интеграции, такие как html-sketchapp или аналогичные инструменты, которые мы могли бы использовать в наших рабочих процессах и конвейерах.

Этот (идеальный) поток всегда был святым Граалем для меня (и многих других):

Но я должен признать, что недавно я начал задаваться вопросом, был ли Sketch по-прежнему правильным инструментом, особенно в контексте системы дизайна. Итак, я начал изучать новые инструменты, такие как Figma с его открытыми API-интерфейсами и Framer X с его невероятной интеграцией с React, потому что я не видел эквивалентных усилий со стороны Sketch по переходу к интеграции с кодом (независимо от того, какой код он является).

Что ж, этот проект передумал. Не полностью, но определенно много.

Возможно, Sketch официально не раскрывает свои API, но, безусловно, способ, которым они построили внутреннюю структуру своих файлов, является своего рода «неофициальным» API. Они могли использовать загадочные имена или запутать ключи в объектах JSON; вместо этого они выбрали ясное, легкое для чтения, понятное человеку, семантическое соглашение об именах. Не могу думать, что это просто случайность.

Тот факт, что файлами Sketch можно манипулировать, открыл мне широкий спектр возможных будущих разработок и улучшений. От плагинов для проверки именования, стиля и структуры слоев для значков до возможных интеграций с нашей вики и документацией по нашей системе проектирования (в обоих направлениях), путем создания приложений Node, размещенных в Electron или Carlo, и облегчить выполнение многих повторяющихся задач, которые приходится решать дизайнерам.

Одним из неожиданных бонусов этого проекта (по крайней мере, для меня) является то, что теперь файлы Sketch с иконками Cosmos стали источником истины, подобно тому, что произошло с Cosmos design система". Если значка нет, значит, его нет в базе кода (или, лучше сказать, не должно быть: но, по крайней мере, мы знаем, что это исключение). Я знаю, что сейчас это кажется очевидным, но раньше этого не было, по крайней мере, для меня.

То, что начиналось как проект MVP, вскоре превратилось в глубокое (буквально) погружение во внутреннее устройство файлов Sketch с осознанием того, что ими можно манипулировать. Мы пока не знаем, к чему все это приведет, но пока это удалось. Дизайнеры, разработчики, менеджеры по продвижению и заинтересованные стороны согласны с тем, что это избавит всех от ручной работы и предотвратит множество потенциальных ошибок. Но это также откроет двери для использования значков, что до сих пор было невозможно.

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

Но для меня важно то, чем я хотел поделиться, так это то, что это возможно. Может быть, по-разному, с разными подходами и разными форматами вывода, возможно, с меньшей сложностью (например, вам может не понадобиться мультибрендинг и AB-тестирование). Но теперь вы можете автоматизировать рабочий процесс, связанный с доставкой значков, с помощью настраиваемого скрипта Node.js и Sketch.

Найдите свой собственный способ сделать это. Это весело (и относительно легко).

Кредиты

Этот огромный проект был разработан в сотрудничестве с Nikhil Verma (Mobile Web), создавшим первую версию скрипта сборки, и Artem Rudoi (Android) и Игорь Савельев (iOS), который разработал скрипты, импортирующие и потребляющие ресурсы на своих родных платформах. Спасибо, ребята, было здорово работать с вами над этим проектом и смотреть, как он оживает. 🚀