Skip to content

vaadin-charts-flow-svg-generator does not await promise #7171

Open
@jabdinghoff

Description

@jabdinghoff

Description

when using the svg generator it seems to fail with any other version of node, except the version packaged with vaadin in ~/.vaadin/node, since the promise is never awaited and therefore the node task ends before the chart is ever generated, resulting in an empty .svg file.

Stopping the process with a debugger, I see that this gets executed

$  & 'C:\Program Files\Volta\node.exe' -e "const exporter = require('C:/Users/redacted/AppData/Local/Temp/svg-export14489522732765497442/export-svg-bundle.js');
> exporter({
> chartConfigurationFile: 'config15621129393804127831.json',
> outFile: 'chart2603073194147823298.svg',
> exportOptions: {'width':1920,'height':972.0},
> });"

based on this template

private static final String SCRIPT_TEMPLATE = "const exporter = require('%s');\n"
+ "exporter({\n" + "chartConfigurationFile: '%s',\n"
+ "outFile: '%s',\n" + "exportOptions: %s,\n" + "})";

but it doesn't create an svg

$  ls C:/Users/redacted/AppData/Local/Temp/svg-export14489522732765497442/

    Directory: C:\Users\redacted\AppData\Local\Temp\svg-export14489522732765497442

Mode                 LastWriteTime         Length Name
----                 -------------         ------ ----
-a---          05.03.2025    10:29           8093 config15621129393804127831.json
-a---          05.03.2025    10:29        4291232 export-svg-bundle.js

but running the same exact thing with the vaadin node version does work:

$  C:\Users\redacted\.vaadin\node\node.exe -e "const exporter = require('C:/Users/redacted/AppData/Local/Temp/svg-export14489522732765497442/export-svg-bundle.js');
> exporter({
> chartConfigurationFile: 'config15621129393804127831.json',
> outFile: 'chart2603073194147823298.svg',
> exportOptions: {'width':1920,'height':972.0},
> });"
$  ls C:/Users/redacted/AppData/Local/Temp/svg-export14489522732765497442/

    Directory: C:\Users\redacted\AppData\Local\Temp\svg-export14489522732765497442

Mode                 LastWriteTime         Length Name
----                 -------------         ------ ----
-a---          05.03.2025    10:38          64277 chart2603073194147823298.svg
-a---          05.03.2025    10:29           8093 config15621129393804127831.json
-a---          05.03.2025    10:29        4291232 export-svg-bundle.js

both are the same exact version

& 'C:\Program Files\Volta\node.exe' --version
v20.9.0
⮞  C:\Users\redacted\.vaadin\node\node.exe --version
v20.9.0

But I also tried v22.14.0

if i instead await the promise it works with both node executables though

(async () => {
    const exporter = require('C:/Users/redacted/AppData/Local/Temp/svg-export14489522732765497442/export-svg-bundle.js');  
    await exporter({
      chartConfigurationFile: 'config15621129393804127831.json',
      outFile: 'chart2603073194147823298.svg',
      exportOptions: {'width':1920,'height':972.0},
    });
})();

Afaict node does not guarantee to not exit before a pending promise is resolved when it is not awaited.

Expected outcome

I would expect any modern lts+ node version to work, since the linked node install section does not make mention that it should be some specific node version.
https://vaadin.com/docs/latest/flow/configuration/development-mode/node-js

Minimal reproducible example

public class Application {

    public static void main(String[] args) {
        Application app = new Application();
        app.generateSVG();
    }

    public void generateSVG() {
        try {
            Configuration configuration = createSampleConfiguration();

            ExportOptions options = new ExportOptions();
            options.setWidth(800);
            options.setHeight(600);

            System.out.println("Starting SVG generation...");
            try (SVGGenerator generator = new SVGGenerator()) {
                String svg = generator.generate(configuration, options);

                if (svg == null || svg.isEmpty()) {
                    System.out.println("Generated SVG is empty");
                    return;
                }

                String fileName = "ChartExport.svg";
                File outputFile = new File(fileName);
                try (FileWriter writer = new FileWriter(outputFile)) {
                    writer.write(svg);
                }

                System.out.println("SVG file generated at: " + outputFile.getAbsolutePath());
            }
        } catch (Exception e) {
            System.err.println("Error generating SVG: " + e.getMessage());
            e.printStackTrace();
        }
    }

    private Configuration createSampleConfiguration() {
        Configuration configuration = new Configuration();
        configuration.setTitle("Monthly Sales");
        configuration.setSubTitle("Source: Company Sales Data");

        configuration.getChart().setType(ChartType.COLUMN);

        XAxis xAxis = new XAxis();
        xAxis.setCategories("Jan", "Feb", "Mar", "Apr", "May", "Jun",
                "Jul", "Aug", "Sep", "Oct", "Nov", "Dec");
        configuration.addxAxis(xAxis);

        YAxis yAxis = new YAxis();
        yAxis.setTitle("Sales ($)");
        yAxis.setMin(0);
        configuration.addyAxis(yAxis);

        Tooltip tooltip = new Tooltip();
        tooltip.setValueSuffix(" $");
        configuration.setTooltip(tooltip);

        PlotOptionsColumn plotOptions = new PlotOptionsColumn();
        plotOptions.setBorderWidth(0);
        plotOptions.setPointPadding(0.2);
        configuration.setPlotOptions(plotOptions);

        ListSeries series1 = new ListSeries("Products");
        series1.setData(49000, 71000, 106000, 129000, 144000, 176000,
                135000, 148000, 216000, 194000, 95000, 54000);

        ListSeries series2 = new ListSeries("Services");
        series2.setData(83000, 78000, 98000, 93000, 106000, 84000,
                105000, 104000, 91000, 83000, 106000, 92000);

        configuration.addSeries(series1);
        configuration.addSeries(series2);

        return configuration;
    }
}
plugins {
    id 'java'
    id 'application'
}

group = 'com.example'
version = '1.0-SNAPSHOT'
sourceCompatibility = '11'

repositories {
    mavenCentral()
    maven { url 'https://maven.vaadin.com/vaadin-addons' }
}

dependencies {
    implementation group: 'com.vaadin', name: 'vaadin-charts-flow-svg-generator', version: '24.6.6'
    implementation 'org.apache.logging.log4j:log4j-api:2.14.1'
    implementation 'org.apache.logging.log4j:log4j-core:2.14.1'
}

application {
    mainClassName = 'com.example.Application'
}

if i run this with C:\Users\redacted\.vaadin\node\node.exe in my path it outputs:

Starting SVG generation...
SVG file generated at: C:\Users\redacted\IdeaProjects\vaadin-svg-example\ChartExport.svg

With "C:\Program Files\Volta\node.exe in my path it outputs:

Starting SVG generation...
Generated SVG is empty

Steps to reproduce

  1. Setup your path so that node points to any other version beside ~/.vaadin/node/node
    (I have it set to C:\Program Files\Volta\node.exe)
  2. gradlew run

Environment

Vaadin version(s): 24.6.6
OS: Windows

Browsers

Edge

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions