
Security News
Attackers Are Hunting High-Impact Node.js Maintainers in a Coordinated Social Engineering Campaign
Multiple high-impact npm maintainers confirm they have been targeted in the same social engineering campaign that compromised Axios.
grunt-force-developer
Advanced tools
A grunt task for salesforce and force.com development. Designed to help force.com developers to work using the benefits of grunt and a folder structure when developing.
First - learn about Grunt Second - read the overview below Third - watch this short video demoing grunt-force-developer. Finally - Download via NPM and have a play.
npm install grunt-force-developer --save-dev
Once the plugin has been installed, it may be enabled inside your Gruntfile with this line of JavaScript:
grunt.loadNpmTasks('grunt-force-developer');
Using grunt and the grunt-force-developer tasks, developers for salesforce & force.com can:
To use grunt-force-developer as quickly as possible, we recommend starting with the Gruntfile.js in examples.
Traditionally, when a developer is developing for salesforce / force.com, they are constrained by the mandated package structure. This structure is extremely limiting and, as the size of projects / packages grow, raplidly becomes unwieldy.
package.xml
== classes
-- PaymentController.cls
-- PaymentController.cls-meta.xml
-- UserManagement.cls
-- UserManagement.cls-meta.xml
== pages
-- Payment.page
-- Payment.page-meta.xml
-- UserManagement.page
-- UserManagement.page-meta.xml
== objects
-- Payment__c.object
Using grunt-force-developer, a developer can adopt a fully dynamic file structure that operates independent of the prescribed salesforce package structure. The below example is a snippet from a developer managing their package in structure with little constraints, appropriate for their project.
== .metadata
-- Payment.page-meta.xml
-- PaymentController.cls-meta.xml
-- UserManagement.page-meta.xml
-- UserManagementController.cls-meta.xml
== Admin
== Users
-- UserManagementController.cls
-- UserManagement.page
== Payments
-- PaymentController.cls
-- Payment.page
-- Payment__c.object
In your project's Gruntfile, add a section named force to the data object passed into grunt.initConfig().
var credentials = {
consumerKey: '3MVG98SW_UPr.JFjzEoUdZZczc4pPByJsJh_3hvL_dxAMPsA8DpjdYBXepSg3GztwV.PPEG2Q6YaK1l.11111',
consumerSecret: '1233452345246423523',
username: 'james.kent@gruntdemo.vertic.com.au',
password: 'qwerty123',
token: 'O7uccvnguEXqLnOBiTLC1234'
};
// Project configuration.
grunt.initConfig({
force: {
createPackage: {
options: {
action: 'package'
},
},
deployPackage: {
options: {
action: 'deploy',
consumerKey: credentials.consumerKey,
consumerSecret: credentials.consumerSecret,
username: credentials.username,
password: credentials.password,
token: credentials.token
},
}
}
});
Type: String
Default value: 'deploy'
This option drives the behaviour of the plugin. There are 3 available modes:
Type: String
Default value: 'production'
Values can be 'production' or 'sandbox'. Maps to nforce createConnection.
Type: String
Default value: '.force-developer.filehash.json'
Persists the file hashes to determine modified and new files.
Type: String
Default value: 'app-metadata'
The folder used to store all '-meta.xml' files for the project. A corresponding file is required for all pages, components, trigger and classes. If the projectBaseDirectory isn't altered, the default location is ./project/app-metadata.
Type: Integer
Default value: 500
Sets the polling interval when deploying a package.
Type: String
Default value: 'project'
Used to determine the root of the project folder.
Type: String
Default value: '.package'
The folder used when the files are copied from the project folder into a salesforce package-compliant folder structure.
Type: String
Default value: './.package/package.zip'
The location where the zipped package is to be stored.
Type: Integer
Default value: 34
The api version to be used by the task. Used when creating on-demand meta-xml files.
In this example, the default task is configured to package the new and modified project files and upload these using ant. ant has been used due to problems getting nforce-metadata to deploy zip files -- this will be addressed.
This script enables a developer to work using any folder structure and uploading changes by executing grunt. Once the nforce issue is addressed, this script would be executed grunt default-nforce.
Install the appropriate dependancies required for this Gruntfile by executing:
npm install grunt-force-developer grunt-ant-sfdc grunt-contrib-compress --save-dev
Please ensure ant is installed and available as part of the environment path.
Gruntfile.js:
'use strict';
module.exports = function(grunt) {
// TODO: Update the credentials.
var credentials = {
// Not required for ant deployment
consumerKey: '3MVG98SW_UPr.JFjzEoUdZZczc4pPByJsJh_3hvL_dxAMPsA8DpjdYBXepSg3GztwV.PPEG2Q6YaK1l.11111',
// Not required for ant deployment
consumerSecret: '1233452345246423523',
username: 'james.kent@gruntdemo.vertic.com.au',
password: 'qwerty123',
token: 'O7uccvnguEXqLnOBiTLC1234'
};
// Project configuration.
grunt.initConfig({
// Configuration to be run (and then tested).
force: {
resetCache: {
options: {
action: 'reset'
},
},
createPackage: {
options: {
action: 'package'
},
},
deployPackage: {
options: {
action: 'deploy',
consumerKey: credentials.consumerKey,
consumerSecret: credentials.consumerSecret,
username: credentials.username,
password: credentials.password,
token: credentials.token
},
},
commitCache: {
options: {
action: 'commit'
},
},
},
compress: {
packageZip: {
options: {
archive: './.package/package.zip'
},
files: [
{cwd: './.package/src/', expand: true, src: ['**']} // includes files in path and its subdirs
]
}
},
antdeploy: {
options: {
root: './.package/src/', // note trailing slash is important
apiVersion: '32.0',
existingPackage: true
},
deployPackage: {
options: {
user: credentials.username,
pass: credentials.password,
token: credentials.token
}
}
}
});
// These plugins provide necessary tasks.
grunt.loadNpmTasks('grunt-ant-sfdc');
grunt.loadNpmTasks('grunt-contrib-compress');
grunt.loadNpmTasks('grunt-force-developer');
grunt.registerTask('reset', ['force:resetCache']);
grunt.registerTask('default', ['force:createPackage', 'compress:packageZip', 'antdeploy:deployPackage']);
grunt.registerTask('default-nforce', ['force:createPackage', 'compress:packageZip', 'force:deployPackage']);
};
In lieu of a formal styleguide, take care to maintain the existing coding style. Add unit tests for any new or changed functionality. Lint and test your code using Grunt.
FAQs
A grunt task for salesforce and force.com development
We found that grunt-force-developer demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Security News
Multiple high-impact npm maintainers confirm they have been targeted in the same social engineering campaign that compromised Axios.

Security News
Axios compromise traced to social engineering, showing how attacks on maintainers can bypass controls and expose the broader software supply chain.

Security News
Node.js has paused its bug bounty program after funding ended, removing payouts for vulnerability reports but keeping its security process unchanged.