Sketch + Node.js: générez des icônes pour de nombreuses plateformes et marques. 2e partie



Il s'agit de la deuxième partie de l'article sur la création d'un outil capable d'exporter toutes les icônes placées dans un fichier Sketch: dans différents formats, pour différentes plateformes, avec la possibilité de tester A / B de chaque icône.

Vous pouvez lire la première partie du lien .



La dernière fois, nous avons préparé des fichiers Sketch contenant toutes les icônes dans les bons styles et avec les noms corrects. C'est au tour d'écrire du code.

Il suffit de dire que nous avons fait des essais et des erreurs. Après que notre chef d'équipe Nihil Verma , qui a jeté les bases du script, ait développé le code source clé, j'ai commencé un processus qui a nécessité au moins trois phases de refactoring et de nombreuses modifications. Pour cette raison, je n'entrerai pas dans les détails de la création du script et ne me concentrerai pas sur la façon dont il fonctionne aujourd'hui, dans sa forme finale.

Créer un script


Le script de construction écrit sur Node.js est assez simple dans son travail: en important des dépendances, en déclarant une liste de fichiers Sketch à traiter (c'est une liste de marques, chacune ayant une liste de fichiers associés) et en s'assurant que Sketch est installé sur le client , le script traite les marques à tour de rôle, effectuant une série d'actions avec chacune d'elles.

  1. Prend des jetons de conception appropriés pour les marques (nous avons besoin de valeurs de couleur).
  2. Clone les fichiers Sketch associés à la marque, les décompresse pour extraire les fichiers JSON internes et traite certaines de leurs valeurs internes (plus d'informations plus loin).
  3. Lit les métadonnées nécessaires à partir de ces fichiers JSON ( document.json , meta.json et pages / pageUniqueID.json ). Nous sommes intéressés par les listes de styles courants et de ressources / icônes contenues dans les fichiers.
  4. Après quelques manipulations supplémentaires avec les fichiers JSON, il recrée l'archive et, à l'aide de fichiers Sketch (clonés et mis à jour), exporte et crée les fichiers de sortie finaux pour trois plates-formes (iOS, Android, Web mobile).

Les parties pertinentes du script de construction peuvent être trouvées ici:

// ... 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   }); }); } 

En fait, le code du pipeline est beaucoup plus compliqué. La raison de cette complexité réside dans les fonctions prepareSketchFiles , getSketchMetadata et generateAssets[format][platform] . Ci-dessous, je vais essayer de les décrire plus en détail.

Préparation des fichiers d'esquisse


La première étape du processus d'assemblage est la préparation des fichiers Sketch, qui seront ensuite utilisés pour exporter des ressources pour différentes plates-formes.

Les fichiers associés à une marque particulière (par exemple, dans le cas de Blendr, il s'agit des fichiers icons_common.sketch et icons_blendr.sketch ) sont clonés dans un dossier temporaire (plus précisément, dans un sous-dossier nommé d'après la marque en cours de traitement) et décompressé.

Ensuite, les fichiers JSON sont traités. Un préfixe est ajouté au nom des ressources soumises aux tests A / B - ainsi, lors de l'exportation, elles seront enregistrées dans un sous-dossier avec un nom prédéfini (correspondant au nom unique de l'expérience). Vous pouvez comprendre si une ressource est soumise à un test A / B par le nom de la page sur laquelle elle est stockée: si c'est le cas, le nom contiendra le préfixe " XP_ ".



Dans l'exemple ci-dessus, les ressources exportées seront stockées dans un sous-dossier de « this__is_an_experiment » avec un nom de fichier de la forme « nom-icône [nom-variante] .ext ».

Lecture des métadonnées d'un croquis


La deuxième étape importante consiste à extraire toutes les métadonnées nécessaires des fichiers Sketch, ou plutôt des fichiers JSON internes. Comme nous l'avons vu ci-dessus, ce sont deux fichiers principaux ( document.json et meta.json ) et des fichiers de page ( pages / pageUniqueId.json ).

Le fichier document.json est utilisé pour obtenir la liste des styles courants qui apparaît sous la propriété de l'objet 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      }    },    ... 

Nous stockons des informations de base sur chaque style dans un objet au format clé-valeur. Il sera utilisé plus tard lorsque nous aurons besoin d'extraire le nom du style sur la base d'un ID unique (propriété do_objectID dans Sketch):

 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, }; }); 

