Skip to content
This repository was archived by the owner on Mar 3, 2026. It is now read-only.

Commit 47653e3

Browse files
committed
Asset module fix jooby-project#192
The asset module is library to concatenate, minify or compress JavaScript and CSS assets. It also adds the ability to write these assets in other languages and process/compile them to another language. Finally, it help you to write high quality code by validate JavaScript and CSS too. A variety of processors are available (jshint, csslint, jscs, uglify, closure-compiler, etc..), but also you might want to write your owns. ```xml <dependency> <groupId>org.jooby</groupId> <artifactId>jooby-assets</artifactId> <version>{{version}}</version> </dependency> ``` The first thing you need to do is to define your assets. Definition is done in your ```.conf``` file or in a special file: ```assets.conf```. **assets.conf** ```properties assets { fileset { home: [assets/home.js, assets/home.css] } } ``` **App.java** ```java { use(new Assets()); } ``` The assets module will publish 4 request local variables for ```home``` fileset: ```_css``` and ```_js``` each of these variables is a list of string with the corresponding files. There are two more variables: ```_styles``` and ```_scripts``` : ```html <html> <head> {{{home_styles}}} <body> ... {{{home_scripts}} </body> </head> </html> ``` The variables: ```_styles``` and ```_scripts``` produces one ore more ```link``` and ```script``` tags. The example above, shows you how to render these variables in the template engine of your choice (handlebars, here). Now, let's see how to configure the Maven plugin to process our assets at build-time: **pom.xml** ```html <plugin> <groupId>org.jooby</groupId> <artifactId>jooby-maven-plugin</artifactId> <executions> <execution> <goals> <goal>assets</goal> </goals> </execution> </executions> </plugin> ``` The plugin will process all your assets and include them to the final ```.jar```, ```.zip``` or ```.war```. Cool, isn't? The ```assets.fileset``` defines all your assets. In ```dev``` assets are rendered/processed at runtime. In ```prod``` at built-time. Assets are rendered at runtime using ```*_styles``` or ```*_scripts ``` variables. So you define your assets in one single place: ```assets.conf```. Also, at build-time, the asset compiler concatenates all the files from a fileset and generate a fingerprint. The fingerprint is a SHA-1 hash of the content of the fileset. Thanks to the fingerprint an asset can be cached it for ever! Defaults cache max age is: ```365 days```. That isn't all! the ```*_styles``` and ```*_scripts``` are updated with the fingerprint version of assets, so you don't have to do or change anything in your views! It just works!!! A fileset is a group of assets within a name. The fileset name is expanded into 4 request local variables, for example: ```properties assets { fileset { home: [assets/home.js, assets/home.css] pageA: [assets/pageA.js, assets/pageA.css] } } ``` Produces 4 variables for ```home```: * home_css: a list of all the ```css``` files * home_styles: a string, with all the ```css``` files rendered as ```link``` tags * home_js: a list of all the ```js``` files * home_scripts: a string, with all the ```js``` files rendered as ```script``` tags Another 4 variables will be available for the ```pageA``` fileset! Extension or re-use of filesets is possible via the: ```<``` operator: ```properties assets { fileset { base: [js/lib/jquery.js, css/normalize.css] home < base: [js/home.js] pageA < base: [js/pageA.js] } } ``` An [AssetProcessor]({{defdocs}}/assets/AssetProcessor.html) usually checks or modify an asset content in one way or another. They are defined in the ```assets.conf``` files using the ```pipeline``` construction: ```properties assets { fileset { home: [js/home.js, css/home.css] } pipeline { dev: [jshint, jscs, csslint, sass] dist: [uglify, sass, clean-css] } } ``` Example above, defines a **pipeline** for development (dev) and one generic for prod (dist). In ```dev``` the code will be checked it against js-hint, jscs and csslint! But also, we want to use sass for css!! The generic ```dist``` will be used it for any other environment and here we just want to optimize our javascript code with uglify, compile sass to css and then optimize the css using clean-css!!
1 parent 78a98ca commit 47653e3

File tree

299 files changed

+304592
-46
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

299 files changed

+304592
-46
lines changed

