Tasks

The plugin registers multiple tasks, that may have dependencies with each other, and also with:

  • Gradle lifecycle tasks defined in the Gradle Base plugin: clean, assemble, check.
  • Tasks defined in the Gradle Publishing plugin: publish.

Dependency tree

clean check assemble publish installNode resolvePackageManager installPackageManager installFrontend cleanFrontend checkFrontend assembleFrontend publishFrontend RunNode RunCorepack RunNpm RunPnpm RunYarn Gradle Base plugin Gradle Publishing plugin Frontend Gradle plugin Additional task types

Reference

Built-in tasks

# Task installNode - Install Node.js

The task downloads a Node.js distribution, verifies its integrity, and installs it in the directory pointed by the nodeInstallDirectory property (if this property is null, the distribution is installed in directory ${projectDir}/node). The URL used to download the distribution is resolved using the nodeDistributionUrlRoot property and the nodeDistributionUrlPathPattern property. Checking the distribution integrity consists of downloading a file providing the distribution shasum. This file is expected to be in the same remote web directory than the distribution archive. For example, if the distribution is located at https://nodejs.org/dist/vX.Y.Z/node-vX.Y.Z-win-x64.zip, the plugin attempts to download the shasum file located at https://nodejs.org/dist/vX.Y.Z/SHASUMS256.txt. By default, the plugin relies on the VM network properties to know if a proxy server shall be used when downloading the distribution and the shasum. A custom proxy server may also be used by defining httpsProxyHost property (respectively httpProxyHost property) if the nodeDistributionUrlRoot property uses the https protocol (resp. uses the http protocol). In case of connectivity/HTTP error, download of the distribution file and the shasum file may be retried using property maxDownloadAttempts.

If a Node.js distribution is already installed in the system - either as a global installation or as an installation performed by another Gradle (sub-)project - and shall be used instead of a downloaded distribution, take a look at the nodeDistributionProvided property instead: when true, this task is ignored if invoked during a Gradle build, and its outcome will always be SKIPPED.

The task takes advantage of Gradle incremental build, and is not executed again unless one of its inputs/outputs changed. Consequently, if the task takes part of a Gradle build, its outcome will be UP-TO-DATE.

This task should not be executed directly. Gradle executes it if the build requires it.

# Task resolvePackageManager - Resolve package manager C

The task identifies the name and the version of the package manager applicable to the project by parsing the packageManager property located in the package.json file (pointed by the packageJsonDirectory property). For example, if the package.json file contains "packageManager": "npm@9.6.7", the task resolves npm as the name of the package manager, and 9.6.7 as its version.

The task takes advantage of Gradle incremental build, and is not executed again unless one of its inputs/outputs changed. Consequently, if the task takes part of a Gradle build, its outcome will be UP-TO-DATE.

This task should not be executed directly. Gradle executes it if the build requires it.

# Task installPackageManager - Install package manager

The task installs the package manager resolved with task resolvePackageManager, by executing command corepack enable <package-manager>.

The task takes advantage of Gradle incremental build, and is not executed again unless one of its inputs/outputs changed. Consequently, if the task takes part of a Gradle build, its outcome will be UP-TO-DATE.

This task should not be executed directly. Gradle executes it if the build requires it.

# Task installFrontend - Install frontend dependencies

Depending on the package manager, this task executes either command npm install, or command pnpm install, or command yarn install, by default. Consequently, the command shall install project dependencies according to the algorithm followed by each package manager (see hereafter). Optionally, this command may be customized with the installScript property (e.g. to run a npm ci command instead). On a developer workstation, executing this task is a good starting point to setup a workspace for development as it will install the Node.js distribution (if not provided) as well as dependencies.

About incremental build and up-to-date checks

If you execute this task several times in a row, you may notice the npm/pnpm/yarn command is always executed: Gradle does not reuse task outputs based on a previous execution with the SUCCESS outcome. This is the expected behaviour by default because the task does not declare any relevant input(s) and output(s) Gradle could track to know the task is already UP-TO-DATE (e.g. unlike the installNode task). Resolving these inputs/outputs is a bit complex, since it depends on the package manager, the value of the installScript property, and the files present in the project. That's why incremental build for this task is not available out-of-the-box by now. However, some examples provide guidelines to customize this task and limit executions under certain circumstances. Notes hereafter provide also some unofficial ideas:

  • npm: inputs may be one or more of files package.json, npm-shrinkwrap.json, package-lock.json, yarn.lock, while outputs may be the node_modules directory and the package-lock.json file (see npm install). If the installScript property is set with ci, files npm-shrinkwrap.json and package-lock.json may be the only possible input file, if one or the other exists, and the node_modules directory the only output.
  • pnpm: inputs may be one or more of files package.json, pnpm-lock.yaml, while outputs may be the node_modules directory and the pnpm-lock.yaml file.
  • Yarn: inputs may be one or more of files package.json, yarn.lock, while outputs may be the node_modules directory, or the .pnp.cjs file and the .yarn/cache directory (Zero-installs), and the yarn.lock file.

