Security News
UK Officials Consider Banning Ransomware Payments from Public Entities
The UK is proposing a bold ban on ransomware payments by public entities to disrupt cybercrime, protect critical services, and lead global cybersecurity efforts.
@jenkins-cd/js-builder
Advanced tools
Table of Contents:
NPM utility for building CommonJS module bundles (and optionally making them js-modules compatible).
See js-modules.
The following diagram illustrates the basic flow (and components used) in the process of building a CommonJS module bundle. It uses a number of popular JavaScript and maven tools (CommonJS/node.js, Browserify, Gulp, frontend-maven-plugin and more).
The responsibilities of the components in the above diagram can be summarized as follows:
require
syntax synonymous with node.js (for module loading) e.g. var mathUtil = require('../util/mathUtil');
. This allows us to tap into the huge NPM JavaScript ecosystem.require
calls (see above) resolve properly to the correct module within the bundle.js-builder
does a number of things:
bundle
task below). The bundle file is typically placed somewhere on the filesystem that allows a higher level Maven build to pick it up and include it in e.g. a Jenkins plugin HPI file (so it can be loaded by the browser at runtime)..hbs
) and include them in the bundle file (see 2 above)..css
file that can be picked up by the top level Maven build and included in the e.g. a Jenkins plugin HPI file. See the bundle
task below.import
- see js-modules), making the bundle a lot lighter by allowing it to use a shared instance of the Framework lib Vs it being included in the bundle. This can easily reduce the size of a bundle from e.g. 1Mb to 50Kb or less, as Framework libs are often the most weighty components. See the bundle
task below.export
(see js-modules) the bundles "main" CommonJS module (see 2 above) so as to allow other bundles import
it i.e. effectively making the bundle a Framework lib (see 5 above). See the bundle
task below.npm install --save-dev @jenkins-cd/js-builder
This assumes you have node.js (minimum v4.0.0) installed on your local development environment.
Note this is only required if you intend developing js-modules compatible module bundles. Plugins using this should automatically handle all build aspects via maven (see later) i.e. simple building of a plugin should require no machine level setup.
Add a gulpfile.js
(see Gulp) in the same folder as the package.json
. Then use js-builder
as follows:
var builder = require('@jenkins-cd/js-builder');
builder.bundle('./index.js', 'myappbundle.js')
.inDir('target/classes/org/jenkins/myapp/ui');
The following sections describe the available predefined Gulp tasks.
Note: If no task is specified (i.e. you just type
gulp
on its own), then thebundle
andtest
tasks are auto-installed (i.e. auto-run) as the default tasks.
Run the 'bundle' task. See detail on this in the dedicated section titled "Bundling" (below).
gulp bundle
Run tests. The default location for tests is the spec
folder. The file names need to match the
pattern "*-spec.js". The default location can be overridden by calling builder.tests(<new-path>)
.
gulp test
See jenkins-js-test for more on testing. See command line options for
--skipTest
option. See command line options for--test
option (for running a single test spec).
Watch module source files (index.js
, ./lib/**/*.js
and ./lib/**/*.hbs
) for change, auto-running the
bundle
task whenever changes are detected.
Note that this task will not be run by default, so you need to specify it explicitly on the gulp command in order to run it e.g.
gulp bundle:watch
Watch module source files changes (including test code) and rerun the tests e.g.
gulp test:watch
Run linting - ESLint or JSHint. ESlint is the default if no .eslintrc
or .jshintrc
file is found
(using eslint-config-jenkins) in the working
directory (.eslintrc
is also searched for in parent directories).
gulp lint
See command line options for
--skipLint
,--continueOnLint
and--fixLint
options.
There are times when you need to break out and redefine one of the predefined gulp tasks (see previous section).
To redefine a task, you simply call defineTask
again e.g. to redefine the test
task to use mocha:
builder.defineTask('test', function() {
var mocha = require('gulp-mocha');
var babel = require('babel-core/register');
builder.gulp.src('src/test/js/*-spec.js')
.pipe(mocha({
compilers: {js: babel}
})).on('error', function(e) {
if (builder.isRetest()) {
// ignore test failures if we are running test:watch.
return;
}
throw e;
});
});
As stated in the "Features" section above, much of the usefulness of js-builder
lies in how it
helps with the bundling of the different JavaScript and CSS components:
.css
file.hbs
) into the JavaScript bundle.It also helps with js-modules compatibility i.e. handling import
s and export
s so as to allow
slimming down of your "app" bundle.
Most of the bundling options are configured on the "Bundle Spec", which is an object returned from
a call to the bundle
function on the builder
:
var bundleSpec = builder.bundle('<path-to-main-module>', '<bundle-name>');
path-to-main-module
: The path to the "main" CommonJS module, from which Browserify will start the bundling process (see Browserify for more details). E.g. 'js/bootstrap3.js'
.bundle-name
(Optional): The name of the bundle to be generated. If not specified, the "main" module name will be used.js-builder
lets you configure where the generated bundle is output to. There are 3 possible
options for this.
Option 1: Bundle as a js-modules "resource", which means it will be placed in the
./src/main/webapp/jsmodules
folder, from where it can beimport
ed at runtime. This option should be used in conjunction withbundleSpec.export()
(see below).
bundleSpec.asJenkinsModuleResource();
Option 2: Bundle in a specified directory/folder.
bundleSpec.inDir('<path-to-dir>');
Option 3: Bundle as an "adjunct", which means the bundle is put into a package in
./target/generated-adjuncts/
. If using this option, make sure the project'spom.xml
has the appropriate build<resource>
configuration (see below).Of course, you can also just use the
bundleSpec.inDir
option (num 2 above) if you'd prefer to handle adjuncts differently i.e. usebundleSpec.inDir
to generate the bundle into a dir that gets picked up by your maven build, placing the bundle in the correct place on the Java classpath.
bundleSpec.inAdjunctPackage('com.acme');
An example of how to configure the build <resource>
in your pom.xml
file (if using inAdjunctPackage
), allowing the adjunct to be referenced from a Jelly file.
<build>
<resources>
<resource>
<directory>src/main/resources</directory>
</resource>
<resource>
<directory>target/generated-adjuncts</directory>
</resource>
</resources>
</build>
Specify a LESS file for pre-processing to CSS:
bundleSpec.less('js/bootstrap3/style.less');
The output location for the generated .css
file depends on the output location chosen for the bundle. See Step 2 above.
Some of the NPM packages used by your "app" bundle will be common Framework libs that, for performance reasons, you do not want bundled in every "app" bundle. Instead, you would prefer all "app" bundles to share an instance of these common Framework libs.
That said, you would generally prefer to code your application's CommonJS modules as normal, using the more
simple/intuitive CommonJS style require
syntax (synch), and forget about performance optimizations until
later (build time). When doing it this way, your CommonJS module code should just require
the NPM packages it
needs and just use them as normal e.g.
var moment = require('moment');
moment().format('MMMM Do YYYY, h:mm:ss a');
The above code will work fine as is (without performing any mappings), but the downside is that your app bundle will be more bloated as it will
include the moment
NPM module. To lighten your bundle for the browser (by using a shared instance of the moment
NPM module), we tell the builder
(via the bundleSpec
) to "map" (transform) all synchronous require
calls for moment
to async
import
s of the momentjs:momentjs2
Framework lib bundle
(see the momentjs framwork lib bundle).
bundleSpec.withExternalModuleMapping('moment', 'momentjs:momentjs2');
Of course your "app" bundle may depend on a number of weighty Framework libs that you would prefer not to
include in your bundle. If so, simply call withExternalModuleMapping
for each.
Note that you can apply global mappings by calling
withExternalModuleMapping
on the top levelbuilder
instance. This is useful if you are creating multiple bundles, many/all of which are using the same external module mappings.
Externalizing commons Framework libs (see Step 4) is important in terms of producing a JavaScript bundle that can be used in production (is lighter etc), but can make things a bit trickier when it comes to Integration Testing your bundle because your test (and test environment) will now need to accommodate the fact that your bundle no longer contains all the Framework libs it depends on.
For that reason, js-builder
supports the generateNoImportsBundle
option, which tells the builder to also generate
a bundle that includes all of it's dependency Framework libs i.e. a bundle which does not apply imports (hence "no_imports").
bundleSpec.generateNoImportsBundle();
Note that this is an additional bundle i.e. not instead of the "main" bundle (in which "imports" are applied).
With this option set, the "no_imports" bundle is generated into a sub-folder named "no_imports", inside the same folder in which the "main" bundle is generated.
For an example of how to use the
generateNoImportsBundle
option, see the "step-08-zombie-tests" Integration Test sample plugin.
Exporting the "main" module (allowing other bundle modules to import
it) from the bundle is easy:
bundleSpec.export();
The builder
will use the plugin's artifactId
from the pom.xml
(which becomes the plugin ID), as well as the
bundle name (normalised from the bundle name specified during Step 1) to determine the export
bundle ID for
the module.
For example, if the plugin's artifactId
is "acmeplugin" and the bundle name specified is "acme.js", then the
module would be exported as acmeplugin:acme
. The package associated with the "acme.js" module should also be
"published" to NPM so as to allow "app" bundles that might use it to add a dev
dependency on it (so tests
etc can run).
So how would an "app" bundle in another plugin use this later?
It would need to:
dev
dependency on the package associated with the "acme.js" module i.e. npm install --save-dev acme
. This allows the next step will work (and tests to run etc).require
and use the acme
module e.g. var acme = require('acme');
.gulpfile.js
, add a withExternalModuleMapping
e.g. bundleSpec.withExternalModuleMapping('acme', 'acmeplugin:acme');
.See Step 4 above.
This can be done by calling minify
on js-builder
:
bundleSpec.minify();
Or, by passing --minify
on the command line. This will result in the minification of all generated bundles.
$ gulp --minify
There are times when you will need access to the underlying Browserify bundler
just before the
bundling process is executed (e.g. for adding transforms etc).
To do this, you call the onPreBundle
function. This function takes a listener
function as an argument.
This listener
function, when called, receives the bundle
as this
and the bundler
as the only argument to
the supplied listener
.
var builder = require('@jenkins-cd/js-builder');
builder.onPreBundle(function(bundler) {
var bundle = this;
console.log('Adding the funky transform to bundler for bundle: ' + bundle.as);
bundler.transform(myFunkyTransform);
});
The default paths depend on whether or not running in a maven project.
For a maven project, the default source and test/spec paths are:
./src/main/js
and ./src/main/less
(used primarily by the bundle:watch
task, watching these folders for source changes)./src/test/js
(used by the test
task)Otherwise, they are:
./js
and ./less
(used primarily by the bundle:watch
task, watching these folders for source changes)./spec
(used by the test
task)Changing these defaults is done through the builder
instance e.g.:
var builder = require('@jenkins-cd/js-builder');
builder.src('src/main/js');
builder.tests('src/test/js');
You can also specify an array of src
folders e.g.
builder.src(['src/main/js', 'src/main/less']);
A number of js-builder
options can be specified on the command line. If you are looking for
--h
(or --help
)Get a link to this documentation.
$ gulp --h
--minify
Passing --minify
on the command line will result in the minification of all generated bundles.
$ gulp --minify
--test
Run a single test.
$ gulp --test configeditor
The above example would run test specs matching the **/configeditor*-spec.js
pattern (in the test source directory).
--skipTest
, --skipLint
, --skipBundle
Skip one or more of the tasks/phases e.g.
$ gulp --skipTest --skipLint
--skipLint
, --continueOnLint
, --fixLint
Many of the more irritating formatting rule errors/warnings can be fixed automatically by running
with the --fixLint
option, making them a little less irritating e.g.
$ gulp --fixLint
Or if you are just running the lint
task on it's own (explicitly):
$ gulp lint --fixLint
Alternatively, if you wish to run lint
and see all of the lint errors, but not fail the build:
$ gulp --continueOnLint
And to skip linting completely:
$ gulp --skipLint
Hooking a Gulp based build into a Maven build involves adding a few Maven <profile>
s to the
Maven project's pom.xml
. For Jenkins plugins, the easiest way to get this integration is to simply
have the plugin pom.xml
depend on the Jenkins plugin-pom. For other project types, you'll need
to copy those profiles locally (see plugin-pom).
These integrations hook the Gulp build into the maven build lifecycles. A few mvn
build
switches are supported, as described in the following sections.
-DcleanNode
Cleans out the local node and NPM artifacts and resource (including the node_modules
folder).
$ mvn clean -DcleanNode
-DskipTests
This switch is a standard mvn
switch and is honoured by the profiles defined in the plugin-pom.
$ mvn clean -DskipTests
-DskipTests
also skips linting. See -DskipLint
-DskipLint
Skip linting.
$ mvn clean -DskipLint
FAQs
Jenkins CI JavaScript Build utilities.
The npm package @jenkins-cd/js-builder receives a total of 1,177 weekly downloads. As such, @jenkins-cd/js-builder popularity was classified as popular.
We found that @jenkins-cd/js-builder demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 9 open source maintainers 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
The UK is proposing a bold ban on ransomware payments by public entities to disrupt cybercrime, protect critical services, and lead global cybersecurity efforts.
Security News
Snyk's use of malicious npm packages for research raises ethical concerns, highlighting risks in public deployment, data exfiltration, and unauthorized testing.
Research
Security News
Socket researchers found several malicious npm packages typosquatting Chalk and Chokidar, targeting Node.js developers with kill switches and data theft.