coverage-report/pom.xml

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@
6262
<source>${project.parent.basedir}/jooby-sass/src/main/java</source>
6363
<source>${project.parent.basedir}/jooby-less/src/main/java</source>
6464
<source>${project.parent.basedir}/jooby-ebean/src/main/java</source>
65+
<source>${project.parent.basedir}/jooby-assets/src/main/java</source>
6566
</sources>
6667
</configuration>
6768
</execution>
@@ -102,6 +103,7 @@
102103
<source>${project.parent.basedir}/jooby-sass/src/test/java</source>
103104
<source>${project.parent.basedir}/jooby-less/src/test/java</source>
104105
<source>${project.parent.basedir}/jooby-ebean/src/test/java</source>
106+
<source>${project.parent.basedir}/jooby-assets/src/test/java</source>
105107
</sources>
106108
</configuration>
107109
</execution>
@@ -116,6 +118,9 @@
116118
<resource>
117119
<directory>${project.parent.basedir}/jooby/src/test/resources</directory>
118120
</resource>
121+
<resource>
122+
<directory>${project.parent.basedir}/jooby-assets/src/test/resources</directory>
123+
</resource>
119124
<resource>
120125
<directory>${project.parent.basedir}/jooby-hbs/src/test/resources</directory>
121126
</resource>
@@ -364,6 +369,12 @@
364369
<version>${project.version}</version>
365370
</dependency>
366371