If you are about to tweak this task to declare additional inputs and outputs, take a look at these recommendations.

# Task cleanFrontend - Clean frontend artifacts

This task does nothing by default, considering frontend artifacts (minimified Javascript, CSS, HTML files...) are generated in the ${project.buildDir} directory. If it is not the case, this task may be useful to clean the relevant directory. A clean script shall be defined in the package.json file, and the cleanScript property shall be set with the corresponding npm/pnpm/yarn command. This task depends on the installFrontend task, and is skipped if the cleanScript property is null. Apart from direct execution, the task is also executed when the Gradle lifecycle clean task is executed.

# Task assembleFrontend - Assemble frontend artifacts

This task allows to execute a build script as part of a Gradle build. The build script shall be defined in the package.json file, and the assembleScript property shall be set with the corresponding npm/pnpm/yarn command. This task depends on the installFrontend task, and is skipped if the assembleScript property is null. Apart from direct execution, the task is also executed when the Gradle lifecycle assemble task is executed.
About incremental build and up-to-date checks

If you execute this task several times in a row, you may notice the npm/pnpm/yarn command is always executed: Gradle does not skip the task based on a previous execution with the SUCCESS outcome. This is the expected behaviour because the task does not declare any input/output Gradle could track, to know the task is already UP-TO-DATE (e.g. unlike task installNode). The task provides the ability to plug the developer's own Javascript build process to Gradle, and nothing more. Every Javascript build process is unique: it depends on the project, the languages involved (e.g. TypeScript, JSX, ECMA script, SASS, SCSS...), the directory layout, the build utilities (Webpack...), etc., chosen by the team. Moreover, some build utilities are already able to build artifacts incrementally. The plugin does not duplicate this logic. If you are about to tweak this task, take a look at these recommendations.

# Task checkFrontend - Check frontend application

This task may be used to integrate a check script into a Gradle build. The check script shall be defined in the package.json file, and the checkScript property shall be set with the corresponding npm/pnpm/yarn command. A typical check script may lint source files, execute tests, and/or perform additional analysis actions. This task depends on the installFrontend task, and is skipped if the checkScript property is null. Apart from direct execution, the task is also executed when the Gradle lifecycle check task is executed.

# Task publishFrontend - Publish frontend artifacts

This task may be used to integrate a publish script into a Gradle build. The publish script shall be defined in the package.json file, and the publishScript property shall be set with the corresponding npm/pnpm/yarn command. This task depends on the assembleFrontend task, and is skipped either if the assembleScript property is null, or if the publishScript property is null. Apart from direct execution, the task is also executed when the Gradle publish task is executed.

Additional types

# Type RunNode - Run a custom command with node

The plugin provides task type org.siouan.frontendgradleplugin.infrastructure.gradle.RunNode that allows creating a custom task to run a JS script. The script property must be set with the corresponding command. Then, choose whether Node.js only is required, or if additional dependencies located in the package.json file should be installed: make the task either depends on installNode task or on installFrontend task. The code hereafter shows the configuration required to run a JS script:

import org.siouan.frontendgradleplugin.infrastructure.gradle.RunNode
tasks.register('myScript', RunNode) {
    // dependsOn tasks.named('installNode')
    // dependsOn tasks.named('installFrontend')
    script = 'my-script.js'
}
import org.siouan.frontendgradleplugin.infrastructure.gradle.RunNode
tasks.register<RunNode>("myScript") {
    // dependsOn(tasks.named("installNode"))
    // dependsOn(tasks.named("installFrontend"))
    script.set("my-script.js")
}

# Type RunCorepack - Run a custom command with corepack

The plugin provides task type org.siouan.frontendgradleplugin.infrastructure.gradle.RunCorepack that allows creating a custom task to run a corepack command. The script property must be set with the corresponding command. The code hereafter shows the configuration required to output the version of corepack:

import org.siouan.frontendgradleplugin.infrastructure.gradle.RunCorepack
tasks.register('corepackVersion', RunCorepack) {
    script = '--version'
}
import org.siouan.frontendgradleplugin.infrastructure.gradle.RunCorepack
tasks.register<RunCorepack>("corepackVersion") {
    script.set("--version")
}

# Type RunNpm - Run a custom command with npm

The plugin provides task type org.siouan.frontendgradleplugin.infrastructure.gradle.RunNpm that allows creating a custom task to run a npm command. The script property must be set with the corresponding command. Then, choose whether additional dependencies located in the package.json file should be installed: make the task either depends on installPackageManager task or on installFrontend task. The code hereafter shows the configuration required to output the version of npm:

import org.siouan.frontendgradleplugin.infrastructure.gradle.RunNpm
tasks.register('npmVersion', RunNpm) {
    // dependsOn tasks.named('installPackageManager')
    // dependsOn tasks.named('installFrontend')
    script = '--version'
}
import org.siouan.frontendgradleplugin.infrastructure.gradle.RunNpm
tasks.register<RunNpm>("npmVersion") {
    // dependsOn(tasks.named("installPackageManager"))
    // dependsOn(tasks.named("installFrontend"))
    script.set("--version")
}

