Как запустить JavaScript утилиту для оптимизации CSS через GraalVM в Java/Spring приложении

Как интегрировать JavaScript инструменты для сжатия CSS в Java приложение через GraalVM?

Я использую GraalVM для выполнения npm модулей из Java кода. Мне нужно подключить что-то вроде PurgeCSS для уменьшения размера CSS файлов в Spring приложении. Идея в том, чтобы контроллер вызывал PurgeCSS, который бы кешировал CSS файл и потом отдавал кешированную версию.

Похоже, что GraalVM Polyglot поддерживает два типа JavaScript: Node версию (доступна только через командную строку) и ECMAScript версию (доступна только программно). И кажется, что они не могут взаимодействовать друг с другом.

Что я пробовал:
Использовал npm install purgecss через GraalVM, это сработало хорошо, но следующий код не работает:

@Service
public class CssProcessor {
    String script = "var PurgeCSS = require('purgecss')\n" +
            "const processor = new PurgeCSS({\n" +
            "  content: ['**/*.html'],\n" +
            "  css: ['**/*.css']\n" +
            "})\n" +
            "const result = processor.purge()";

    public void processCss() {
        try (Context ctx = Context.create()) {
            Value func = ctx.eval("js", this.script);
            assert func.canExecute();
            String output = func.execute().asString();
            System.out.println(output);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

Проблема в том, что require это node-специфичная функция, поэтому она не работает. К сожалению, вся библиотека PurgeCSS полна require вызовов.

Вопросы:

  • Нужно ли искать single-file .mjs CSS библиотеку (ESM версию)?
  • Есть ли способ указать node вариант JavaScript, чтобы включить require?
  • Можно ли заменить все require на load?

Буду благодарен за любую помощь с настройкой JavaScript функциональности GraalVM для этого случая.

PS: Запускаю Spring через Gradle. Раньше думал о подключении Spring к Gulp через Gradle Wrapper и выполнении CSS задач через Gulp. Хостинг на Heroku, где можно использовать несколько buildpack (Java и Node).

Недавно решал такую же задачу с js-модулями в спринге. Сделал отдельный микросервис на node.js для CSS оптимизации и подключил через REST API. Так удобнее масштабировать и обновлять js-зависимости. Если хочешь всё в одном приложении - попробуй nashorn engine. Он старый, но require можно эмулировать. Ещё вариант - gradle plugin для сборки оптимизированного css на этапе билда, а не в рантайме.

Попробуй GraalVM Node.js runtime - он поддерживает require из коробки. Добавь флаги --jvm --polyglot при запуске и используй Context.newBuilder("js").allowIO(true).build(). Или собери PurgeCSS в один файл через webpack/rollup с target: “node” и подключи как ESM модуль. У меня работало с другими npm пакетами.

А может запустить node команду напрямую через ProcessBuilder? Создаёшь временный js файл с кодом и выполняешь через node процесс. Не так красиво как GraalVM, но require точно работать будет. Какие требования по производительности?