Typst is a new markup-based typesetting system that is designed to be as powerful as LaTeX while being much easier to learn and use. A Typst document can be compiled from a single .typ file, but a complex project can also contain many files, including data, images, and fonts. The Typst compiler needs the correct file paths to find everything and compile such projects successfully. This Gradle plugin offers a way to maintain such projects:
- Compile multiple documents in parallel for faster builds
- Generate all output formats supported by Typst (PDF, PNG, and SVG)
- Incremental build: Edit files and rebuild only affected documents
- Typst can either be automatically downloaded from GitHub releases, or use a local installation
- Define multiple source sets in one project to produce variants of your content, e.g., versions for printing and web publishing
- Track changes in locally installed Typst packages
- Convert unsupported image formats to format supported by Typst (ImageMagick required)
- Merge generated PDF files into one file using PDFBox
- Works well with Gradle's Configuration Cache and Build cache
- Runs on JVM 17 and above
The plugin expects these tools being installed locally:
- Java 17 or above
- ImageMagick for image conversion (Optional)
After creating a new Gradle project with gradle init
, the plugin needs to be configured in build.gradle.kts:
plugins {
// Good practice to have some standard tasks like clean, assemble, build
id("base")
// Apply the Typst plugin
id("de.infolektuell.typst") version "0.4.2"
}
// The release tag for the Typst version to be used, defaults to latest stable release on GitHub
typst.version = "v0.12.0"
A source set is a directory in your project under src that may contain subfolders for Typst files, data, images, and fonts. The Typst files that should be treated as input documents to be compiled must explicitly be configured. There can be one or as many of them as needed. Having multiple source sets can be useful if multiple variants of similar content should be produced, especially for data-driven documents. Otherwise, a single source set is sufficient. So let's add two of them in build.gradle.kts:
// The source sets container
typst.sourceSets {
// Sources for documents intended for web publishing in src/web folder
val web by registering {
// The files to compile (without .typ extension)
documents = listOf("frontmatter", "main", "appendix", "backmatter")
// Values set in this map are passed to Typst as --input options
inputs.put("version", version.toString())
}
// Sources for documents intended for printing in src/printing folder
val printing by registering {
documents = listOf("frontmatter", "main", "poster", "appendix", "backmatter")
}
}
In a source set folder, these subfolders are watched for changes:
- data: Files in YAML, TOML or JSON format
- fonts: Additional font files for your documents
- images: Image files included in your documents
- typst: Typst files, can be documents or contain declarations for importing
Running gradlew build
now will compile all documents into build/typst/.
If multiple source sets have many files in common, they could go into their own source set without documents. The source sets using these files can depend on this new shared source set.
typst.sourceSets {
// Sources used by other source sets in src/shared
val shared by registering
val printing by registering {
// Shared sources are also watched when printing documents are compiled
addSourceSet(shared)
}
}
Currently, Typst can output a document as PDF or as a series of images in PNG or SVG format. The desired output options can be configured per source set, e.g., PDF for printing and PNG for web publishing.
typst.sourceSets {
val web by registering {
documents = listOf("frontmatter", "main", "appendix", "backmatter")
format {
// The PNG format is right
png {
enabled = true
// Customized resolution (144 by default)
ppi = 72
}
// Disable the PDF format which is active by default
pdf.enabled = false
}
}
val printing by registering {
documents = listOf("frontmatter", "main", "poster", "appendix", "backmatter")
format {
// Setting this creates a merged PDF file from the documents list
pdf.merged = "thesis-$version"
}
}
}
Image files in src/ are copied to build/generated/typst/images. If the format ist not supported by Typst, they are converted to png before copying. Typst runs after image processing, so the images can be referenced by their path in Typst files. Typst receives the project directory as root (not the root project), so absolute import paths start with /src/.
A document receives the fonts subfolders of their source set and added shared source sets as font paths. Since version 0.2.0 of this plugin, system fonts are ignored by default for higher reproducibility. If a Typst version below 0.12.0 is in use or if system fonts should be considered, this must be turned off per configuration:
import de.infolektuell.gradle.typst.tasks.TypstCompileTask
// Configure all typst tasks
tasks.withType(TypstCompileTask::class) {
// Override the convention (false by default)
useSystemFonts = true
}
For better build reproducibility, Typst accepts a fixed creation date in UNIX timestamp format. See SOURCE_DATE_EPOCH specification for a format description. If no timestamp is set, it is determined by Typst.
import de.infolektuell.gradle.typst.providers.GitCommitDateValueSource
// Use the included utility to get a timestamp from git commit
val timestamp = providers.of(GitCommitDateValueSource::class) {
parameters {
revision = "main"
}
}
// Configure the Typst extension with this timestamp (eagerly for configuration cache compatibility)
typst.creationTimestamp = timestamp.get()
Typst 0.12.0 added a CLI option to pass the path where local packages are stored. This plugin sets this explicitly to Typst's platform-dependent convention, so both are working with the same files. To use an older version of Typst, you have to opt-out of this behavior.
import de.infolektuell.gradle.typst.tasks.TypstCompileTask
// Configure all typst tasks
tasks.withType(TypstCompileTask::class) {
// Unset the package path
packagePath.unset()
// Optionally add the local packages folder from the typst extension to the source set to keep change tracking
sourceSets.register("main") {
typst.add(localPackages)
}
}