Is it possible to include AngularJs to a project with Gradle
I have AngularJS 2 + Spring Boot application with Gradle. I use typescript (.ts file) and npm (node js package manager). So I'm running npm install for generate node_modules and npm run tsc for translating typescript to javascript. I still use some of webjars though, basically dependencies are gathered by npm task during build time and wired by systemjs.config.js file
Below is my folder structure
/src/main/java/src/main/resources /app - .ts files and .js translated from .ts /css /js - systemjs.config.js /node_modules - generated by npm install /typings - generated by npm install package.json tsconfig.json typings.json/src/main/webapp/WEB-INF/jsp - .jsp files
This is my build.gradle file and add two custom tasks (npmInstall and npmRunTsc) to run npm tasks
build.gradle
buildscript { repositories { mavenCentral() } dependencies { classpath("org.springframework.boot:spring-boot-gradle-plugin:1.3.5.RELEASE") classpath("org.flywaydb:flyway-gradle-plugin:3.2.1") }}apply plugin: 'java'apply plugin: 'eclipse'apply plugin: 'idea'apply plugin: 'spring-boot'apply plugin: 'war'war { baseName = 'my-angular-app' version = '1.0' manifest { attributes 'Main-Class': 'com.my.Application' }}sourceCompatibility = 1.8targetCompatibility = 1.8repositories { mavenLocal() mavenCentral()}task npmInstall(type:Exec) { workingDir 'src/main/resources' commandLine 'npm', 'install' standardOutput = new ByteArrayOutputStream() ext.output = { return standardOutput.toString() }}task npmRunTsc(type:Exec) { workingDir 'src/main/resources' commandLine 'npm', 'run', 'tsc' standardOutput = new ByteArrayOutputStream() ext.output = { return standardOutput.toString() }}dependencies { // tag::jetty[] compile("org.springframework.boot:spring-boot-starter-web") compile("org.springframework.boot:spring-boot-starter-tomcat", "org.springframework.boot:spring-boot-starter-data-jpa", "org.springframework.boot:spring-boot-starter-actuator", "org.springframework.boot:spring-boot-starter-security", "org.springframework.boot:spring-boot-starter-batch", "org.springframework.cloud:spring-cloud-starter-config:1.0.3.RELEASE", "org.springframework.cloud:spring-cloud-config-client:1.0.3.RELEASE", "com.google.code.gson:gson", "commons-lang:commons-lang:2.6", "commons-collections:commons-collections", "commons-codec:commons-codec:1.10", "commons-io:commons-io:2.4", "com.h2database:h2", "org.hibernate:hibernate-core", "org.hibernate:hibernate-entitymanager", "org.webjars:datatables:1.10.5", "org.webjars:datatables-plugins:ca6ec50", "javax.servlet:jstl", "org.apache.tomcat.embed:tomcat-embed-jasper", "org.quartz-scheduler:quartz:2.2.1", "org.jolokia:jolokia-core", "org.aspectj:aspectjweaver", "org.perf4j:perf4j:0.9.16", "commons-jexl:commons-jexl:1.1", "cglib:cglib:3.2.1", "org.flywaydb:flyway-core", ) providedRuntime("org.springframework.boot:spring-boot-starter-tomcat") testCompile("junit:junit", "org.springframework:spring-test", "org.springframework.boot:spring-boot-starter-test", "org.powermock:powermock-api-mockito:1.6.2", "org.powermock:powermock-module-junit4:1.6.2", )}task wrapper(type: Wrapper) { gradleVersion = '1.11'}
When I run the gradle build process I run like below
$ gradle clean npmInstall npmRunTsc test bootRepackage
I can use same systemjs.config.js shown on AngularJS tutorial
systemjs.config.js
(function(global) { // map tells the System loader where to look for things var map = { 'app': 'app', // 'dist', 'rxjs': 'node_modules/rxjs', 'angular2-in-memory-web-api': 'node_modules/angular2-in-memory-web-api', '@angular': 'node_modules/@angular' }; // packages tells the System loader how to load when no filename and/or no extension var packages = { 'app': { main: 'main.js', defaultExtension: 'js' }, 'rxjs': { defaultExtension: 'js' }, 'angular2-in-memory-web-api': { defaultExtension: 'js' }, }; var packageNames = [ '@angular/common', '@angular/compiler', '@angular/core', '@angular/http', '@angular/platform-browser', '@angular/platform-browser-dynamic', '@angular/router', '@angular/router-deprecated', '@angular/testing', '@angular/upgrade', ]; // add package entries for angular packages in the form '@angular/common': { main: 'index.js', defaultExtension: 'js' } packageNames.forEach(function(pkgName) { packages[pkgName] = { main: 'index.js', defaultExtension: 'js' }; }); var config = { map: map, packages: packages } System.config(config);})(this);
And on .jsp file I include the systemjs.config.js in head section
<script type="text/javascript" src="node_modules/zone.js/dist/zone.js"></script><script type="text/javascript" src="node_modules/reflect-metadata/Reflect.js"></script><script type="text/javascript" src="node_modules/systemjs/dist/system.src.js"></script><script type="text/javascript" src="js/systemjs.config.js"></script>
For last, to sort out context path I do like below on my Spring WebMvcConfigurerAdapter
@Configuration@EnableWebMvc@ComponentScan(basePackages = "com.my.controller")public class WebConfig extends WebMvcConfigurerAdapter { @Override public void addResourceHandlers(ResourceHandlerRegistry registry) { if (!registry.hasMappingForPattern("/webjars/**")) { registry.addResourceHandler("/webjars/**").addResourceLocations("classpath:/META-INF/resources/webjars/"); } if (!registry.hasMappingForPattern("/images/**")) { registry.addResourceHandler("/images/**").addResourceLocations("classpath:/images/"); } if (!registry.hasMappingForPattern("/css/**")) { registry.addResourceHandler("/css/**").addResourceLocations("classpath:/css/"); } if (!registry.hasMappingForPattern("/js/**")) { registry.addResourceHandler("/js/**").addResourceLocations("classpath:/js/"); } if (!registry.hasMappingForPattern("/app/**")) { registry.addResourceHandler("/app/**").addResourceLocations("classpath:/app/"); } if (!registry.hasMappingForPattern("/node_modules/**")) { registry.addResourceHandler("/node_modules/**").addResourceLocations("classpath:/node_modules/"); } } @Bean public InternalResourceViewResolver internalViewResolver() { InternalResourceViewResolver viewResolver = new InternalResourceViewResolver(); viewResolver.setPrefix("/WEB-INF/jsp/"); viewResolver.setSuffix(".jsp"); viewResolver.setOrder(1); return viewResolver; }}
Check out webjars, i highly recommend it.
I've just used it in Maven and Gradle project.
Basically it is just what we needed, a vast collection of front-end projects and frameworks packaged in jars.
Add this dependency to your
build.gradle
script:compile 'org.webjars:angularjs:1.3.14'
Go to documentation section for a quick setup guide for Spring
include
angular.js
or some other module from the jar in you script like a local resource<script src="where-you-exposed-webjars/angular/1.3.14/angular.js"></script>
- Or optionaly require it from
require.js
script
Although it turned out in the discussion below the question that it doesn't make sense to download angular via gradle it can be done with the following piece of code:
repositories { ivy { name = 'AngularJS' url = 'https://code.angularjs.org/' layout 'pattern', { artifact '[revision]/[module](.[classifier]).[ext]' } }}configurations { angular}dependencies { angular group: 'angular', name: 'angular', version: '1.3.9', classifier: 'min', ext: 'js'}task fetch(type: Copy) { from configurations.angular into 'src/main/webapp/js' rename { 'angular.js' }}