From 4bbc34e3b47bcf3c7bfa8f61a35a7ed16c03a636 Mon Sep 17 00:00:00 2001
From: Jesse Weaver <pianohacker@gmail.com>
Date: Tue, 17 Oct 2017 16:27:43 -0600
Subject: [PATCH] Bug 15522: Add JS build pipeline

This is not directly testable, but can be either used through the
Makefile:

$ make js-build

(This will automatically install all dependencies.)

Or by manually installing yarn:

$ sudo apt install nodejs npm
$ sudo npm install -g yarn
$ yarn install
$ yarn build

(There is also `make js-watch` and `yarn watch`, which automatically
recompile when files are changed.)

JD note: the make rule does not work
---
 .gitignore   |  1 +
 Makefile.PL  | 19 ++++++++++++++++++-
 gulpfile.js  | 50 +++++++++++++++++++++++++++++++++++++++++++++++++-
 package.json | 15 ++++++++++++++-
 4 files changed, 82 insertions(+), 3 deletions(-)

diff --git a/.gitignore b/.gitignore
index c70d94a1dd..cb9c7af4b0 100644
--- a/.gitignore
+++ b/.gitignore
@@ -5,3 +5,4 @@
 node_modules/
 koha-tmpl/opac-tmpl/bootstrap/css/maps/
 koha-tmpl/intranet-tmpl/prog/css/maps/
+koha-tmpl/intranet-tmpl/prog/js/built
diff --git a/Makefile.PL b/Makefile.PL
index 69eae835b7..edbe671b8f 100644
--- a/Makefile.PL
+++ b/Makefile.PL
@@ -1719,7 +1719,24 @@ sub postamble {
 		$env .= join("\n", map { "export __${_}__ := $config{$_}" } keys %config);
 	}
 
-    return "$env\n";
+    my $js_build_targets = <<'JS';
+.PHONY: js-build js-deps js-watch
+YARN=node_modules/.bin/yarn
+
+$(YARN):
+	npm install yarn
+
+js-deps: $(YARN)
+	$(YARN) install
+
+js-build: $(YARN) js-deps
+	$(YARN) build
+
+js-watch: $(YARN) js-deps
+	$(YARN) watch
+JS
+
+    return "$env\n$js_build_targets\n";
 }
 
 
diff --git a/gulpfile.js b/gulpfile.js
index 1214585d21..c549e1875f 100644
--- a/gulpfile.js
+++ b/gulpfile.js
@@ -10,7 +10,10 @@ try {
     process.exit(1);
 }
 
+const browserify = require( "browserify" );
 const gutil = require( "gulp-util" );
+const source = require( "vinyl-source-stream" );
+const tap = require( "gulp-tap" );
 const sass = require("gulp-sass");
 const cssnano = require("gulp-cssnano");
 const sourcemaps = require('gulp-sourcemaps');
@@ -21,6 +24,15 @@ const STAFF_CSS_BASE = "koha-tmpl/intranet-tmpl/prog/css";
 const OPAC_JS_BASE = "koha-tmpl/opac-tmpl/bootstrap/js";
 const OPAC_CSS_BASE = "koha-tmpl/opac-tmpl/bootstrap/css";
 
+// These node modules will be shoved into vendor.js instead of each built file.
+const VENDOR_DEPENDENCIES = [
+    "lodash",
+    "promise-polyfill",
+    "react",
+    "react-dom",
+    "whatwg-fetch",
+];
+
 var sassOptions = {
     errLogToConsole: true,
     precision: 3
@@ -58,4 +70,40 @@ gulp.task('build', function() {
 
 gulp.task('watch', function(){
     gulp.watch( css_base + "/src/**/*.scss", ['css'] );
-});
\ No newline at end of file
+});
+
+let vendorBuilt = false;
+
+function getBundler() {
+    let bundler = browserify( {
+        debug: !process.env.PRODUCTION,
+    } );
+
+    if ( process.env.DESCRIPTION ) {
+        bundler.transform( "uglifyify" );
+    }
+
+    return bundler;
+}
+
+gulp.task( "build", () => {
+    if ( !vendorBuilt ) {
+        getBundler().require( VENDOR_DEPENDENCIES )
+            .bundle()
+            .on( "error", gutil.log )
+            .pipe( source( "vendor.js" ) )
+            .pipe( gulp.dest( js_base + "/built/" ) );
+    }
+
+    let bundler = getBundler().transform( "babelify", { presets: [ "es2015", "react" ], plugins: [ "transform-class-properties" ] } );
+
+    return gulp.src( js_base + '/src/**/entry.js' )
+        .pipe( tap( file => {
+            let base_start = file.path.indexOf( js_base );
+            gutil.log( `bundling ${file.path.substr( base_start + js_base.length + 1 )}` );
+
+            bundler.external( VENDOR_DEPENDENCIES );
+            file.contents = bundler.add( file.path ).bundle();
+        } ) )
+        .pipe( gulp.dest( js_base+ "/built" ) );
+} );
diff --git a/package.json b/package.json
index 3d9092402c..ef0eb009a4 100644
--- a/package.json
+++ b/package.json
@@ -7,12 +7,25 @@
     "test": "test"
   },
   "dependencies": {
+    "babel-plugin-transform-class-properties": "^6.24.1",
+    "babel-preset-es2015": "^6.24.1",
+    "babel-preset-react": "^6.24.1",
+    "babelify": "^7.3.0",
+    "browserify": "^14.4.0",
     "gulp": "^3.9.1",
     "gulp-autoprefixer": "^4.0.0",
     "gulp-cssnano": "^2.1.2",
     "gulp-sass": "^3.1.0",
     "gulp-sourcemaps": "^2.6.1",
-    "gulp-util": "^3.0.8"
+    "gulp-tap": "^1.0.1",
+    "gulp-util": "^3.0.8",
+    "lodash": "^4.17.4",
+    "promise-polyfill": "^6.0.2",
+    "react": "^16.0.0",
+    "react-dom": "^16.0.0",
+    "uglifyify": "^4.0.4",
+    "vinyl-source-stream": "^1.1.0",
+    "whatwg-fetch": "^2.0.3"
   },
   "devDependencies": {},
   "scripts": {
-- 
2.11.0