Here is a simplified implementation of my code, where I used “symbolInstance.duplicate();” to structure the SymbolInstance into a Group before using it.
main.js
const sketch = require('sketch/dom');
const fs = require('@skpm/fs');
function rndShortHexValue() {
return `${Math.random().toString(36).substring(2)}`;
}
function getDocumentArtboards(doc) {
let list = [];
if (!doc) return list;
let pages = doc.pages;
if (!pages || pages.length < 1) return list;
pages.forEach(page => {
let layers = page.layers;
if (!layers || layers.length < 1) return;
layers.forEach(layer => {
if (!layer || layer.type !== "Artboard") return;
list.push(layer);
});
});
return list;
}
function getSelectedDocument(context) {
let doc;
if (context) {
doc = context.actionContext?.document || context.document;
}
return doc ? sketch.fromNative(doc) : sketch.getSelectedDocument();
}
function isFolderExist(folderpath){
try {
let stat = fs.statSync(folderpath);
return stat.isDirectory();
} catch (error) {
return false;
}
}
function createSubFolder(folderpath){
try {
if(isFolderExist(folderpath))return true;
fs.mkdirSync(folderpath);
return true;
} catch (error) {
console.log(error)
return false;
}
}
const exportOptions = {
compact: false,
'include-namespaces': false,
'group-contents-only': true,
overwriting: true,
progressive: false,
'save-for-web': true,
'use-id-for-name': true,
trimmed: false, // 等价于 shouldTrim=false
compression: 1.0,
};
/**
* main
*/
export function exportMain(context) {
const document = getSelectedDocument();
if (!document) {
console.log("Please open the document first.");
return;
}
const pluginFolderPath = context.scriptURL.URLByDeletingLastPathComponent().path();
const paths = [`export_output`, rndShortHexValue()];
let outputFold = pluginFolderPath + "/";
paths.forEach(path => {
outputFold += path + "/";
if (!createSubFolder(outputFold)) {
console.log(`Failed to create temporary export directory ${outputFold}`);
return;
}
});
console.log(`layer will export in :${outputFold}`)
const allArtboards = getDocumentArtboards(document);
const exportLayers = [];
for (let index = 0; index < allArtboards.length; index++) {
const artboard = allArtboards[index];
exportLayers.push(...getAllExportLayers(artboard, artboard, outputFold));
}
console.log("exportLayers", exportLayers);
}
function getAllExportLayers(artboard, layer, outputFold) {
const list = [];
let markedForExport = false;
const { type, layers, name, id } = layer;
if (type !== "Artboard") {
let exportFormats = layer.exportFormats;
markedForExport = exportFormats && exportFormats.length > 0;
}
if (markedForExport) {
const success = sketch.export(layer, {
...exportOptions,
output: outputFold,
scales: [1, 2, 3],
formats: "png"
}) && sketch.export(layer, {
...exportOptions,
output: outputFold,
formats: "svg"
});
console.log(`export layer:[${layer.type}] ${layer.name},success=${success}`);
list.push({ id, name, type });
}
else if (type === "SymbolInstance") {
list.push(...exportSymbolInstance(artboard, layer, outputFold))
return list;
}
if (layers && layers.length > 0) {
for (let index = 0; index < layers.length; index++) {
list.push(...getAllExportLayers(artboard, layers[index], outputFold));
}
}
return list;
}
function exportSymbolInstance(artboard, symbolInstance, outputFold) {
let tempGroup;
try {
tempGroup = symbolInstance.duplicate();
tempGroup.parent = artboard;
let symbolFrame = symbolInstance.frame.toJSON();
tempGroup.frame = symbolFrame;
let tempGroup2 = tempGroup.detach({ recursively: false });
if (tempGroup2) {
tempGroup = tempGroup2;
}
return getAllExportLayers(artboard, tempGroup, outputFold);
} finally {
if (tempGroup) {
tempGroup.remove();
tempGroup = null;
}
}
}
export default function () {
//IS_DEV && console.log(`${timeFormat()}:onRun.default`)
};
manifest.json
{
"$schema": "https://raw.githubusercontent.com/sketch-hq/SketchAPI/develop/docs/sketch-plugin-manifest-schema.json",
"commands": [
{
"name": "export layers",
"identifier": "exportMain",
"script": "./main.js",
"handlers": {
"run":"exportMain"
}
}
],
"menu": {
"title": "slice_bug_report",
"items": [
"exportMain"
]
}
}