Stirling-PDF/app/core/build.gradle
Anthony Stirling e47ed13be8
Builds custom Jar (#5029)
# Description of Changes

Change jar files to contain frontend if provided with param, else
doesnt... add release artifact -server version which wont have frontend

---

## Checklist

### General

- [ ] I have read the [Contribution
Guidelines](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/CONTRIBUTING.md)
- [ ] I have read the [Stirling-PDF Developer
Guide](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/DeveloperGuide.md)
(if applicable)
- [ ] I have read the [How to add new languages to
Stirling-PDF](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/HowToAddNewLanguage.md)
(if applicable)
- [ ] I have performed a self-review of my own code
- [ ] My changes generate no new warnings

### Documentation

- [ ] I have updated relevant docs on [Stirling-PDF's doc
repo](https://github.com/Stirling-Tools/Stirling-Tools.github.io/blob/main/docs/)
(if functionality has heavily changed)
- [ ] I have read the section [Add New Translation
Tags](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/HowToAddNewLanguage.md#add-new-translation-tags)
(for new translation tags only)

### Translations (if applicable)

- [ ] I ran
[`scripts/counter_translation.py`](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/docs/counter_translation.md)

### UI Changes (if applicable)

- [ ] Screenshots or videos demonstrating the UI changes are attached
(e.g., as comments or direct attachments in the PR)

### Testing (if applicable)

- [ ] I have tested my changes locally. Refer to the [Testing
Guide](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/DeveloperGuide.md#6-testing)
for more details.
2025-11-26 17:21:42 +00:00

287 lines
9.9 KiB
Groovy

apply plugin: 'org.springframework.boot'
import org.apache.tools.ant.taskdefs.condition.Os
repositories {
maven { url = 'https://build.shibboleth.net/maven/releases' }
maven { url = 'https://maven.pkg.github.com/jcefmaven/jcefmaven' }
}
configurations {
developmentOnly
runtimeClasspath {
extendsFrom developmentOnly
}
}
spotless {
java {
target 'src/**/java/**/*.java'
targetExclude 'src/main/resources/static/**'
googleJavaFormat(googleJavaFormatVersion).aosp().reorderImports(false)
importOrder("java", "javax", "org", "com", "net", "io", "jakarta", "lombok", "me", "stirling")
toggleOffOn()
trimTrailingWhitespace()
leadingTabsToSpaces()
endWithNewline()
}
yaml {
target '**/*.yml', '**/*.yaml'
targetExclude 'src/main/resources/static/**'
trimTrailingWhitespace()
leadingTabsToSpaces()
endWithNewline()
}
format 'gradle', {
target '**/gradle/*.gradle', '**/*.gradle'
targetExclude 'src/main/resources/static/**'
trimTrailingWhitespace()
leadingTabsToSpaces()
endWithNewline()
}
}
dependencies {
if (System.getenv('STIRLING_PDF_DESKTOP_UI') != 'false'
|| (project.hasProperty('STIRLING_PDF_DESKTOP_UI')
&& project.getProperty('STIRLING_PDF_DESKTOP_UI') != 'false')) {
implementation 'org.openjfx:javafx-controls:21'
implementation 'org.openjfx:javafx-swing:21'
}
if (System.getenv('DISABLE_ADDITIONAL_FEATURES') != 'true'
|| (project.hasProperty('DISABLE_ADDITIONAL_FEATURES')
&& System.getProperty('DISABLE_ADDITIONAL_FEATURES') != 'true')) {
implementation project(':proprietary')
}
implementation project(':common')
implementation 'org.springframework.boot:spring-boot-starter-jetty'
implementation 'com.posthog.java:posthog:1.2.0'
implementation 'commons-io:commons-io:2.20.0'
implementation "org.bouncycastle:bcprov-jdk18on:$bouncycastleVersion"
implementation "org.bouncycastle:bcpkix-jdk18on:$bouncycastleVersion"
implementation 'io.micrometer:micrometer-core:1.15.4'
implementation 'com.google.zxing:core:3.5.3'
implementation "org.commonmark:commonmark:$commonmarkVersion" // https://mvnrepository.com/artifact/org.commonmark/commonmark
implementation "org.commonmark:commonmark-ext-gfm-tables:$commonmarkVersion"
// General PDF dependencies
implementation "org.apache.pdfbox:preflight:$pdfboxVersion"
implementation "org.apache.pdfbox:xmpbox:$pdfboxVersion"
// https://mvnrepository.com/artifact/technology.tabula/tabula
implementation ('technology.tabula:tabula:1.0.5') {
exclude group: 'org.slf4j', module: 'slf4j-simple'
exclude group: 'org.bouncycastle', module: 'bcprov-jdk15on'
exclude group: 'com.google.code.gson', module: 'gson'
}
implementation 'org.apache.pdfbox:jbig2-imageio:3.0.4'
implementation 'com.opencsv:opencsv:5.12.0' // https://mvnrepository.com/artifact/com.opencsv/opencsv
// Batik
implementation 'org.apache.xmlgraphics:batik-all:1.19'
// TwelveMonkeys
runtimeOnly "com.twelvemonkeys.imageio:imageio-batik:$imageioVersion"
runtimeOnly "com.twelvemonkeys.imageio:imageio-bmp:$imageioVersion"
runtimeOnly "com.twelvemonkeys.imageio:imageio-jpeg:$imageioVersion"
runtimeOnly "com.twelvemonkeys.imageio:imageio-tiff:$imageioVersion"
runtimeOnly "com.twelvemonkeys.imageio:imageio-webp:$imageioVersion"
// runtimeOnly "com.twelvemonkeys.imageio:imageio-hdr:$imageioVersion"
// runtimeOnly "com.twelvemonkeys.imageio:imageio-icns:$imageioVersion"
// runtimeOnly "com.twelvemonkeys.imageio:imageio-iff:$imageioVersion"
// runtimeOnly "com.twelvemonkeys.imageio:imageio-pcx:$imageioVersion@
// runtimeOnly "com.twelvemonkeys.imageio:imageio-pict:$imageioVersion"
// runtimeOnly "com.twelvemonkeys.imageio:imageio-pnm:$imageioVersion"
runtimeOnly "com.twelvemonkeys.imageio:imageio-psd:$imageioVersion"
// runtimeOnly "com.twelvemonkeys.imageio:imageio-sgi:$imageioVersion"
// runtimeOnly "com.twelvemonkeys.imageio:imageio-tga:$imageioVersion"
// runtimeOnly "com.twelvemonkeys.imageio:imageio-thumbsdb:$imageioVersion"
// runtimeOnly "com.twelvemonkeys.imageio:imageio-xwd:$imageioVersion"
developmentOnly 'org.springframework.boot:spring-boot-devtools'
}
sourceSets {
main {
resources {
srcDirs += ['../configs']
}
java {
if (System.getenv('STIRLING_PDF_DESKTOP_UI') == 'false') {
exclude 'stirling/software/SPDF/UI/impl/**'
}
}
}
test {
java {
if (System.getenv('STIRLING_PDF_DESKTOP_UI') == 'false') {
exclude 'stirling/software/SPDF/UI/impl/**'
}
}
}
}
// Disable regular jar
jar {
enabled = false
}
// Configure and enable bootJar for this project
bootJar {
enabled = true
duplicatesStrategy = DuplicatesStrategy.EXCLUDE
zip64 = true
// Don't include all dependencies directly like the old jar task did
// from {
// configurations.runtimeClasspath.collect { it.isDirectory() ? it : zipTree(it) }
// }
// Exclude signature files to prevent "Invalid signature file digest" errors
exclude 'META-INF/*.SF'
exclude 'META-INF/*.DSA'
exclude 'META-INF/*.RSA'
exclude 'META-INF/*.EC'
manifest {
attributes(
'Implementation-Title': 'Stirling-PDF',
'Implementation-Version': project.version
)
}
}
// Configure main class for Spring Boot
springBoot {
mainClass = 'stirling.software.SPDF.SPDFApplication'
}
// Frontend build tasks - only enabled with -PbuildWithFrontend=true
def buildWithFrontend = project.hasProperty('buildWithFrontend') && project.property('buildWithFrontend') == 'true'
def frontendDir = file('../../frontend')
def frontendDistDir = file('../../frontend/dist')
def resourcesStaticDir = file('src/main/resources/static')
def generatedFrontendPaths = [
'assets',
'index.html',
'locales',
'Login',
'classic-logo',
'modern-logo',
'og_images',
'samples',
'manifest-classic.json'
]
tasks.register('npmInstall', Exec) {
enabled = buildWithFrontend
group = 'frontend'
description = 'Install frontend dependencies'
workingDir frontendDir
commandLine = Os.isFamily(Os.FAMILY_WINDOWS) ? ['cmd', '/c', 'npm', 'ci', '--prefer-offline'] : ['npm', 'ci', '--prefer-offline']
inputs.file(new File(frontendDir, 'package.json'))
inputs.file(new File(frontendDir, 'package-lock.json'))
outputs.dir(new File(frontendDir, 'node_modules'))
// Show live output
standardOutput = System.out
errorOutput = System.err
// Skip if node_modules exists and is up-to-date
onlyIf {
def nodeModules = new File(frontendDir, 'node_modules')
if (!nodeModules.exists()) {
println "node_modules not found, will install..."
return true
}
def packageJson = new File(frontendDir, 'package.json')
def packageLock = new File(frontendDir, 'package-lock.json')
def isOutdated = nodeModules.lastModified() < packageJson.lastModified() ||
nodeModules.lastModified() < packageLock.lastModified()
if (isOutdated) {
println "package.json or package-lock.json changed, will reinstall..."
} else {
println "node_modules is up-to-date, skipping npm install"
}
return isOutdated
}
doFirst {
println "Installing npm dependencies in ${frontendDir}..."
}
}
tasks.register('npmBuild', Exec) {
enabled = buildWithFrontend
group = 'frontend'
description = 'Build frontend application'
workingDir frontendDir
commandLine = Os.isFamily(Os.FAMILY_WINDOWS) ? ['cmd', '/c', 'npm', 'run', 'build'] : ['npm', 'run', 'build']
dependsOn npmInstall
inputs.dir(new File(frontendDir, 'src'))
inputs.file(new File(frontendDir, 'package.json'))
outputs.dir(frontendDistDir)
// Show live output
standardOutput = System.out
errorOutput = System.err
// Override VITE_API_BASE_URL to use relative paths for production builds
// This ensures JARs work regardless of how they're deployed (direct, proxied, etc.)
environment 'VITE_API_BASE_URL', '/'
doFirst {
println "Building frontend application for production (VITE_API_BASE_URL=/)"
}
}
tasks.register('copyFrontendAssets', Copy) {
enabled = buildWithFrontend
group = 'frontend'
description = 'Copy frontend build to static resources'
dependsOn npmBuild
from(frontendDistDir) {
// Exclude files that conflict with backend static resources
exclude 'robots.txt' // Backend already has this
exclude 'favicon.ico' // Backend already has this
}
into resourcesStaticDir
duplicatesStrategy = DuplicatesStrategy.INCLUDE // Let frontend overwrite when needed
doFirst {
println "Copying frontend build from ${frontendDistDir} to ${resourcesStaticDir}..."
println "Backend static resources will be preserved"
}
doLast {
println "Frontend assets copied successfully!"
}
}
tasks.register('cleanFrontendAssets', Delete) {
group = 'frontend'
description = 'Remove previously generated frontend assets from static resources'
delete generatedFrontendPaths.collect { new File(resourcesStaticDir, it) }
}
// Ensure copyFrontendAssets runs after spotless tasks
tasks.named('copyFrontendAssets').configure {
mustRunAfter tasks.matching { it.name.startsWith('spotless') }
}
if (buildWithFrontend) {
println "Frontend build enabled - JAR will include React frontend"
processResources.dependsOn copyFrontendAssets
} else {
println "Frontend build disabled - JAR will be backend-only"
// When not building the UI, ensure any stale frontend assets are removed
processResources.dependsOn cleanFrontendAssets
}
bootJar.dependsOn ':common:jar'
bootJar.dependsOn ':proprietary:jar'