From 555cb560f08c53c03d0c95ef99eec08aae8c98ea Mon Sep 17 00:00:00 2001 From: Damien Merenne Date: Fri, 16 May 2025 15:34:46 +0000 Subject: [PATCH 1/2] Add Docker image with export infrastructure. This commits updates the Dockerfile to add a new structurizr-export on top of the original structurizr-lite image. The image is configured with puppeteer, headless google chrome, the puppeteer structurizr export repository and 2 scripts to do the actual exports. With this image, one can run ``` docker run --rm -v .:/workspace -it structurizr-export:latest export-diagrams workspace build svg ``` to export the diagrams to svg. There's also an export-documentation script. --- Dockerfile | 27 ++++++++++++++++++++++++++- puppeteer-export-diagrams.sh | 31 +++++++++++++++++++++++++++++++ puppeteer-export-documentation.sh | 25 +++++++++++++++++++++++++ 3 files changed, 82 insertions(+), 1 deletion(-) create mode 100644 puppeteer-export-diagrams.sh create mode 100644 puppeteer-export-documentation.sh diff --git a/Dockerfile b/Dockerfile index 2242dd8..c50ddf5 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM eclipse-temurin:21.0.6_7-jre-noble +FROM eclipse-temurin:21.0.6_7-jre-noble AS structurizr-lite ENV PORT=8080 RUN set -eux; \ @@ -12,3 +12,28 @@ EXPOSE ${PORT} HEALTHCHECK CMD curl --fail http://localhost:${PORT}/health || exit 1 CMD ["java", "-Dserver.port=${PORT}", "-jar", "/usr/local/structurizr-lite.war"] + +FROM structurizr-lite AS structurizr-export + +ENV STRUCTURIZR_EXPORT=/opt/structurizr-export +ENV STRUCTURIZR_WORKSPACE_PATH=/workspace + +RUN set -eux; \ + apt-get install -y --no-install-recommends git nodejs npm; \ + git clone https://github.com/structurizr/puppeteer.git $STRUCTURIZR_EXPORT; \ + sed -i $STRUCTURIZR_EXPORT/export-diagrams.js -e 's@headless: HEADLESS@headless: HEADLESS, args: [ "--no-sandbox" ]@'; \ + sed -i $STRUCTURIZR_EXPORT/export-documentation.js -e 's@headless: HEADLESS@headless: HEADLESS, args: [ "--no-sandbox" ]@'; \ + cd $STRUCTURIZR_EXPORT; \ + npm install puppeteer; \ + npx puppeteer browsers install --install-deps chrome-headless-shell@stable; \ + mkdir $STRUCTURIZR_WORKSPACE_PATH; \ + apt-get remove -y --purge git npm; \ + apt-get autoremove -y; \ + rm -rf /var/lib/apt/lists/* /var/cache/apt/* + +COPY --chmod=0775 puppeteer-export-diagrams.sh /usr/local/bin/export-diagrams +COPY --chmod=0775 puppeteer-export-documentation.sh /usr/local/bin/export-documentation + +WORKDIR /workspace + +CMD ["/bin/bash"] diff --git a/puppeteer-export-diagrams.sh b/puppeteer-export-diagrams.sh new file mode 100644 index 0000000..6eefd03 --- /dev/null +++ b/puppeteer-export-diagrams.sh @@ -0,0 +1,31 @@ +#!/bin/bash +# export [[format] ...] + +cleanup() { + kill %1 + wait +} + +export STRUCTURIZR_WORKSPACE_FILENAME=$1 +shift +OUTPUT_DIR="${STRUCTURIZR_WORKSPACE_PATH}/${1}" +shift + +java -Dserver.port=${PORT} -jar /usr/local/structurizr-lite.war / & +(until printf "" 2>>/dev/null >>/dev/tcp/localhost/$PORT; do sleep 1; done) > /dev/null 2>&1 + +trap cleanup EXIT +trap cleanup INT +trap cleanup TERM + +mkdir -p "$OUTPUT_DIR" +cd "$OUTPUT_DIR" + +for FORMAT in $@; do + echo exporting $STRUCTURIZR_WORKSPACE_FILENAME diagrams to $FORMAT in $OUTPUT_DIR + for FILE in $(node $STRUCTURIZR_EXPORT/export-diagrams.js http://localhost:$PORT $FORMAT | grep "^ - .*\\.$FORMAT" | sed "s/ - //"); do + OUTPUT_FILE="$OUTPUT_DIR/${STRUCTURIZR_WORKSPACE_FILENAME}_${FILE}" + mv "$OUTPUT_DIR/$FILE" "$OUTPUT_FILE" + echo exported "$OUTPUT_FILE" + done +done diff --git a/puppeteer-export-documentation.sh b/puppeteer-export-documentation.sh new file mode 100644 index 0000000..253e226 --- /dev/null +++ b/puppeteer-export-documentation.sh @@ -0,0 +1,25 @@ +#!/bin/bash +# export [[format] ...] + +cleanup() { + kill %1 + wait +} + +export STRUCTURIZR_WORKSPACE_FILENAME=$1 +shift +OUTPUT_DIR="${STRUCTURIZR_WORKSPACE_PATH}/${1}" +shift + +java -Dserver.port=${PORT} -jar /usr/local/structurizr-lite.war / & +(until printf "" 2>>/dev/null >>/dev/tcp/localhost/$PORT; do sleep 1; done) > /dev/null 2>&1 + +trap cleanup EXIT +trap cleanup INT +trap cleanup TERM + +mkdir -p "$OUTPUT_DIR" +cd "$OUTPUT_DIR" + +echo exporting $STRUCTURIZR_WORKSPACE_FILENAME documentation in $OUTPUT_DIR +node $STRUCTURIZR_EXPORT/export-documentation.js http://localhost:$PORT $FORMAT From 019f5c6412bf02e39d8be57fa93d01505bbfa355 Mon Sep 17 00:00:00 2001 From: Damien Merenne Date: Wed, 21 May 2025 15:43:39 +0000 Subject: [PATCH 2/2] Use svgo to cleanup exported svgs. --- Dockerfile | 8 ++++++++ puppeteer-export-diagrams.sh | 6 +++++- svgo/removeNoDimensionImages.js | 27 +++++++++++++++++++++++++++ svgo/svgo.config.js | 10 ++++++++++ 4 files changed, 50 insertions(+), 1 deletion(-) create mode 100644 svgo/removeNoDimensionImages.js create mode 100644 svgo/svgo.config.js diff --git a/Dockerfile b/Dockerfile index c50ddf5..477bee2 100644 --- a/Dockerfile +++ b/Dockerfile @@ -26,14 +26,22 @@ RUN set -eux; \ cd $STRUCTURIZR_EXPORT; \ npm install puppeteer; \ npx puppeteer browsers install --install-deps chrome-headless-shell@stable; \ + npm install -g svgo; \ mkdir $STRUCTURIZR_WORKSPACE_PATH; \ apt-get remove -y --purge git npm; \ apt-get autoremove -y; \ rm -rf /var/lib/apt/lists/* /var/cache/apt/* +COPY svgo /usr/local/lib/svgo COPY --chmod=0775 puppeteer-export-diagrams.sh /usr/local/bin/export-diagrams COPY --chmod=0775 puppeteer-export-documentation.sh /usr/local/bin/export-documentation WORKDIR /workspace CMD ["/bin/bash"] + +# Local Variables: +# dockerfile-indent-offset: 8 +# tab-width: 8 +# indent-tabs-mode: t +# End: diff --git a/puppeteer-export-diagrams.sh b/puppeteer-export-diagrams.sh index 6eefd03..94a936c 100644 --- a/puppeteer-export-diagrams.sh +++ b/puppeteer-export-diagrams.sh @@ -25,7 +25,11 @@ for FORMAT in $@; do echo exporting $STRUCTURIZR_WORKSPACE_FILENAME diagrams to $FORMAT in $OUTPUT_DIR for FILE in $(node $STRUCTURIZR_EXPORT/export-diagrams.js http://localhost:$PORT $FORMAT | grep "^ - .*\\.$FORMAT" | sed "s/ - //"); do OUTPUT_FILE="$OUTPUT_DIR/${STRUCTURIZR_WORKSPACE_FILENAME}_${FILE}" - mv "$OUTPUT_DIR/$FILE" "$OUTPUT_FILE" + if [ $FORMAT == svg ]; then + svgo --config=/usr/local/lib/svgo/svgo.config.js --quiet "$OUTPUT_DIR/$FILE" -o "$OUTPUT_FILE" + else + mv "$OUTPUT_DIR/$FILE" "$OUTPUT_FILE" + fi echo exported "$OUTPUT_FILE" done done diff --git a/svgo/removeNoDimensionImages.js b/svgo/removeNoDimensionImages.js new file mode 100644 index 0000000..3bc2159 --- /dev/null +++ b/svgo/removeNoDimensionImages.js @@ -0,0 +1,27 @@ +'use strict'; + +exports.name = 'removeNodDimensionImages'; +exports.type = 'visitor'; +exports.active = true; +exports.description = 'removes images without width or height attributes (disabled by default)'; + +/** + * Remove raster images references in . + * + * @see https://bugs.webkit.org/show_bug.cgi?id=63548 + * + * @author Kir Belevich + * + * @type {import('../lib/types').Plugin} + */ +exports.fn = () => { + return { + element: { + enter: (node, parentNode) => { + if (node.name === 'image' && !(node.attributes.width && node.attributes.height)) { + parentNode.children = parentNode.children.filter((child) => child !== node); + } + }, + }, + }; +}; diff --git a/svgo/svgo.config.js b/svgo/svgo.config.js new file mode 100644 index 0000000..273a235 --- /dev/null +++ b/svgo/svgo.config.js @@ -0,0 +1,10 @@ + +const removeNoDimensionImages = require('/usr/local/lib/svgo/removeNoDimensionImages.js'); +module.exports = { + multipass: true, + + plugins: [ + 'preset-default', + removeNoDimensionImages, + ], +};