# Type RunPnpm - Run a custom command with pnpm

The plugin provides task type org.siouan.frontendgradleplugin.infrastructure.gradle.RunPnpm that allows creating a custom task to run a pnpm command. The script property must be set with the corresponding command. Then, choose whether additional dependencies located in the package.json file should be installed: make the task either depends on installPackageManager task or on installFrontend task. The code hereafter shows the configuration required to output the version of pnpm:

import org.siouan.frontendgradleplugin.infrastructure.gradle.RunPnpm
tasks.register('pnpmVersion', RunPnpm) {
    // dependsOn tasks.named('installPackageManager')
    // dependsOn tasks.named('installFrontend')
    script = '--version'
}
import org.siouan.frontendgradleplugin.infrastructure.gradle.RunPnpm
tasks.register<RunPnpm>("pnpmVersion") {
    // dependsOn(tasks.named("installPackageManager"))
    // dependsOn(tasks.named("installFrontend"))
    script.set("--version")
}

# Type RunYarn - Run a custom command with yarn

The plugin provides task type org.siouan.frontendgradleplugin.infrastructure.gradle.RunYarn that allows creating a custom task to run a yarn command. The script property must be set with the corresponding command. Then, choose whether additional dependencies located in the package.json file should be installed: make the task either depends on installPackageManager task or on installFrontend task. The code hereafter shows the configuration required to output the version of yarn:

import org.siouan.frontendgradleplugin.infrastructure.gradle.RunYarn
tasks.register('yarnVersion', RunYarn) {
    // dependsOn tasks.named('installPackageManager')
    // dependsOn tasks.named('installFrontend')
    script = '--version'
}
import org.siouan.frontendgradleplugin.infrastructure.gradle.RunYarn
tasks.register<RunYarn>("yarnVersion") {
    // dependsOn(tasks.named("installPackageManager"))
    // dependsOn(tasks.named("installFrontend"))
    script.set("--version")
}

Tweaking the built-in tasks

If you need to customize the plugin's built-in tasks (e.g. declare additional I/O or dependencies), it is important to conform to the Configuration avoidance API: use references of task providers instead of references of tasks, and continue taking advantage of the lazy configuration strategy the plugin already implements. The examples below introduce the implementation expected with simple cases:

// Configuring a predefined task.
// LEGACY SYNTAX: task 'installFrontend' is immediately created and configured, as well as task
// 'otherTask', even if both tasks are not executed.
installFrontend {
    dependsOn 'otherTask'
    inputs.files('package.json', 'package-lock.json')
}
// MODERN SYNTAX: task 'installFrontend' is created and configured only when Gradle is about to execute it.
// Consequently, task 'otherTask' is also created and configured later. Let's also reinforce this behaviour
// by using its provider to retrieve the task.
tasks.named('installFrontend') {
    dependsOn tasks.named('otherTask')
    inputs.files('package.json', 'package-lock.json')
}

// Defining a new task
// LEGACY SYNTAX: task 'eagerTask' is immediately created and configured, as well as task
// 'installFrontend', even if both tasks are not executed.
task eagerTask {
    dependsOn 'installFrontend'
}
// MODERN SYNTAX: task 'lazyTask' is created and configured only when Gradle is about to execute it.
// Consequently, task 'installFrontend' is also created and configured later. Let's also reinforce this
// behaviour by using its provider to retrieve the task.
tasks.register('lazyTask') {
    dependsOn tasks.named('installFrontend')
}
// Configuring a predefined task.
// LEGACY SYNTAX: task 'installFrontend' is immediately created and configured, as well as task
// 'otherTask', even if both tasks are not executed.
installFrontend {
    dependsOn("otherTask")
    inputs.files("package.json", "package-lock.json")
}
// MODERN SYNTAX: task 'installFrontend' is created and configured only when Gradle is about to execute it.
// Consequently, task 'otherTask' is also created and configured later.
tasks.named<InstallTask>("installFrontend") {
    dependsOn(tasks.named("otherTask"))
    inputs.files("package.json", "package-lock.json")
}

// Defining a new task
// LEGACY SYNTAX: task 'eagerTask' is immediately created and configured, as well as task
// 'installFrontend', even if both tasks are not executed.
task eagerTask {
    dependsOn("installFrontend")
}
// MODERN SYNTAX: task 'lazyTask' is created and configured only when Gradle is about to execute it.
// Consequently, task 'installFrontend' is also created and configured later. Let's also reinforce this
// behaviour by using its provider to retrieve the task.
tasks.register("lazyTask") {
    dependsOn(tasks.named("installFrontend"))
}

If your application uses the legacy syntax, you may find further instructions to migrate to the modern syntax in this Gradle guide.