Maintenant, nous allons dans le fichier meta.json et obtenons une liste de pages. Nous sommes intéressés par leur unique-id et leur 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]"      }    }  }, 

Ensuite, nous lisons les fichiers JSON correspondant à chaque page du dossier pages (je répète que les noms de fichiers sont au format [pageUniqueId] .json ) et étudions les ressources stockées sur cette page (elles ressemblent à des calques). Ainsi, nous obtenons le nom , la largeur / hauteur de chaque icône, les métadonnées Sketch pour l'icône de cette couche, et si nous avons affaire à une page d' expérimentation , alors le nom du test A / B et une variante de cette icône.

Remarque : l'objet page.json a un périphérique très complexe, donc je ne m'attarderai pas dessus. Si vous êtes intéressé par ce qu'il y a à l'intérieur, je vous conseille de créer un nouveau fichier Sketch vide, d'y ajouter du contenu et de l'enregistrer; puis renommez son extension en ZIP, décompressez-la et examinez l'un des fichiers du dossier pages.

Dans le processus de traitement des plans de travail, nous créerons également une liste d'expériences (et de ressources connexes). Nous en aurons besoin pour déterminer quelles variations de l'icône sont utilisées dans quelle expérience - les noms des variations de l'icône sont attachés à l'objet «de base».

