Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
338 changes: 338 additions & 0 deletions _posts/2025-07-15-quickjs4j.adoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,338 @@
---
layout: post
title: 'Introducing Quarkus quickjs4j: Seamless JavaScript Integration in Your Quarkus Applications'
date: 2025-07-15
tags: javascript, integration, cdi, build-time
synopsis: A new Quarkiverse extension that brings JavaScript execution to your Java applications with compile-time code generation and full CDI integration.
author: ewittman
---
:imagesdir: /assets/images/posts/quickjs4j
ifdef::env-github,env-browser,env-vscode[:imagesdir: ../assets/images/posts/quickjs4j]

== Introduction

We're excited to announce the release of the Quarkus quickjs4j extension, a powerful new addition to the
Quarkus ecosystem that enables seamless execution of JavaScript code within your Java applications. Built
on top of the https://github.com/roastedroot/quickjs4j[quickjs4j library], this extension brings the
lightweight QuickJS JavaScript engine to both JVM and Native Quarkus, with full CDI integration and
compile-time optimizations.

Whether you need to execute dynamic business logic, implement configurable rules engines, or integrate with
JavaScript-based algorithms, the Quarkus quickjs4j extension provides a type-safe, performant solution that
leverages Quarkus's build-time processing capabilities.

== Why JavaScript in Java Applications?

Quarkus applications often need to execute dynamic logic that can be modified without recompiling the entire
application. JavaScript provides an excellent solution for this use case, offering:

- **Dynamic Configuration**: Update business rules and logic without application restarts
- **Scripting Capabilities**: Enable power users to customize application behavior
- **Algorithm Integration**: Leverage existing JavaScript libraries and algorithms
- **Rapid Prototyping**: Quickly test and iterate on complex logic

The Quarkus quickjs4j extension makes this integration seamless while maintaining the performance and developer
experience you expect from Quarkus.

== Key Features

=== Compile-time Code Generation
The extension automatically generates CDI beans and proxy classes for your JavaScript interfaces during build
time, ensuring optimal performance and early error detection.

=== Full CDI Integration
JavaScript interfaces are first-class citizens in your Quarkus application, injectable like any other CDI bean.

=== Flexible Script Loading
Load JavaScript files from multiple sources:
- Classpath resources (recommended for packaged scripts)
- Filesystem paths (for dynamic script loading)
- URLs (for remote script execution)
- Anywhere else (using the optional Factory pattern)

=== Context Support
Pass Java objects as context to JavaScript execution, enabling bidirectional communication between Java and
JavaScript code.

=== Sandboxed Execution
QuickJs4J provides a secure and efficient way to execute JavaScript within Java. By running code in a sandbox,
it ensures:

- Memory safety – JavaScript runs in isolation, protecting your application from crashes or memory leaks.
- No system access by default – JavaScript cannot access the filesystem, network, or other sensitive resources unless explicitly allowed.
- Portability – Being pure Java bytecode, it runs wherever the JVM does.
- Native-image friendly – Compatible with GraalVM's native-image for fast, lightweight deployments.

Whether you're embedding scripting capabilities or isolating untrusted code, QuickJs4J is designed for safe and
seamless integration.

== Getting Started

Adding the extension to your Quarkus application is straightforward. First, add the dependency to your `pom.xml`:

[source,xml]
----
<dependency>
<groupId>io.quarkiverse.quickjs4j</groupId>
<artifactId>quarkus-quickjs4j</artifactId>
<version>${quarkus-quickjs4j.version}</version>
</dependency>
----

You'll also need to enable the annotation processor for code generation:

[source,xml]
----
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<annotationProcessorPaths>
<path>
<groupId>io.quarkiverse.quickjs4j</groupId>
<artifactId>quarkus-quickjs4j</artifactId>
<version>${quarkus-quickjs4j.version}</version>
</path>
</annotationProcessorPaths>
</configuration>
</plugin>
</plugins>
</build>
----

== Simple Example: JavaScript Calculator

Let's create a simple calculator to demonstrate the extension's capabilities.

First, define a Java interface annotated with `@ScriptInterface` and `@ScriptImplementation`:

[source,java]
----
package com.example;

import io.roastedroot.quickjs4j.annotations.ScriptInterface;
import io.quarkiverse.quickjs4j.annotations.ScriptImplementation;

@ScriptInterface
@ScriptImplementation(location = "calculator.js")
public interface Calculator {
int add(int a, int b);
int multiply(int a, int b);
}
----

Next, create the JavaScript implementation in `src/main/resources/calculator.js`:

[source,javascript]
----
function add(a, b) {
return a + b;
}

function multiply(a, b) {
return a * b;
}

export { add, multiply };
----

Finally, inject and use the calculator in your Quarkus application:

[source,java]
----
package com.example;

import jakarta.enterprise.context.ApplicationScoped;
import jakarta.inject.Inject;

@ApplicationScoped
public class MathService {

@Inject
Calculator calculator;

public int performCalculation() {
int sum = calculator.add(5, 3); // Returns 8
int product = calculator.multiply(4, 7); // Returns 28
double quotient = calculator.divide(10.0, 2.0); // Returns 5.0

return sum + product + (int) quotient;
}
}
----

That's it! The extension handles all the complexity of JavaScript execution, type conversion, and CDI
integration behind the scenes.

