Sometimes I use Sketch to create graphics for my content; however, I have always found it challenging to keep track of my work. Saving files here and there, versioning them with what I thought were sensible name schemes, only to realise that following such schemes requires a lot of mental effort.
My dream was always to be able to store my Sketch files in a Git repo; for some reason, I always thought this would be impossible, that Sketch's files were binaries impossible to properly version.
In the following post, I'll explain why I was wrong and how is it that you can version your Sketch files as plain text documents.
So I start with a base document, nothing too complex as I don't want to overcomplicate things:
I have named this document tcsg.sketch; then, the next thing to understand is how Sketch actually saves these documents as a single file. The most important thing is that a .sketch file is nothing more than a .zip file with a bunch of .json files inside.
De-sketchify
We know that Git does not play nice with binary files but plays very nicely with plain text files – and JSON is just that. Why not decompress the .sketch file and keep track of the .json files alone; after all, when we want to open our file in Sketch again, we can compress those files again.
Decompress
With this in mind, we can use:
unzip -d tcsg tcsg.sketch
To unzip the files into the tcsg
repository. A quick glance into the newly unzipped repository gives us the following repo structure:
tcsg
├── document.json
├── meta.json
├── pages
│ └── 4FB4BFA1-4E01-4EE8-9962-F07A85622B2F.json
├── previews
│ └── preview.png
└── user.json
I will not discuss the details of the files, as they are well explained in Sketch's documentation.
We should note that for optimisation purposes, the JSON files are saved with no indentation, and all the contents are stored in a single line. As I want to embrace the full power of Git, I need to format these files to be able to view the diffs.
Indent files
There is a useful tool to work with JSON fines from the CLI, it is named jq, I will use it to format the files with indentation:
find ./tcsg -type f -name "*.json" \
-exec sh -c "jq . {} | sponge {}" \;
An explanation of the above command:
-
find ./tcsg
: Searches for objects in the./tcsg
folder -
-type f
: Specifies, withf
that we are looking for a regular file -
-name "*.json"
: Filters the files we will find to all those ending in.json
-
-exec [command]
: Executes a command for each file; within this command we can use{}
to refer to the file name. The command to execute should be followed by\;
-
sh -c "jq . {} | sponge {}"
: In this case, the command that will be executed for each file isjq . [filename] | sponge [filename]
.
Delete previews (optional)
There is a previews
folder where the last page edited by the user is preserved to be used as a thumbnail (and a preview) for the document. Again, this is an image, and for the time being, I will delete it since it is not needed for the file format.
rm -rf ./tcsg/previews/preview.png
And that is it! we now have a Sketch document as a series of plain text files.
Sketchify
Of course, I want this process to be reversible – I want to be able to open my documents in Sketch again.
Create a temporary folder
I rather not modify the original directory, so I will create a copy of the working directory:
cp -r ./tcsg ./tcsg_temp
Un-indent files
When I decompressed the files, I realised that the JSON files contained all the information in a single line; to respect that format, let's apply the jq -c . {} | sponge {}
command to all those files. It is pretty similar to the format command above, with the difference of the -c
flat of jq, which "compresses" the output.
find ./tcsg_temp -type f -name "*.json" \
-exec sh -c "jq -c . {} | sponge {}" \;
Remove previews (optional)
Again, let's delete any preview image, for consistency with the process above:
rm -rf ./tcsg_temp/previews/preview.png
Putting everything together
I placed all the above code into a single file called desketchify.sh
:
#!/usr/bin/env bash
unzip -o -d tcsg tcsg.sketch
find ./tcsg -type f -name "*.json" \
-exec sh -c "jq . {} | sponge {}" \;
rm -rf ./tcsg/previews/preview.png
Compress
Finally, in the compression step, we need to change directory to the temporary folder I have been working on. Then apply the compression step using the zip
utility:
cd ./tcsg_temp; zip -r -X ../tcsg.sketch *
The flag -r
specifies that zip
should recursively compress the files; the -X
flag specifies that the compression should not save any extra file attributes.
At the end of this command I should have a .sketch
file that can be opened in the app.
Cleanup
Lastly, let's clean up what I just did:
cd ..; rm -rf ./tcsg_temp
Putting everything together
I placed all the above code into a single file called sketchify.sh
:
#!/usr/bin/env bash
cp -r ./tcsg ./tcsg_temp
find ./tcsg_temp -type f -name "*.json" \
-exec sh -c "jq -c . {} | sponge {}" \;
rm -rf ./tcsg_temp/previews/preview.png
cd ./tcsg_temp; zip -r -X ../tcsg.sketch *
cd ..; rm -rf ./tcsg_temp
Exporting artboards
But why stop there? what if I want to export the contents of the file as images? This will make it easy to share the assets with people who do not have Sketch installed at all!
This is surprisingly easy using GitHub Actions; all I need to do is use a kind of hidden gem in the Sketch ecosystem: their sketchtool utility, read more about it here. It allows you to interact with Sketch documents without human interaction.
In particular, the command that I am interested in the most is the one that exports artboards: sketchtool export artboards [file]
.
The tool itself is free to use for my purposes, but we need to download Sketch, I wrote the following code to achieve that:
wget -O sketch.zip \
https://download.sketch.com/sketch-88.1-145978.zip
unzip -qq sketch.zip
Sketch.app/Contents/MacOS/sketchtool -v
Leaving the sketchtool accesible via the Sketch.app/Contents/MacOS/sketchtool
command. Obviously, be mindful of the version you are working with.
Full automation
It is finally time to put everything together using GitHub actions, I want to run all these steps only when the source files of the Sketch document change:
name: Sketchify
on:
workflow_dispatch:
push:
branches: [ "main" ]
paths:
- 'tcsg/**'
The jobs are organised in steps, where each step performs one and only one action:
jobs:
generate_assets:
name: Generate assets
runs-on: macos-latest
steps:
- name: Checkout code
uses: actions/checkout@v3
- name: Install dependencies
run: |
brew install jq
brew install moreutils
- name: Create Sketchfile
run: ./sketchify.sh
- name: Install Sketch
run: |
wget -O sketch.zip https://download.sketch.com/sketch-88.1-145978.zip
unzip -qq sketch.zip
Sketch.app/Contents/MacOS/sketchtool -v
- name: Export artboards
run: Sketch.app/Contents/MacOS/sketchtool export artboards tcsg.sketch --output=export --formats=jpg --scales=1,2
- name: Save exported images
uses: actions/upload-artifact@v3
with:
name: images
path: export/
- name: Save generated Sketch file
uses: actions/upload-artifact@v3
with:
name: sketch-file
path: tcsg.sketch
This will rebuild my Sketch file every time new changes are made to the repository and will export all the artboards in it. The best part? the artefacts will be available for download in the GitHub UI:
Conclusion
I consider this to be a pretty decent way to store Sketch files as assets in a Git repository; of course, depending on the changes you make, the diffs may still be monstrous; but at least they are more trackable than as a single zip file.
To use the code described in this post you will need to make some adjustments to it to refer to your own files.
So, tell me, do you use Sketch? I hope this post was useful for you as it was helpful for me, I discovered so many things about Sketch. If you have any doubts, let me know on Twitter at @feregri_no. As always, find the code for this post in GitHub. Happy Sketch-ing.
Top comments (0)