Pour chaque fichier Sketch assetsMetadata marque en cours de traitement, nous créons un objet assetsMetadata qui ressemble à ceci:

 { "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  ... 

Comme vous pouvez le voir, dans l'expérience, une seule icône (dans ce cas, navigation-bar-edit ) peut correspondre à de nombreuses ressources. Dans le même temps, la même icône peut apparaître sous le même nom dans un autre fichier Sketch associé à la marque. C'est très utile : nous utilisons cette astuce pour compiler un ensemble commun d'icônes, puis identifier des options spécifiques en fonction de la marque. C'est pourquoi nous avons déclaré les fichiers Sketch associés à une marque particulière en tant que tableau:

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

Dans ce cas, l'ordre est d'une importance fondamentale. En fait, dans la fonction getSketchMetadata appelée par le script, nous ne assetsMetadata objets assetsMetadata un par un sous la forme d'un fichier de liste. Au lieu de cela, nous effectuons une fusion profonde des objets - nous les combinons et assetsMetadata un seul objet assetsMetadata .

En général, ce n'est rien d'autre qu'une fusion «logique» de fichiers Sketch et de leurs ressources en un seul fichier. Cependant, la logique n'est pas aussi simple qu'il y paraît. Voici un diagramme que nous avons créé pour tenter de comprendre ce qui se passe lorsque des icônes portant le même nom (et éventuellement soumises à des tests A / B) dans différents fichiers sont associées à la même marque:



Création de fichiers prêts à l'emploi dans différents formats pour différentes plateformes


La dernière étape de notre processus consiste à créer directement des fichiers d'icônes dans différents formats pour différentes plates-formes (PDF pour iOS, SVG / JSX pour Web et VectorDrawable pour Android).

Comme vous pouvez le voir d'après le nombre de paramètres transmis aux fonctions generateAssets[format][platform] , cette partie du pipeline est la plus complexe. C'est là que le processus commence à se décomposer et à changer en fonction de la plateforme. Ci-dessous, vous verrez le déroulement logique du script dans son ensemble et comment la partie liée à la génération de ressources est divisée en trois processus similaires mais différents:



Pour créer des ressources prêtes à l'emploi avec les couleurs correctes correspondant à la marque en cours de traitement, nous devrons effectuer quelques manipulations supplémentaires avec les fichiers JSON. Nous parcourons toutes les couches auxquelles le style général est appliqué et remplaçons les valeurs de couleur par les couleurs du jeton de conception de la marque.

Pour générer des fichiers pour Android, vous devez effectuer une action supplémentaire (à ce sujet un peu plus tard): nous changeons la propriété de fill-rule de chaque couche de even-odd à non-zero (ceci est contrôlé par la propriété windingRule de l'objet JSON, dans laquelle 1 signifie "impair / pair" , et 0 est "différent de zéro").

Après avoir effectué ces manipulations, nous replaçons les fichiers JSON dans un fichier Sketch standard pour traiter et exporter des ressources avec des propriétés mises à jour (les fichiers clonés et mis à jour sont des fichiers Sketch ordinaires, ils peuvent être ouverts, affichés, modifiés, enregistrés, etc. )

Après cela, nous utilisons SketchTool (enveloppé sous Node ) pour exporter automatiquement toutes les ressources dans des formats adaptés aux plates-formes. Pour chacun des fichiers associés à la marque (ou plutôt, leurs versions clonées et mises à jour), nous exécutons la commande suivante:

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

Comme vous pouvez le deviner, cette commande exporte les ressources vers le dossier de destination dans un format spécifique, en utilisant éventuellement la mise à l'échelle (nous conservons l'échelle d'origine pour l'instant). La clé ici est l'option -overwriting : tout comme nous faisons une fusion profonde des objets assetsMetadata (correspondant aux fichiers Sketch «logiques»), lors de l'exportation, nous fusionnons de nombreux fichiers dans un répertoire (lié à la marque / plateforme). Cela signifie que si la ressource - identifiée par le nom de la couche - existait déjà dans le fichier Sketch précédent, elle sera remplacée lors de la prochaine exportation. Encore une fois, ce n'est rien de plus qu'une opération de fusion normale.

Cependant, dans cet exemple, certaines ressources peuvent se révéler être des «fantômes». Cela se produit lorsque l'icône du fichier est soumise à un test A / B, mais est remplacée dans le fichier suivant. Ensuite, les fichiers de variantes sont exportés vers le dossier de destination, ont un lien correspondant à la ressource dans l'objet assetsMetadata (avec leur clé et leurs propriétés), mais ne sont associés à aucune ressource de base (en raison de la fusion en profondeur des objets assetsMetadata ). Ces fichiers seront supprimés ultérieurement, avant de terminer le processus.



Comme déjà mentionné, différentes plates-formes nécessitent différents formats de sortie. Les fichiers iOS s'adaptent aux PDF et nous pouvons les exporter directement à l'aide de la commande SketchTool. Les fichiers JSX sont requis pour Mobile Web et VectorDrawable pour Android. Pour cette raison, nous exportons des ressources au format SVG vers un dossier temporaire et après cela nous les traitons.

PDF pour iOS


Curieusement, PDF est le seul (?) Format pris en charge par Xcode et OS / iOS pour l'importation et le rendu des ressources vectorielles ( voici une brève explication du choix d' Apple).

Comme nous pouvons exporter directement au format PDF via SketchTool, aucune étape supplémentaire n'est requise: il suffit d'enregistrer les fichiers directement dans le dossier de destination, et c'est tout.

Fichiers Web React / JSX


Dans le cas du Web, nous utilisons la bibliothèque SVGR Node, qui vous permet de convertir SVG en composants React. Cependant, nous voulons faire quelque chose de brusquement: «coloriser dynamiquement» l'icône lors de l'exécution (les couleurs sont tirées des jetons). Pour ce faire, avant la conversion, nous modifions les valeurs de fill des vecteurs auxquels le style général a été précédemment appliqué aux valeurs des jetons correspondant à ce style.

Donc, si le fichier badge-feature-like.svg exporté depuis Sketch ressemble à ceci:

 <?xml version="1.0" encoding="UTF-8"?> <svg width="128px" height="128px" viewBox="0 0 128 128" version="1.1" xmlns="<a href="http://www.w3.org/2000/svg">http://www.w3.org/2000/svg</a>" xmlns:xlink="<a href="http://www.w3.org/1999/xlink">http://www.w3.org/1999/xlink</a>"> <!-- Generator: sketchtool 52.2 (67145) -<a href="http://www.bohemiancoding.com/sketch"> http://www.bohemiancoding.com/sketch</a> --> <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> 