== Advanced Features

=== Context Objects for Bidirectional Communication

A powerful feature of quickjs4j is the ability to provide Java context objects that JavaScript code
can invoke:

[source,java]
----
@ScriptInterface(context = CalculatorContext.class)
@ScriptImplementation(location = "calculator.js")
public interface Calculator {
int add(int a, int b);
int multiply(int a, int b);
}
----

[source,java]
----
@ApplicationScoped
public class CalculatorContext {
public void log(String message) {
System.out.println("Calc>> " + message);
}
}
----

Your JavaScript code can then call these Java methods:

[source,javascript]
----
function add(a, b) {
Calculator_Builtins.log(`Adding ${a} + ${b}`);
return a + b;
}

function multiply(a, b) {
Calculator_Builtins.log(`Multiplying ${a} * ${b}`);
return a * b;
}

export { add, multiply };
----

=== Factory Pattern for Dynamic Scripts

For scenarios where you need to load scripts dynamically at runtime, use the factory pattern:

[source,java]
----
@ApplicationScoped
public class DynamicMathService {

@Inject
CalculatorContext context;

@Inject
ScriptInterfaceFactory<Calculator, CalculatorContext> calculatorFactory;

public void executeCustomScript() {
// Load your javascript from some dynamic source
String scriptContent = loadDynamicScriptContent();

// Create calculator instance with dynamic script
Calculator calculator = calculatorFactory.create(scriptContent, context);

// Use the calculator
int result = calculator.add(10, 20);
System.out.println("Result: " + result);
}
}
----

This approach is perfect for applications that need to execute user-provided scripts or
load scripts from external sources. Note that the execution of the script is fully sandboxed.
Only the methods exposed by the Context can be invoked from within the script.

== Error Handling and Debugging

JavaScript errors are propagated as Java exceptions, making debugging straightforward:

[source,java]
----
try {
double result = calculator.divide(10, 0);
} catch (RuntimeException e) {
logger.error("JavaScript execution failed: {}", e.getMessage(), e);
// Handle the error appropriately
}
----

== Build-time Magic

Behind the scenes, the extension performs build-time code generation, creating:

1. **CDI Bean Classes**: `{InterfaceName}_CDI` - Injectable CDI beans
2. **Factory Classes**: `{InterfaceName}_Factory` - Injectable factory beans
3. **Proxy Classes**: `{InterfaceName}_Proxy` - Generated by quickjs4j
4. **Context Builtins**: `{ContextName}_Builtins` - JavaScript-accessible Java methods

This build-time approach ensures minimal runtime overhead while providing full IDE
support with code completion and type checking.

== Performance Considerations

The QuickJS engine is designed for lightweight, fast JavaScript execution. Combined with
Quarkus's build-time optimizations, the extension provides:

- **Fast Startup**: Minimal impact on application startup time
- **Low Memory Footprint**: Efficient memory usage for JavaScript execution
- **Native Image Support**: Full compatibility with GraalVM native images
- **Build-time Validation**: Early detection of interface mismatches and errors

== Use Cases

The Quarkus quickjs4j extension is perfect for:

- **Business Rules Engines**: Implement configurable business logic
- **Template Processing**: Generate dynamic content with JavaScript templates
- **Algorithm Integration**: Leverage existing JavaScript algorithms and libraries
- **User Scripting**: Allow power users to customize application behavior
- **Configuration Logic**: Implement complex configuration scenarios

== Current Status and Future Plans

The extension is currently in **experimental status**, meaning APIs may evolve based on
community feedback. We're actively working on:

- Enhanced error reporting and debugging capabilities
- Performance optimizations
- Configurable JavaScript engine options
- Improved IDE integration and tooling

In particular, we have a lot of work to do in optimizing performance. There are
clear tradeoffs to consider around flexibility and speed, as well as customization.
The current experimental implementation takes a very conservative approach to
ensure full sandboxing and thread safety. The result is a slower implementation,
but one that is guaranteed to be thread safe and fully sandboxed.

== Getting Involved

The Quarkus quickjs4j extension is part of the Quarkiverse ecosystem and welcomes community
contributions. Whether you're interested in:

- Reporting bugs or requesting features
- Contributing code improvements
- Sharing use cases and examples
- Improving documentation

Visit our https://github.com/quarkiverse/quarkus-quickjs4j[GitHub repository] to get involved.
We would really love for you to try out quickjs4j in Quarkus and give us feedback. The best
way to evolve the functionality is by hearing from users!

== Conclusion

The Quarkus quickjs4j extension opens up exciting possibilities for Java developers who need
to integrate JavaScript execution into their applications. With its compile-time code generation,
full CDI integration, and flexible script loading options, it provides a powerful yet easy-to-use
solution for dynamic code execution.

Try it out and let us know what you think! We're excited to see what the community builds with this
capability.

== Links and Resources
If you want to learn more about QuickJS itself, or the upstream quickjs4j Java project,
here are some helpful links:

- https://github.com/quarkiverse/quarkus-quickjs4j[Quarkus quickjs4j GitHub Repository]
- https://github.com/roastedroot/quickjs4j[quickjs4j Library]
- https://bellard.org/quickjs/[QuickJS JavaScript Engine]
Loading