templates.plugins.spincast-js-closurecompiler.spincast-js-closurecompiler.html Maven / Gradle / Ivy
Show all versions of spincast-website Show documentation
{% extends "../../layout.html" %}
{% block sectionClasses %}plugins hasBreadCrumb plugins-spincast-js-closurecompiler{% endblock %}
{% block meta_title %}Plugins - Spincast JS Closure Compiler{% endblock %}
{% block meta_description %}Spincast JS Closure Compiler plugin - Integration with Google's Closure Compiler to optimize your Javascript files.{% endblock %}
{% block scripts %}
{% endblock %}
{% block body %}
Overview
This plugin integrates Google's Closure Compiler.
It is used to optimize and compress your Javascript files.
Closure Compiler
is a well-supported library that can be used
even with modern ECMAScript
features!
Usage
You inject and use
the SpincastJsClosureCompilerManager
component where you need to optimize Javascript files.
It is highly suggested that you only optimize a given Javascript file one time and
then serve a cached version of it after that! The optimization done by the Closure Compiler
can indeed take a couple of seconds.
One good way to optimize and then cache a Javascript file is by using
a dynamic resource:
{% verbatim %}
router.dir("/publicdyn/js/*{relativePath}")
.pathRelative("/publicdyn/js")
.handle(publicResourcesController::dynJs);
{% endverbatim %}
In the "dynJs(...)
" handler, you would get the raw content of the .js
file and optimize it using
the SpincastJsClosureCompilerManager
component before sending the result:
{% verbatim %}
File jsFile = //... get the .js file
String rawJsContent = FileUtils.readFileToString(jsFile, "UTF-8");
String jsOptimized = getSpincastJsClosureCompilerManager()
.compile(rawJsContent,
"--compilation_level ", "WHITESPACE_ONLY");
context.response().sendCharacters(jsOptimized, "application/javascript");
{% endverbatim %}
Explanation :
-
1 : We get the
.js
file using the
"relativePath
" path parameter taken from the request. We make sure we validate
this user input properly!
-
3 : We get the raw Javascript content.
-
5-6 : We call the
compile(...)
method.
-
7 : In this example, we specify one option (using two arguments).
You will learn more about options in the next section
-
9 : We send the optimized Javascript, using the proper content-type. Since this is a
dynamic resource route, the result will be cached and it is this cached version that will be served on next requests!
Flags and Options
Read the official Flags and Options
documentation of Closure Compiler
to learn how to tweak the optimization of your Javascript files.
There are two ways you can specify an option such as "--compilation_level
" with a value of "WHITESPACE_ONLY
":
1. Using two separate arguments
{% verbatim %}
String jsOptimized =
getSpincastJsClosureCompilerManager()
.compile(jsContent, "--compilation_level", "WHITESPACE_ONLY");
{% endverbatim %}
2. Or using one argument only with a "=
" between the name and the value
{% verbatim %}
String jsOptimized =
getSpincastJsClosureCompilerManager()
.compile(jsContent, "--compilation_level=WHITESPACE_ONLY");
{% endverbatim %}
Some options take only one argument without any value at all (ex: --strict_mode_input
).
You cannot use the "--js_output_file
" option! This option is managed
by the plugin. If you specify it, your version will be ignored.
Note that, when bundling Javascript files
for Spincast itself,
we had to use "--language_out ECMASCRIPT_2017
" or errors were generated! You may try this option if you get errors.
SpincastJsClosureCompilerManager methods
The main methods provided by
SpincastJsClosureCompilerManager are:
-
String compile(String jsContent, String... args))
Run the Closure Compiler on the specified Javascript content, as a String. Return the optimized
Javascript.
The command generated by this method will be equivalent to:
java -jar closure-compiler.jar --js_output_file=internalSpincastFile fileCreatedFromYourJsContent.js [YOUR ARGS]
-
String compile(File jsFile, String... args))
Run the Closure Compiler on the content of the specified .js file. Return the optimized
Javascript.
The command generated by this method will be equivalent to:
java -jar closure-compiler.jar --js_output_file=internalSpincastFile yourFile.js [YOUR ARGS]
-
String compile(List<File> jsFiles, String... args))
Run the Closure Compiler on the concatenated content of multiple .js files. Return the
concatenated and optimized Javascript.
You can read more about using multiple input files here.
The command generated by this method will be equivalent to:
java -jar closure-compiler.jar --js_output_file=internalSpincastFile file1.js file2.js file3.js [YOUR ARGS]
-
String compileCustom(String... args))
Run the Closure Compiler using only custom arguments. Return the optimized
Javascript.
When you use this method, you are responsible to specify
all the arguments that are going to be passed to the Closure Compiler (except, again,
"--js_output_file
"). This means you are responsible to specify
the input files as arguments too!
To specify the input files as arguments, you can use globs patterns
if you want.
The command generated by this method will be equivalent to:
java -jar closure-compiler.jar --js_output_file=internalSpincastFile [YOUR ARGS]
Pebble function to easily bundle multiple Javascript files
If you are using Pebble, the default Templating Engine, a
function is provided by this plugin to bundle multiple Javascript files together directly from an HTML
template.
Let's say your HTML
template includes those .js
files:
{% verbatim %}
<script src="/public/js/jquery.js"></script>
<script src="/public/js/anotherLibrary.js"></script>
<script src="/publicdyn/js/{{spincast.cacheBuster}}main.js"></script>
{% endverbatim %}
You could convert those separate files to a single compressed and optimized bundle,
so an unique and fast request is required from the client!
To do so, you use the jsBundle(...)
Pebble function which is provided when this
plugin is installed:
{% verbatim %}
{{ jsBundle('/public/js/jquery.js',
'/public/js/anotherLibrary.js',
'/publicdyn/js/main.js') }}
{% endverbatim %}
This function will concatenate all the specified
Javascript files, will optimize them using the Closure Compiler
and will output a resulting "<script>
" element pointing to the
bundle:
{% verbatim %}
<script src="/spincast/plugins/jsclosurecompiler/jsbundles/resultingBundle.js"></script>
{% endverbatim %}
The parameters accepted by the jsBundle(...)
function are:
-
First, the paths to the Javascript files to bundle. Those paths must
be absolute (they must start with a "
/
").
-
Then, the options to pass to the Closure Compiler
.
Those must be specified after the paths to the Javascript files.
When an argument starting with "-
" is found, this argument and all the following ones
are considered as options for the Closure Compiler
!
-
There is a single option specific to Spincast that you can use: "--spincast-no-cache-busting
".
When this flag is specified, no cache busting code
will be added to the resulting bundle path.
Here is an example of using jsBundle(...)
with options:
{% verbatim %}
{{ jsBundle('/public/js/jquery.js',
'/public/js/anotherLibrary.js',
'/publicdyn/js/main.js',
'--compilation_level', 'WHITESPACE_ONLY',
'--formatting', 'PRETTY_PRINT',
'--spincast-no-cache-busting') }}
{% endverbatim %}
Behind the scene, calling jsBundle(...)
will not only generate the bundle,
but will also automatically add the associated route to
your router!
The resulting bundle will be cached (it will only be generated on the very first
request), will be served with caching HTTP headers and will contain
a cache busting code (except if the
"--spincast-no-cache-busting
" flag is used).
During development, you probably want to disable the bundling
so changes made to the CSS files are available immediately (no cache).
There is a configuration for that!
{% verbatim %}
Don't forget to remove any "{{spincast.cacheBuster}}
" tag
when you move a regular .js file to a jsBundle(...)
function!
{% endverbatim %}
Note that the content of the Javascript files to bundle together will be retrieved using HTTP
requests! This allows you
to use dynamic resources to generate those files,
if required.
Bundling multiple files may take a couple of seconds... If you want to prevent the
first request made to this bundle to be slow, you can pre-generate the bundle when your application
starts.
Here is an example where we do this, for this very website.
If, for some reason, you want to change the output made by
jsBundle(...)
, you can extend
SpincastJsClosureCompilerPebbleExtensionDefault,
override the "bundlingOutput(String path)
" function and bind your implementation
to the SpincastJsClosureCompilerPebbleExtension
interface in the Guice context.
Configurations
You can bind a custom implementation of SpincastJsClosureCompilerConfig
to tweak global configurations. This implementation can extend
SpincastJsClosureCompilerConfigDefault
as a base class.
-
String getJsBundlePebbleFunctionName()
The name to give to the Pebble function provided by this plugin to
bundle multiple Javascript files together. It is the name you are going to use
in your HTML
file to call the function.
Defaults to "jsBundle
".
-
String getJsBundlesUrlPath()
The base URL path where the Javascript bundles will be served from.
The path returned by the jsBundle()
Pebble function
will start with this base path.
Defaults to "/spincast/plugins/jsclosurecompiler/jsbundles
".
-
File getJsBundlesDir()
The directory where the jsBundle()
Pebble function will save the
generated Javascript bundles.
Defaults to "[WRITABLE_DIR]/spincast/plugins/jsclosurecompiler/jsBundles
".
-
boolean isJsBundlesIgnoreSslCertificateErrors()
When the jsBundle()
Pebble function retrieves the files to be bundled
together, should SSL
certificate errors be ignored? Setting this to true
is useful
during testing, on a development environment where a self-signed certificate may be used.
Defaults to true
if
isDevelopmentMode()
or
isTestingMode()
is true
.
-
boolean isJsBundlesDisabled()
When this is true
, the jsBundle()
Pebble function will not bundle
the specified files together. The files will be served as usual, each with their
own "<script>
" tag.
This is useful during development, when you don't want any cache
and want changes to the files to be immediately available!
Defaults to true
if
isDevelopmentMode()
is true
.
Dependencies
This plugin depends on the
Spincast HTTP Client plugin
which is not provided by default by the spincast-default
artifact.
It also uses Spincast Pebble plugin which is included
in the spincast-default
artifact.
Those plugins will be automatically installed. Note that it is always a good
idea to read the documentation of the automatically installed plugins though!
Installation
1.
Add this Maven artifact to your project:
<dependency>
<groupId>org.spincast</groupId>
<artifactId>spincast-plugins-js-closurecompiler</artifactId>
<version>{{spincast.spincastCurrrentVersion}}</version>
</dependency>
2. Add an instance of the SpincastJsClosureCompilerPlugin
plugin to your Spincast Bootstrapper:
{% verbatim %}
Spincast.configure()
.plugin(new SpincastJsClosureCompilerPlugin())
// ...
{% endverbatim %}
{% endblock %}