alors l' icĂ´ne finale de ressource / badge-fonction-like.js ressemblera Ă  ceci:

 /* 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> ); }; 

Comme vous pouvez le voir, nous avons remplacé la couleur de fill statique par une couleur dynamique qui prend des valeurs des jetons (elles peuvent être mises à disposition pour le composant React <Icon/> via l'API Context, mais c'est une autre histoire).

Ce remplacement est possible grâce aux métadonnées Sketch pour les actifs de l'objet assetsMetadata : en parcourant récursivement les couches, vous pouvez créer un sélecteur DOM (pour l'exemple ci-dessus, #Icons #badge-feature-like #circle ) et l'utiliser pour rechercher un nœud dans l'arborescence SVG et remplacer sa valeur attribut fill (pour cela, nous avons besoin de la bibliothèque cheerio ).

Fichiers vectoriels pour Android


Android prend en charge les graphiques vectoriels en utilisant le format vectoriel personnalisé VectorDrawable . Habituellement, la conversion de SVG en VectorDrawable se fait directement dans Android Studio . Cependant, nous voulions automatiser entièrement le processus, donc nous cherchions un moyen de convertir en utilisant du code.

Après avoir étudié divers outils et bibliothèques, nous avons opté pour svg2vectordrawable . Il est non seulement activement pris en charge (en tout cas, plus actif que tout le monde), mais aussi plus fonctionnel que les autres.

Les réalités sont que VectorDrawable et SVG ne sont pas les mêmes dans leurs fonctionnalités: certaines fonctions SVG (par exemple, les dégradés radiaux et la mise en évidence complexe) ne sont pas prises en charge par VectorDrawable, tandis que d'autres ont commencé à être prises en charge assez récemment (à partir d'Android API 24). L'un des problèmes qui en résulte est que les anciennes versions (jusqu'à 24) ne prennent pas en charge la valeur paire-impaire de l'attribut fill-rule . Cependant, chez Badoo, nous avons besoin du support pour Android 5 et supérieur. C'est pourquoi, à l'une des étapes précédentes, nous avons amené le fill chaque vecteur des fichiers Sketch à une valeur non-zero .

En principe, les concepteurs peuvent effectuer cette action manuellement:



Mais c'est facile à oublier et à commettre une erreur. Par conséquent, nous avons décidé d'ajouter une étape supplémentaire au processus pour Android, au cours de laquelle tous les vecteurs dans JSON sont automatiquement convertis en non-zero . Cela est fait de sorte que lors de l'exportation d'icônes vers SVG, elles soient déjà au format requis, et chaque objet VectorDrawable créé est pris en charge par les appareils sur Android 5.

Le fichier badge-feature-like.xml terminé ressemble à ceci:

 <!-- This file is generated automatically - DO NOT EDIT --> <vector xmlns:android="<a href="http://schemas.android.com/apk/res/android">http://schemas.android.com/apk/res/android</a>" 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> 

Dans les fichiers VectorDrawable, nous insérons des noms de variables pour les couleurs de fill , qui sont associées aux jetons de conception via des styles courants dans les applications Android.



Il est Ă  noter qu'Android Studio a des exigences strictes pour l'organisation des ressources: pas de sous-dossiers et de majuscules dans les noms! Nous avons donc dĂ» trouver un nouveau format pour les noms d'icĂ´nes: dans le cas des ressources Ă  tester, ils ressemblent Ă  ceci: ic_icon-name__experiment-name__variant-name .

Dictionnaire JSON en tant que bibliothèque de ressources


Une fois les fichiers de ressources enregistrés au format final, il ne reste plus qu'à collecter toutes les méta-informations obtenues lors de l'assemblage et à les enregistrer dans un «dictionnaire» à utiliser lorsque les ressources sont importées et utilisées par la base de code de différentes plateformes.

Après avoir extrait une liste plate d'icônes de l'objet assetsMetadata nous le assetsMetadata vérifiant chacune d'elles:

  • S'agit-il d'une ressource rĂ©gulière (par exemple, tabbar-livestream ); si oui, alors laissez-le;
  • s'il s'agit d'une option pour un test A / B (par exemple, experiment / tabbar-livestream [variant] ), nous associons son nom, son chemin, les noms du test A / B et sa variante Ă  la propriĂ©tĂ© abtests
    la ressource de base (dans notre cas, il s'agit de tabbar-livestream ), après quoi nous supprimons l'enregistrement de la variante de la liste / objet (seul l'élément «base» compte);
  • s'il s'agit d'un «fantĂ´me», supprimez le fichier et supprimez l'entrĂ©e de la liste / objet.

Après avoir terminé ce processus, le dictionnaire contiendra une liste de toutes les icônes de base (et leurs tests A / B, le cas échéant), et seulement eux. Les informations sur chacun d'eux incluent le nom, la taille, le chemin d'accès et, si l'icône est soumise à des tests A / B, des informations sur ses différentes options.

Le dictionnaire est enregistré au format JSON dans le dossier de destination de la marque et de la plateforme . Voici, par exemple, le fichier assets.json généré pour l'application Blendr pour Mobile Web:

 { "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"      }    }  },  ... } } 

Il ne reste plus qu'à emballer tous les dossiers de ressources dans des archives ZIP pour un téléchargement plus facile.

Résumé


Le processus décrit dans l'article, du clonage et de la manipulation des fichiers Sketch à l'exportation et à la conversion des ressources dans des formats pris en charge par les plateformes et à l'enregistrement des méta-informations collectées dans la bibliothèque de ressources, est répété avec chaque marque annoncée dans le script de construction.

Voici une capture d'écran montrant l'apparence des dossiers src et dist une fois le processus terminé:



À ce stade, à l'aide d'une commande simple, vous pouvez télécharger toutes les ressources (JSON, ZIP et fichiers de ressources) vers le stockage distant et les rendre disponibles pour toutes les plates-formes pour le téléchargement et l'utilisation dans la base de code.

La manière exacte dont les plateformes reçoivent et traitent les ressources (à l'aide de scripts personnalisés créés spécifiquement à cet effet) ne dépasse pas le cadre de cet article. Et cette question sera probablement traitée dans l'un des articles suivants par un de mes collègues.

Conclusion (et leçons apprises)


J'ai toujours aimé Sketch. Pendant de nombreuses années, le programme a été l'outil par défaut pour les développeurs et les concepteurs. Par conséquent, j'étais très curieux d'apprendre des outils d'intégration comme html-sketchapp et d'autres outils similaires que nous pourrions utiliser dans le flux de travail et nos pipelines.

Comme beaucoup d'autres , j'ai toujours œuvré pour un tel processus (idéal):



Cependant, je dois admettre que j'ai commencé à douter que Sketch soit un outil approprié, surtout compte tenu du système de conception. Par conséquent, j'ai commencé à regarder d'autres services, tels que Figma avec ses API ouvertes et Framer X avec une intégration pratique avec React, parce que je ne ressentais pas le mouvement de Sketch vers l'intégration avec le code (quel qu'il soit).

Donc, ce projet m'a convaincu. Pas complètement, mais à bien des égards.

Bien que Sketch n'ouvre pas ses API, le dispositif même de la structure interne de ses fichiers sert comme une sorte d'API «non officielle». Les créateurs peuvent utiliser des noms chiffrés ou masquer des clés dans les objets JSON, mais à la place, ils adhèrent à une convention de dénomination claire, lisible et conceptuelle. Je ne pense pas que ce soit un accident.

Le fait que les fichiers Sketch puissent être gérés de cette manière m'a ouvert la voie à de nombreux développements et améliorations futurs: des plugins pour vérifier le nom, la stylisation et la structure des couches pour les icônes à l'intégration avec notre Wiki et la documentation de notre système de conception (mutuelle). En créant des applications Node sur Electron ou Carlo , nous pouvons faciliter la tâche des concepteurs pour effectuer de nombreuses tâches de routine.

( , ) , Sketch- Cosmos « » — - Cosmos. , ( ; , — ). , — , , .

, Sketch- , , MVP-, . , , . , , -, — , . , .

: , . , .

, , — . , , , (, A/B-), Node.js Sketch.

! .

Remerciements


(Mobile Web), , (Android) (iOS), .

, ! .

Source: https://habr.com/ru/post/fr442886/


All Articles