Skip to content

Commit a244025

Browse files
EricWittmanncescoffier
authored andcommitted
Added a blog post to announce the quarkus-quickjs4j extension
1 parent 426ec51 commit a244025

File tree

1 file changed

+326
-0
lines changed

1 file changed

+326
-0
lines changed

_posts/2025-07-14-quickjs4j.adoc

Lines changed: 326 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,326 @@
1+
---
2+
layout: post
3+
title: 'Introducing Quarkus quickjs4j: Seamless JavaScript Integration in Your Quarkus Applications'
4+
date: 2025-07-14
5+
tags: javascript, integration, cdi, build-time
6+
synopsis: A new Quarkiverse extension that brings JavaScript execution to your Java applications with compile-time code generation and full CDI integration.
7+
author: ewittman
8+
---
9+
:imagesdir: /assets/images/posts/quickjs4j
10+
ifdef::env-github,env-browser,env-vscode[:imagesdir: ../assets/images/posts/quickjs4j]
11+
12+
== Introduction
13+
14+
We're excited to announce the release of the Quarkus quickjs4j extension, a powerful new addition to the
15+
Quarkus ecosystem that enables seamless execution of JavaScript code within your Java applications. Built
16+
on top of the https://github.com/roastedroot/quickjs4j[quickjs4j library], this extension brings the
17+
lightweight QuickJS JavaScript engine to Quarkus with full CDI integration and compile-time optimizations.
18+
19+
Whether you need to execute dynamic business logic, implement configurable rules engines, or integrate with
20+
JavaScript-based algorithms, the Quarkus quickjs4j extension provides a type-safe, performant solution that
21+
leverages Quarkus's build-time processing capabilities.
22+
23+
== Why JavaScript in Java Applications?
24+
25+
Quarkus applications often need to execute dynamic logic that can be modified without recompiling the entire
26+
application. JavaScript provides an excellent solution for this use case, offering:
27+
28+
- **Dynamic Configuration**: Update business rules and logic without application restarts
29+
- **Scripting Capabilities**: Enable power users to customize application behavior
30+
- **Algorithm Integration**: Leverage existing JavaScript libraries and algorithms
31+
- **Rapid Prototyping**: Quickly test and iterate on complex logic
32+
33+
The Quarkus quickjs4j extension makes this integration seamless while maintaining the performance and developer
34+
experience you expect from Quarkus.
35+
36+
== Key Features
37+
38+
=== Compile-time Code Generation
39+
The extension automatically generates CDI beans and proxy classes for your JavaScript interfaces during build
40+
time, ensuring optimal performance and early error detection.
41+
42+
=== Full CDI Integration
43+
JavaScript interfaces are first-class citizens in your Quarkus application, injectable like any other CDI bean.
44+
45+
=== Flexible Script Loading
46+
Load JavaScript files from multiple sources:
47+
- Classpath resources (recommended for packaged scripts)
48+
- Filesystem paths (for dynamic script loading)
49+
- URLs (for remote script execution)
50+
- Anywhere else (using the optional Factory pattern)
51+
52+
=== Context Support
53+
Pass Java objects as context to JavaScript execution, enabling bidirectional communication between Java and
54+
JavaScript code.
55+
56+
=== Sandboxed Execution
57+
QuickJs4J provides a secure and efficient way to execute JavaScript within Java. By running code in a sandbox,
58+
it ensures:
59+
60+
- Memory safety – JavaScript runs in isolation, protecting your application from crashes or memory leaks.
61+
- No system access by default – JavaScript cannot access the filesystem, network, or other sensitive resources unless explicitly allowed.
62+
- Portability – Being pure Java bytecode, it runs wherever the JVM does.
63+
- Native-image friendly – Compatible with GraalVM's native-image for fast, lightweight deployments.
64+
65+
Whether you're embedding scripting capabilities or isolating untrusted code, QuickJs4J is designed for safe and
66+
seamless integration.
67+
68+
== Getting Started
69+
70+
Adding the extension to your Quarkus application is straightforward. First, add the dependency to your `pom.xml`:
71+
72+
[source,xml]
73+
----
74+
<dependency>
75+
<groupId>io.quarkiverse.quickjs4j</groupId>
76+
<artifactId>quarkus-quickjs4j</artifactId>
77+
<version>${quarkus-quickjs4j.version}</version>
78+
</dependency>
79+
----
80+
81+
You'll also need to enable the annotation processor for code generation:
82+
83+
[source,xml]
84+
----
85+
<build>
86+
<plugins>
87+
<plugin>
88+
<groupId>org.apache.maven.plugins</groupId>
89+
<artifactId>maven-compiler-plugin</artifactId>
90+
<configuration>
91+
<annotationProcessorPaths>
92+
<path>
93+
<groupId>io.quarkiverse.quickjs4j</groupId>
94+
<artifactId>quarkus-quickjs4j</artifactId>
95+
<version>${quarkus-quickjs4j.version}</version>
96+
</path>
97+
</annotationProcessorPaths>
98+
</configuration>
99+
</plugin>
100+
</plugins>
101+
</build>
102+
----
103+
104+
== Simple Example: JavaScript Calculator
105+
106+
Let's create a simple calculator to demonstrate the extension's capabilities.
107+
108+
First, define a Java interface annotated with `@ScriptInterface` and `@ScriptImplementation`:
109+
110+
[source,java]
111+
----
112+
package com.example;
113+
114+
import io.roastedroot.quickjs4j.annotations.ScriptInterface;
115+
import io.quarkiverse.quickjs4j.annotations.ScriptImplementation;
116+
117+
@ScriptInterface
118+
@ScriptImplementation(location = "calculator.js")
119+
public interface Calculator {
120+
int add(int a, int b);
121+
int multiply(int a, int b);
122+
}
123+
----
124+
125+
Next, create the JavaScript implementation in `src/main/resources/calculator.js`:
126+
127+
[source,javascript]
128+
----
129+
function add(a, b) {
130+
return a + b;
131+
}
132+
133+
function multiply(a, b) {
134+
return a * b;
135+
}
136+
137+
export { add, multiply };
138+
----
139+
140+
Finally, inject and use the calculator in your Quarkus application:
141+
142+
[source,java]
143+
----
144+
package com.example;
145+
146+
import jakarta.enterprise.context.ApplicationScoped;
147+
import jakarta.inject.Inject;
148+
149+
@ApplicationScoped
150+
public class MathService {
151+
152+
@Inject
153+
Calculator calculator;
154+
155+
public int performCalculation() {
156+
int sum = calculator.add(5, 3); // Returns 8
157+
int product = calculator.multiply(4, 7); // Returns 28
158+
double quotient = calculator.divide(10.0, 2.0); // Returns 5.0
159+
160+
return sum + product + (int) quotient;
161+
}
162+
}
163+
----
164+
165+
That's it! The extension handles all the complexity of JavaScript execution, type conversion, and CDI
166+
integration behind the scenes.
167+
168+
== Advanced Features
169+
170+
=== Context Objects for Bidirectional Communication
171+
172+
A powerful feature of quickjs4j is the ability to provide Java context objects that JavaScript code
173+
can invoke:
174+
175+
[source,java]
176+
----
177+
@ScriptInterface(context = CalculatorContext.class)
178+
@ScriptImplementation(location = "calculator.js")
179+
public interface Calculator {
180+
int add(int a, int b);
181+
int multiply(int a, int b);
182+
}
183+
184+
@ApplicationScoped
185+
public class CalculatorContext {
186+
public void log(String message) {
187+
System.out.println("Calc>> " + message);
188+
}
189+
}
190+
----
191+
192+
Your JavaScript code can then call these Java methods:
193+
194+
[source,javascript]
195+
----
196+
function add(a, b) {
197+
Calculator_Builtins.log(`Adding ${a} + ${b}`);
198+
return a + b;
199+
}
200+
201+
function multiply(a, b) {
202+
Calculator_Builtins.log(`Multiplying ${a} * ${b}`);
203+
return a * b;
204+
}
205+
206+
export { add, multiply };
207+
----
208+
209+
=== Factory Pattern for Dynamic Scripts
210+
211+
For scenarios where you need to load scripts dynamically at runtime, use the factory pattern:
212+
213+
[source,java]
214+
----
215+
@ApplicationScoped
216+
public class DynamicMathService {
217+
218+
@Inject
219+
CalculatorContext context;
220+
221+
@Inject
222+
ScriptInterfaceFactory<Calculator, CalculatorContext> calculatorFactory;
223+
224+
public void executeCustomScript() {
225+
// Load your javascript from some dynamic source
226+
String scriptContent = loadDynamicScriptContent();
227+
228+
// Create calculator instance with dynamic script
229+
Calculator calculator = calculatorFactory.create(scriptContent, context);
230+
231+
// Use the calculator
232+
int result = calculator.add(10, 20);
233+
System.out.println("Result: " + result);
234+
}
235+
}
236+
----
237+
238+
This approach is perfect for applications that need to execute user-provided scripts or
239+
load scripts from external sources. Note that the execution of the script is fully sandboxed.
240+
Only the methods exposed by the Context can be invoked from within the script.
241+
242+
== Error Handling and Debugging
243+
244+
JavaScript errors are propagated as Java exceptions, making debugging straightforward:
245+
246+
[source,java]
247+
----
248+
try {
249+
double result = calculator.divide(10, 0);
250+
} catch (RuntimeException e) {
251+
logger.error("JavaScript execution failed: {}", e.getMessage(), e);
252+
// Handle the error appropriately
253+
}
254+
----
255+
256+
== Build-time Magic
257+
258+
Behind the scenes, the extension performs build-time code generation, creating:
259+
260+
1. **CDI Bean Classes**: `{InterfaceName}_CDI` - Injectable CDI beans
261+
2. **Factory Classes**: `{InterfaceName}_Factory` - Injectable factory beans
262+
3. **Proxy Classes**: `{InterfaceName}_Proxy` - Generated by quickjs4j
263+
4. **Context Builtins**: `{ContextName}_Builtins` - JavaScript-accessible Java methods
264+
265+
This build-time approach ensures minimal runtime overhead while providing full IDE
266+
support with code completion and type checking.
267+
268+
== Performance Considerations
269+
270+
The QuickJS engine is designed for lightweight, fast JavaScript execution. Combined with
271+
Quarkus's build-time optimizations, the extension provides:
272+
273+
- **Fast Startup**: Minimal impact on application startup time
274+
- **Low Memory Footprint**: Efficient memory usage for JavaScript execution
275+
- **Native Image Support**: Full compatibility with GraalVM native images
276+
- **Build-time Validation**: Early detection of interface mismatches and errors
277+
278+
== Use Cases
279+
280+
The Quarkus quickjs4j extension is perfect for:
281+
282+
- **Business Rules Engines**: Implement configurable business logic
283+
- **Template Processing**: Generate dynamic content with JavaScript templates
284+
- **Algorithm Integration**: Leverage existing JavaScript algorithms and libraries
285+
- **User Scripting**: Allow power users to customize application behavior
286+
- **Configuration Logic**: Implement complex configuration scenarios
287+
288+
== Current Status and Future Plans
289+
290+
The extension is currently in **experimental status**, meaning APIs may evolve based on
291+
community feedback. We're actively working on:
292+
293+
- Enhanced error reporting and debugging capabilities
294+
- Performance optimizations
295+
- Additional JavaScript engine options
296+
- Improved IDE integration and tooling
297+
298+
== Getting Involved
299+
300+
The Quarkus quickjs4j extension is part of the Quarkiverse ecosystem and welcomes community
301+
contributions. Whether you're interested in:
302+
303+
- Reporting bugs or requesting features
304+
- Contributing code improvements
305+
- Sharing use cases and examples
306+
- Improving documentation
307+
308+
Visit our https://github.com/quarkiverse/quarkus-quickjs4j[GitHub repository] to get involved!
309+
310+
== Conclusion
311+
312+
The Quarkus quickjs4j extension opens up exciting possibilities for Java developers who need
313+
to integrate JavaScript execution into their applications. With its compile-time code generation,
314+
full CDI integration, and flexible script loading options, it provides a powerful yet easy-to-use
315+
solution for dynamic code execution.
316+
317+
Try it out and let us know what you think! We're excited to see what the community builds with this
318+
capability.
319+
320+
== Links and Resources
321+
322+
- https://github.com/quarkiverse/quarkus-quickjs4j[Quarkus quickjs4j GitHub Repository]
323+
- https://github.com/roastedroot/quickjs4j[quickjs4j Library]
324+
- https://bellard.org/quickjs/[QuickJS JavaScript Engine]
325+
- https://quarkus.io/extensions/[Quarkus Extensions]
326+
- https://github.com/quarkiverse[Quarkiverse Hub]

0 commit comments

Comments
 (0)