372+
<dependency>
373+
<groupId>org.jooby</groupId>
374+
<artifactId>jooby-assets</artifactId>
375+
<version>${project.version}</version>
376+
</dependency>
377+
367378
<dependency>
368379
<groupId>org.jooby</groupId>
369380
<artifactId>jooby-swagger</artifactId>
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
package org.jooby.assets;
2+
3+
import java.util.Arrays;
4+
import java.util.List;
5+
import java.util.Map;
6+
7+
import org.jooby.test.ServerFeature;
8+
9+
import com.google.common.collect.ImmutableMap;
10+
import com.typesafe.config.Config;
11+
import com.typesafe.config.ConfigFactory;
12+
import com.typesafe.config.ConfigValueFactory;
13+
14+
public class AssetsBase extends ServerFeature {
15+
16+
public List<Object> list(final Object... args) {
17+
return Arrays.asList(args);
18+
}
19+
20+
public Map<String, Object> map(final Object... args) {
21+
ImmutableMap.Builder<String, Object> builder = ImmutableMap.builder();
22+
for (int i = 0; i < args.length; i += 2) {
23+
builder.put(args[i].toString(), args[i + 1]);
24+
}
25+
return builder.build();
26+
}
27+
28+
public Config assets(final String dist, final Object... args) {
29+
return ConfigFactory.empty()
30+
.withValue("assets", ConfigValueFactory.fromMap(map(args)));
31+
}
32+
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
package org.jooby.assets;
2+
3+
import org.jooby.Results;
4+
import org.jooby.hbs.Hbs;
5+
import org.junit.Test;
6+
7+
public class NoPipelineFeature extends AssetsBase {
8+
9+
{
10+
11+
use(assets("dev", "basedir", "org/jooby/assets", "fileset",
12+
map("home", list("js/index.js", "css/index.css"))));
13+
14+
use(new Hbs("/org/jooby/assets"));
15+
use(new Assets());
16+
17+
get("/", () -> Results.html("index"));
18+
}
19+
20+
@Test
21+
public void nopipeline() throws Exception {
22+
request()
23+
.get("/")
24+
.expect("[/org/jooby/assets/css/index.css]\n" +
25+
"<link href=\"/org/jooby/assets/css/index.css\" rel=\"stylesheet\">\n" +
26+
"\n" +
27+
"[/org/jooby/assets/js/index.js]\n" +
28+
"<script src=\"/org/jooby/assets/js/index.js\"></script>\n");
29+
}
30+
31+
@Test
32+
public void indexjs() throws Exception {
33+
request()
34+
.get("/org/jooby/assets/js/index.js")
35+
.expect("function index() {\n" +
36+
"}\n" +
37+
"");
38+
}
39+
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
.index {
2+
3+
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{{&home_css}}
2+
{{&home_styles}}
3+
{{&home_js}}
4+
{{&home_scripts}}
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
function index() {
2+
}

jooby-assets-clean-css/pom.xml

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
3+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
4+
5+
<parent>
6+
<groupId>org.jooby</groupId>
7+
<artifactId>jooby-project</artifactId>
8+
<version>0.11.0-SNAPSHOT</version>
9+
</parent>
10+
11+
<modelVersion>4.0.0</modelVersion>
12+
<artifactId>jooby-assets-clean-css</artifactId>
13+
14+
<name>clean-css module</name>
15+
16+
<build>
17+
<plugins>
18+
<!-- sure-fire -->
19+
<plugin>
20+
<groupId>org.apache.maven.plugins</groupId>
21+
<artifactId>maven-surefire-plugin</artifactId>
22+
<configuration>
23+
<includes>
24+
<include>**/*Test.java</include>
25+
<include>**/*Feature.java</include>
26+
<include>**/Issue*.java</include>
27+
</includes>
28+
</configuration>
29+
</plugin>
30+
31+
</plugins>
32+
</build>
33+
34+
<dependencies>
35+
<!-- Jooby -->
36+
<dependency>
37+
<groupId>org.jooby</groupId>
38+
<artifactId>jooby-assets-j2v8</artifactId>
39+
<version>${project.version}</version>
40+
</dependency>
41+
42+
<!-- Test dependencies -->
43+
<dependency>
44+
<groupId>org.jooby</groupId>
45+
<artifactId>jooby</artifactId>
46+
<version>${project.version}</version>
47+
<scope>test</scope>
48+
<classifier>tests</classifier>
49+
</dependency>
50+
51+
<dependency>
52+
<groupId>junit</groupId>
53+
<artifactId>junit</artifactId>
54+
<scope>test</scope>
55+
</dependency>
56+
57+
<dependency>
58+
<groupId>org.easymock</groupId>
59+
<artifactId>easymock</artifactId>
60+
<scope>test</scope>
61+
</dependency>
62+
63+
<dependency>
64+
<groupId>org.powermock</groupId>
65+
<artifactId>powermock-api-easymock</artifactId>
66+
<scope>test</scope>
67+
</dependency>
68+
69+
<dependency>
70+
<groupId>org.powermock</groupId>
71+
<artifactId>powermock-module-junit4</artifactId>
72+
<scope>test</scope>
73+
</dependency>
74+
75+
<dependency>
76+
<groupId>org.jacoco</groupId>
77+
<artifactId>org.jacoco.agent</artifactId>
78+
<classifier>runtime</classifier>
79+
<scope>test</scope>
80+
</dependency>
81+
82+
</dependencies>
83+
84+
</project>
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
/**
2+
* Licensed to the Apache Software Foundation (ASF) under one
3+
* or more contributor license agreements. See the NOTICE file
4+
* distributed with this work for additional information
5+
* regarding copyright ownership. The ASF licenses this file
6+
* to you under the Apache License, Version 2.0 (the
7+
* "License"); you may not use this file except in compliance
8+
* with the License. You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
package org.jooby.assets;
20+
21+
import org.jooby.MediaType;
22+
23+
import com.typesafe.config.Config;
24+
25+
/**
26+
* <h1>clean-css</h1>
27+
* <p>
28+
* A fast, efficient, and well tested CSS minifier, via:
29+
* <a href="https://github.com/jakubpawlowicz/clean-css">clean-css</a>
30+
* </p>
31+
*
32+
* <h2>usage</h2>
33+
*
34+
* <pre>
35+
* assets {
36+
* fileset {
37+
* home: ...
38+
* }
39+
*
40+
* pipeline {
41+
* ...
42+
* dist: [clean-css]
43+
* }
44+
* }
45+
* </pre>
46+
*
47+
* <h2>options</h2>
48+
*
49+
* <pre>
50+
* assets {
51+
* ...
52+
* clean-css {
53+
* advanced: true
54+
* aggressiveMerging: true
55+
* }
56+
* }
57+
* </pre>
58+
*
59+
* @author edgar
60+
* @since 0.11.0
61+
*/
62+
public class CleanCss extends AssetProcessor {
63+
64+
public CleanCss() {
65+
set("advanced", true);
66+
set("aggressiveMerging", true);
67+
}
68+
69+
@Override
70+
public boolean matches(final MediaType type) {
71+
return MediaType.css.matches(type);
72+
}
73+
74+
@Override
75+
public String process(final String filename, final String source, final Config conf)
76+
throws Exception {
77+
return V8Context.run(v8 -> {
78+
return v8.invoke("clean-css.js", source, options(), filename);
79+
});
80+
}
81+
82+
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
// Hack for require('http');
2+
var global = {
3+
XMLHttpRequest: function () {
4+
return {
5+
open: function (p, k) {
6+
}
7+
};
8+
},
9+
10+
location: {
11+
host: '/'
12+
}
13+
};
14+
(function (source, options) {
15+
/** Source: See org.jooby.assets.Generator.java */
16+
assets.load('lib/clean-css-3.4.3.js');
17+
18+
var cleancss = new global.CleanCSS(options);
19+
var output = cleancss.minify(source);
20+
21+
var errors = [];
22+
output.errors.concat(output.warnings).forEach(function (error) {
23+
errors.push({
24+
message: error
25+
});
26+
});
27+
28+
return {
29+
output: output.styles,
30+
errors: errors
31+
};
32+
});

0 commit comments

Comments
 (0)