LP#1739803 Webstaff: Replace Grunt with Webpack
authorBill Erickson <berickxx@gmail.com>
Wed, 20 Dec 2017 16:13:10 +0000 (11:13 -0500)
committerGalen Charlton <gmc@equinoxinitiative.org>
Wed, 21 Feb 2018 19:42:08 +0000 (14:42 -0500)
* Remove grunt devDependencies
* Add Webpack devDepenencies
* Copy and minify operations are now handled by Webpack via 'npm run
  build' for dev builds and 'npm run build-prod' for
  production/minified builds.
* Running 'npm run build-watch' executes webpack in --watch mode to
  watch for affected file changes and automatically rebuild.  Useful for
  development.
* Karma unit tests are now invoked directly from node via 'npm run
  test'.
* Docs and release installer updated to match.
* Removed long-outdated inline installer readme.

Webpack is configured to create bundles from sets of JS files.  As it
stands, there are 2 sets: core.bundle.js and vendor.bundle.js.  Core has
all of the EG core services that are loaded on every page.  Vendor
contains all of the 3rd-party dependencies (angular, etc.).  These 2
bundles are loaded on every web staff page (via base_js.tt2).

All other <script/> tags remain as they were.

When building in dev mode ('npm run build'), core service JS files are
bunded un-minified with an inline source map for debugging.  Vendor
files (angularjs, etc.) are always minified because they are quite
large.

Signed-off-by: Bill Erickson <berickxx@gmail.com>
Signed-off-by: Jason Stephenson <jason@sigio.com>
Signed-off-by: Galen Charlton <gmc@equinoxinitiative.org>

Open-ILS/src/templates/staff/base_js.tt2
Open-ILS/src/templates/staff/index.tt2
Open-ILS/web/js/ui/default/staff/Gruntfile.js [deleted file]
Open-ILS/web/js/ui/default/staff/README.install [deleted file]
Open-ILS/web/js/ui/default/staff/package.json
Open-ILS/web/js/ui/default/staff/test/karma.conf.js
Open-ILS/web/js/ui/default/staff/webpack.config.js [new file with mode: 0644]
build/tools/make_release
docs/installation/server_installation.adoc

index 2932e45..7b3d07f 100644 (file)
@@ -34,47 +34,13 @@ UpUp.start({
     '[% ctx.media_prefix %]/js/ui/default/staff/build/js/moment-with-locales.min.js',
     '[% ctx.media_prefix %]/js/ui/default/staff/build/js/moment-timezone-with-data.min.js',
     '[% ctx.media_prefix %]/js/ui/default/common/build/js/jquery.min.js',
-    '[% ctx.media_prefix %]/js/ui/default/staff/build/js/angular.min.js',
-    '[% ctx.media_prefix %]/js/ui/default/staff/build/js/angular-route.min.js',
-    '[% ctx.media_prefix %]/js/ui/default/staff/build/js/ui-bootstrap-tpls.min.js',
-    '[% ctx.media_prefix %]/js/ui/default/staff/build/js/hotkeys.min.js',
-    '[% ctx.media_prefix %]/js/ui/default/staff/build/js/angular-file-saver.bundle.min.js',
-    '[% ctx.media_prefix %]/js/ui/default/staff/build/js/angular-location-update.min.js',
-    '[% ctx.media_prefix %]/js/ui/default/staff/build/js/angular-animate.min.js',
-    '[% ctx.media_prefix %]/js/ui/default/staff/build/js/angular-sanitize.min.js',
-    '[% ctx.media_prefix %]/js/ui/default/staff/build/js/angular-cookies.min.js',
-    '[% ctx.media_prefix %]/js/ui/default/staff/build/js/ngToast.min.js',
-    '[% ctx.media_prefix %]/js/ui/default/staff/build/js/angular-tree-control.js',
-    '[% ctx.media_prefix %]/js/ui/default/staff/build/js/iframeResizer.min.js',
-    '[% ctx.media_prefix %]/js/ui/default/staff/build/js/ng-order-object-by.js',
-    '[% ctx.media_prefix %]/js/ui/default/staff/build/js/angular-tablesort.js',
-    '[% ctx.media_prefix %]/js/ui/default/staff/build/js/lovefield.min.js',
+    '[% ctx.media_prefix %]/js/ui/default/staff/build/js/vendor.bundle.js',
     '[% ctx.media_prefix %]/js/ui/default/staff/build/fonts/glyphicons-halflings-regular.woff',
     '[% ctx.media_prefix %]/js/ui/default/staff/build/fonts/glyphicons-halflings-regular.woff2',
     '[% ctx.media_prefix %]/js/dojo/opensrf/JSON_v1.js',
     '[% ctx.media_prefix %]/js/dojo/opensrf/opensrf.js',
     '[% ctx.media_prefix %]/js/dojo/opensrf/opensrf_ws.js',
-    '[% ctx.media_prefix %]/js/ui/default/staff/services/core.js',
-    '[% ctx.media_prefix %]/js/ui/default/staff/services/strings.js',
-    '[% ctx.media_prefix %]/js/ui/default/staff/services/idl.js',
-    '[% ctx.media_prefix %]/js/ui/default/staff/services/event.js',
-    '[% ctx.media_prefix %]/js/ui/default/staff/services/net.js',
-    '[% ctx.media_prefix %]/js/ui/default/staff/services/auth.js',
-    '[% ctx.media_prefix %]/js/ui/default/staff/services/pcrud.js',
-    '[% ctx.media_prefix %]/js/ui/default/staff/services/env.js',
-    '[% ctx.media_prefix %]/js/ui/default/staff/services/org.js',
-    '[% ctx.media_prefix %]/js/ui/default/staff/services/startup.js',
-    '[% ctx.media_prefix %]/js/ui/default/staff/services/hatch.js',
-    '[% ctx.media_prefix %]/js/ui/default/staff/services/print.js',
-    '[% ctx.media_prefix %]/js/ui/default/staff/services/audio.js',
-    '[% ctx.media_prefix %]/js/ui/default/staff/services/coresvc.js',
-    '[% ctx.media_prefix %]/js/ui/default/staff/services/user.js',
-    '[% ctx.media_prefix %]/js/ui/default/staff/services/navbar.js',
-    '[% ctx.media_prefix %]/js/ui/default/staff/services/ui.js',
-    '[% ctx.media_prefix %]/js/ui/default/staff/services/i18n.js',
-    '[% ctx.media_prefix %]/js/ui/default/staff/services/date.js',
-    '[% ctx.media_prefix %]/js/ui/default/staff/services/op_change.js',
-    '[% ctx.media_prefix %]/js/ui/default/staff/services/lovefield.js',
+    '[% ctx.media_prefix %]/js/ui/default/staff/build/js/core.bundle.js',
     '[% ctx.media_prefix %]/js/ui/default/staff/services/file.js',
     '[% ctx.media_prefix %]/js/ui/default/staff/offline.js',
     '[% ctx.base_path %]/staff/share/t_alert_dialog',
@@ -93,61 +59,24 @@ UpUp.start({
 <script src="/IDL2js"></script>
 <script src="[% ctx.media_prefix %]/js/dojo/opensrf/md5.js"></script>
 
-[% IF EXPAND_WEB_IMPORTS %]
-
-<!-- angular -->
-<script src="[% ctx.media_prefix %]/js/ui/default/common/build/js/jquery.min.js"></script>
-<script src="[% ctx.media_prefix %]/js/ui/default/staff/build/js/angular.min.js"></script>
-<script src="[% ctx.media_prefix %]/js/ui/default/staff/build/js/angular-route.min.js"></script>
-<script src="[% ctx.media_prefix %]/js/ui/default/staff/build/js/ui-bootstrap-tpls.min.js"></script>
-<script src="[% ctx.media_prefix %]/js/ui/default/staff/build/js/hotkeys.min.js"></script>
-<script src="[% ctx.media_prefix %]/js/ui/default/staff/build/js/angular-file-saver.bundle.min.js"></script>
-<script src="[% ctx.media_prefix %]/js/ui/default/staff/build/js/angular-location-update.min.js"></script>
-<script src="[% ctx.media_prefix %]/js/ui/default/staff/build/js/angular-animate.min.js"></script>
-<script src="[% ctx.media_prefix %]/js/ui/default/staff/build/js/angular-sanitize.min.js"></script>
-<script src="[% ctx.media_prefix %]/js/ui/default/staff/build/js/angular-cookies.min.js"></script>
-<script src="[% ctx.media_prefix %]/js/ui/default/staff/build/js/ngToast.min.js"></script>
-<script src="[% ctx.media_prefix %]/js/ui/default/staff/build/js/angular-tree-control.js"></script>
-<script src="[% ctx.media_prefix %]/js/ui/default/staff/build/js/iframeResizer.min.js"></script>
-<script src="[% ctx.media_prefix %]/js/ui/default/staff/build/js/ng-order-object-by.js"></script>
-<script src="[% ctx.media_prefix %]/js/ui/default/staff/build/js/lovefield.min.js"></script>
-<script src="[% ctx.media_prefix %]/js/ui/default/staff/build/js/moment-with-locales.min.js"></script>
-<script src="[% ctx.media_prefix %]/js/ui/default/staff/build/js/moment-timezone-with-data.min.js"></script>
-
 <!-- IDL / opensrf (network) -->
 <script src="[% ctx.media_prefix %]/js/dojo/opensrf/JSON_v1.js"></script>
 <script src="[% ctx.media_prefix %]/js/dojo/opensrf/opensrf.js"></script>
 <script src="[% ctx.media_prefix %]/js/dojo/opensrf/opensrf_ws.js"></script>
 
-<!-- evergreen core services -->
-<script src="[% ctx.media_prefix %]/js/ui/default/staff/services/core.js"></script>
-<script src="[% ctx.media_prefix %]/js/ui/default/staff/services/strings.js"></script>
-<script src="[% ctx.media_prefix %]/js/ui/default/staff/services/idl.js"></script>
-<script src="[% ctx.media_prefix %]/js/ui/default/staff/services/event.js"></script>
-<script src="[% ctx.media_prefix %]/js/ui/default/staff/services/net.js"></script>
-<script src="[% ctx.media_prefix %]/js/ui/default/staff/services/auth.js"></script>
-<script src="[% ctx.media_prefix %]/js/ui/default/staff/services/pcrud.js"></script>
-<script src="[% ctx.media_prefix %]/js/ui/default/staff/services/env.js"></script>
-<script src="[% ctx.media_prefix %]/js/ui/default/staff/services/org.js"></script>
-<script src="[% ctx.media_prefix %]/js/ui/default/staff/services/startup.js"></script>
-<script src="[% ctx.media_prefix %]/js/ui/default/staff/services/hatch.js"></script>
-<script src="[% ctx.media_prefix %]/js/ui/default/staff/services/print.js"></script>
-<script src="[% ctx.media_prefix %]/js/ui/default/staff/services/audio.js"></script>
-<script src="[% ctx.media_prefix %]/js/ui/default/staff/services/coresvc.js"></script>
-<script src="[% ctx.media_prefix %]/js/ui/default/staff/services/user.js"></script>
-<script src="[% ctx.media_prefix %]/js/ui/default/staff/services/navbar.js"></script>
-<script src="[% ctx.media_prefix %]/js/ui/default/staff/services/ui.js"></script>
-<script src="[% ctx.media_prefix %]/js/ui/default/staff/services/i18n.js"></script>
-<script src="[% ctx.media_prefix %]/js/ui/default/staff/services/date.js"></script>
-<script src="[% ctx.media_prefix %]/js/ui/default/staff/services/op_change.js"></script>
-<script src="[% ctx.media_prefix %]/js/ui/default/staff/services/lovefield.js"></script>
-
-[% ELSE %]
+<!-- angular -->
+<script src="[% ctx.media_prefix %]/js/ui/default/common/build/js/jquery.min.js"></script>
+<script src="[% ctx.media_prefix %]/js/ui/default/staff/build/js/vendor.bundle.js"></script>
 
-<!-- concatenated, minified version of all of the above -->
-<script src="[% ctx.media_prefix %]/js/ui/default/staff/build/js/evergreen-staff-client.[% EVERGREEN_VERSION %].min.js"></script>
+<!-- 
+  Load momentjs via script tag.
+  https://github.com/webpack/webpack/issues/3128 
+-->
+<script src="[% ctx.media_prefix %]/js/ui/default/staff/build/js/moment-with-locales.min.js"></script>
+<script src="[% ctx.media_prefix %]/js/ui/default/staff/build/js/moment-timezone-with-data.min.js"></script>
 
-[% END %]
+<!-- evergreen core services -->
+<script src="[% ctx.media_prefix %]/js/ui/default/staff/build/js/core.bundle.js"></script>
 
 <script>
   // Configure OpenSRF
index cd65d7a..803774f 100644 (file)
@@ -6,7 +6,6 @@
 
 [% BLOCK APP_JS %]
 <!-- splash / login page app -->
-<script src="[% ctx.media_prefix %]/js/ui/default/staff/services/lovefield.js"></script>
 <script src="[% ctx.media_prefix %]/js/ui/default/staff/app.js"></script>
 [% END %]
 
diff --git a/Open-ILS/web/js/ui/default/staff/Gruntfile.js b/Open-ILS/web/js/ui/default/staff/Gruntfile.js
deleted file mode 100644 (file)
index b6f8e4b..0000000
+++ /dev/null
@@ -1,250 +0,0 @@
-module.exports = function(grunt) {
-
-  // Project configuration.
-  var config = { 
-    pkg: grunt.file.readJSON('package.json'),
-
-    // copy the files we care about from fetched dependencies
-    // into our build directory
-    copy: {
-
-      js : {
-        files: [{ 
-          dest: 'build/js/', 
-          flatten: true,
-          filter: 'isFile',
-          expand : true,
-          src: [
-            'node_modules/angular/angular.min.js',
-            'node_modules/angular/angular.min.js.map',
-            'node_modules/angular-animate/angular-animate.min.js',
-            'node_modules/angular-animate/angular-animate.min.js.map',
-            'node_modules/angular-sanitize/angular-sanitize.min.js',
-            'node_modules/angular-sanitize/angular-sanitize.min.js.map',
-            'node_modules/angular-route/angular-route.min.js',
-            'node_modules/angular-route/angular-route.min.js.map',
-            'node_modules/angular-ui-bootstrap/dist/ui-bootstrap.js',
-            'node_modules/angular-ui-bootstrap/dist/ui-bootstrap-tpls.js',
-            'node_modules/angular-hotkeys/build/hotkeys.min.js',
-            'node_modules/angular-file-saver/dist/angular-file-saver.bundle.min.js',
-            'node_modules/angular-location-update/angular-location-update.min.js',
-            'node_modules/angular-tree-control/angular-tree-control.js',
-            'node_modules/ng-toast/dist/ngToast.min.js',
-            'node_modules/angular-cookies/angular-cookies.min.js',
-            'node_modules/angular-cookies/angular-cookies.min.js.map',
-            'node_modules/iframe-resizer/js/iframeResizer.min.js',
-            'node_modules/iframe-resizer/js/iframeResizer.map',
-            'node_modules/iframe-resizer/js/iframeResizer.contentWindow.min.js',
-            'node_modules/angular-order-object-by/src/ng-order-object-by.js',
-            'node_modules/angular-tablesort/js/angular-tablesort.js',
-            'node_modules/lovefield/dist/lovefield.min.js',
-            'node_modules/lovefield/dist/lovefield.min.js.map',
-            'node_modules/moment/min/moment-with-locales.min.js',
-            'node_modules/moment-timezone/builds/moment-timezone-with-data.min.js'
-          ]
-        },
-        {
-          dest: '../common/build/js/', 
-          flatten: true,
-          filter: 'isFile',
-          expand : true,
-          src: [
-            'node_modules/jquery/dist/jquery.min.js'
-          ]
-        }]
-      },
-
-      css : {
-        files : [{
-          dest : 'build/css/',
-          flatten : true,
-          filter : 'isFile',
-          expand : true,
-          src : [
-            'node_modules/angular-hotkeys/build/hotkeys.min.css',
-            'node_modules/bootstrap/dist/css/bootstrap.min.css', 
-            'node_modules/ng-toast/dist/ngToast.min.css',
-            'node_modules/ng-toast/dist/ngToast-animations.min.css',
-            'node_modules/angular-tree-control/css/tree-control.css',
-            'node_modules/angular-tree-control/css/tree-control-attribute.css',
-            'node_modules/angular-tablesort/tablesort.css'
-          ]
-        }]
-      },
-
-      fonts : {
-        files : [{
-          dest : 'build/fonts/',
-          flatten : true,
-          filter : 'isFile',
-          expand : true,
-          src : [
-            'node_modules/bootstrap/dist/fonts/glyphicons-halflings-regular.eot',
-            'node_modules/bootstrap/dist/fonts/glyphicons-halflings-regular.svg',
-            'node_modules/bootstrap/dist/fonts/glyphicons-halflings-regular.ttf',
-            'node_modules/bootstrap/dist/fonts/glyphicons-halflings-regular.woff',
-            'node_modules/bootstrap/dist/fonts/glyphicons-halflings-regular.woff2'
-          ]
-        }]
-      },
-
-      images : {
-        files : [{
-          dest : 'build/images/',
-          flatten : true,
-          filter : 'isFile',
-          expand : true,
-          src : [
-            'node_modules/angular-tree-control/images/sample.png',
-            'node_modules/angular-tree-control/images/node-opened-2.png',
-            'node_modules/angular-tree-control/images/folder.png',
-            'node_modules/angular-tree-control/images/node-closed.png',
-            'node_modules/angular-tree-control/images/node-closed-light.png',
-            'node_modules/angular-tree-control/images/node-opened.png',
-            'node_modules/angular-tree-control/images/node-opened-light.png',
-            'node_modules/angular-tree-control/images/folder-closed.png',
-            'node_modules/angular-tree-control/images/node-closed-2.png',
-            'node_modules/angular-tree-control/images/file.png'
-          ]
-        }]
-      }
-    },
-
-    // combine our CSS deps
-    // note: minification also supported, but not required (yet).
-    cssmin: {
-      combine: {
-        files: {
-          'build/css/evergreen-staff-client-deps.<%= pkg.version %>.min.css' : [
-            'build/css/hotkeys.min.css',
-            'build/css/bootstrap.min.css',
-            'build/css/ngToast.min.css',
-            'build/css/ngToast-animations.min.css',
-            'build/css/tree-control.css',
-            'build/css/tree-control-attribute.css'
-          ]
-        }
-      }
-    },
-
-    // concatenation + minification
-    uglify: {
-      options: {
-        banner: '/*! <%= pkg.name %> <%= grunt.template.today("yyyy-mm-dd") %> */\n'
-      },
-      dev: {
-        files: [{
-          expand: true,
-          src: ['build/js/ui-bootstrap.js', 'build/js/ui-bootstrap-tpls.js'],
-          dest: 'build/js',
-          cwd: '.',
-          rename: function (dst, src) {
-            return src.replace('.js', '.min.js');
-          }
-        }]
-      },
-      build: {
-        src: [
-            // These are concatenated in order in the final build file.
-            // The order is important.
-            '../common/build/js/jquery.min.js',
-            'build/js/angular.min.js',
-            'build/js/angular-animate.min.js',
-            'build/js/angular-sanitize.min.js',
-            'build/js/angular-route.min.js',
-            'build/js/ui-bootstrap.min.js',
-            'build/js/ui-bootstrap-tpls.js',
-            'build/js/hotkeys.min.js',
-            'build/js/angular-tree-control.js',
-            'build/js/ngToast.min.js',
-            'build/js/lovefield.min.js',
-            'bulid/js/moment-with-locales.min.js',
-            'build/js/moment-timezone-with-data.min.js',
-            // NOTE: OpenSRF must be installed
-            // XXX: Should not be hard-coded
-            '/openils/lib/javascript/JSON_v1.js',
-            '/openils/lib/javascript/opensrf.js',
-            '/openils/lib/javascript/opensrf_ws.js',
-            'services/core.js',
-            'services/strings.js',
-            'services/idl.js',
-            'services/event.js',
-            'services/net.js',
-            'services/auth.js',
-            'services/pcrud.js',
-            'services/env.js',
-            'services/org.js',
-            'services/startup.js',
-            'services/hatch.js',
-            'services/print.js',
-            'services/audio.js',
-            'services/coresvc.js',
-            'services/navbar.js',
-            'services/ui.js',
-            'services/date.js',
-            'services/op_change.js',
-            'services/file.js',
-            'services/i18n.js'
-        ],
-        dest: 'build/js/<%= pkg.name %>.<%= pkg.version %>.min.js'
-      },
-    },
-
-    // bare concat operation; useful for testing concat w/o minification
-    // to more easily detect if concat order is incorrect
-    concat: {
-      options: {
-       separator: ';'
-      }
-    },
-
-    exec : {
-
-      // Generate test/data/IDL2js.js for unit tests.
-      // note: the output of this script is *not* part of the final build.
-      idl2js : {
-        cwd: 'test/data',
-        command : 'perl idl2js.pl'
-      },
-
-      // Remove the unit test IDL2js.js file.  We don't need it after testing
-      rmidl2js : {
-        command : 'rm test/data/IDL2js.js'
-      }
-    },
-
-    // unit tests configuration
-    karma : {
-      unit: {
-        configFile: 'test/karma.conf.js'
-        //background: true  // for now, visually babysit unit tests
-      }
-    }
-  };
-
-  // tell concat about our uglify build options (instead of repeating them)
-  config.concat.build = config.uglify.build;
-
-  // apply our configuration
-  grunt.initConfig(config);
-
-  // Load our modules
-  grunt.loadNpmTasks('grunt-contrib-uglify');
-  grunt.loadNpmTasks('grunt-contrib-concat');
-  grunt.loadNpmTasks('grunt-contrib-copy');
-  grunt.loadNpmTasks('grunt-contrib-cssmin');
-  grunt.loadNpmTasks('grunt-karma');
-  grunt.loadNpmTasks('grunt-exec');
-
-  // note: "grunt concat" is not required 
-  grunt.registerTask('build', ['copy', 'cssmin', 'uglify']);
-
-  // test only, no minification
-  grunt.registerTask('test', ['copy', 'exec:idl2js', 'karma:unit', 'exec:rmidl2js']);
-
-  // note: "grunt concat" is not requried 
-  grunt.registerTask('all', ['test', 'cssmin', 'uglify']);
-
-};
-
-// vim: ts=2:sw=2:softtabstop=2
diff --git a/Open-ILS/web/js/ui/default/staff/README.install b/Open-ILS/web/js/ui/default/staff/README.install
deleted file mode 100644 (file)
index ba0a912..0000000
+++ /dev/null
@@ -1,113 +0,0 @@
-= Building, Testing, Packaging the Browser Client =
-:Author:    Bill Erickson
-:Email:     berick@esilibrary.com
-:Date:      2014-05-07
-
-== Prerequisites ==
-
- * http://bower.io/[Bower] 
-  ** Dependency retrieval
- * http://jasmine.github.io/[Jasmine] 
-  ** Headless unit tests runner
- * http://gruntjs.com/[Grunt]
-  ** Coordinating the build
-  ** Concatenation + minification of JS and CSS
-
-These are all Node.js plugins, so start by installing Node.js
-
-=== Install Node.js ===
-
-Node.js does not have have Debian Wheezy build target.  For now, I've opted
-to install from source.  For more, see also 
-https://github.com/joyent/node/wiki/installation[Node.js Installation]
-
-[source,sh]
-------------------------------------------------------------------------------
-% git clone https://github.com/joyent/node.git
-% cd node
-% git checkout -b v0.10.28 v0.10.28
-
-# set -j to number of CPU cores + 1
-% ./configure && make -j5 && sudo make install
-
-# update packages
-% sudo npm update
-------------------------------------------------------------------------------
-
-=== Install Grunt CLI ===
-
-[source,sh]
-------------------------------------------------------------------------------
-% sudo npm install -g grunt-cli
-------------------------------------------------------------------------------
-
-=== Install Bower ===
-
-[source,sh]
-------------------------------------------------------------------------------
-% sudo npm install -g bower
-------------------------------------------------------------------------------
-
-== Building, Testing, Minification == 
-
-The remaining steps all take place within the staff JS web root:
-
-[source,sh]
-------------------------------------------------------------------------------
-% cd $EVERGREEN_ROOT/Open-ILS/web/js/ui/default/staff/
-------------------------------------------------------------------------------
-
-=== Install Project-local Dependencies ===
-
-npm inspects the 'package.json' file for dependencies and fetches them
-from the Node package network.
-
-[source,sh]
-------------------------------------------------------------------------------
-% npm install   # fetch Grunt dependencies
-% bower install # fetch JS dependencies
-------------------------------------------------------------------------------
-
-=== Running the Build Scripts ===
-
-[source,sh]
-------------------------------------------------------------------------------
-
-# build, run tests
-% grunt test
-
-# build, concat+minify
-% grunt uglify
-
-# build, run tests, concat+minify 
-% grunt all
-------------------------------------------------------------------------------
-
-== Updating Dependencies
-
- * Remove the contents of the "dependencies" {} in bowser.json
- * rm -r bower_components
- * Re-install all dependencies:
-
-[source,sh]
-------------------------------------------------------------------------------
-bower install --save angular-latest
-bower install --save jquery
-bower install --save bootstrap
-bower install --save angular-route
-bower install --save angular-mocks
-bower install --save angular-bootstrap
-bower install --save angular-hotkeys
-bower install --save angular-file-saver
-bower install --save angular-location-update
-# ... others as needed
-------------------------------------------------------------------------------
-
-== TODO ==
-
- * Minification of app-specific JS files
- * Integrate this into the Evergreen Makefile test and install targets
-   ** Avoid installing test, node_modules, etc. into the web dir.
- * Support fetching JS deps (angularjs, etc.) via direct retrieval for 
-   installation without test + concat + minify (i.e. w/o requiring Node.js)?
-
index 26a48a1..1d3e5a0 100644 (file)
@@ -6,25 +6,25 @@
   "homepage": "https://evergreen-ils.org/",
   "devDependencies": {
     "angular-mocks": "^1.6.7",
-    "grunt": "^1.0.1",
-    "grunt-cli": "^1.2.0",
-    "grunt-contrib-concat": "^1.0.1",
-    "grunt-contrib-copy": "^1.0.0",
-    "grunt-contrib-cssmin": "^2.2.1",
-    "grunt-contrib-jasmine": "^1.1.0",
-    "grunt-contrib-uglify": "^3.2.1",
-    "grunt-exec": "^3.0.0",
-    "grunt-karma": "^2.0.0",
+    "clean-webpack-plugin": "^0.1.17",
+    "copy-webpack-plugin": "^4.3.0",
     "karma": "^1.7.1",
     "karma-jasmine": "^1.1.1",
     "karma-phantomjs-launcher": "^1.0.4",
     "karma-script-launcher": "^1.0.0",
     "karma-spec-reporter": "0.0.32",
     "karma-story-reporter": "^0.3.1",
-    "phantomjs-prebuilt": "^2.1.16"
+    "phantomjs-prebuilt": "^2.1.16",
+    "webpack": "^3.10.0",
+    "webpack-merge": "^4.1.1"
   },
   "scripts": {
-    "test": "grunt test"
+    "create-mock-idl": "cd test/data && perl idl2js.pl",
+    "remove-mock-idl": "rm test/data/IDL2js.js",
+    "test": "npm run create-mock-idl ; karma start test/karma.conf --single-run; npm run remove-mock-idl",
+    "build": "webpack --env.dev",
+    "build-watch": "webpack --env.dev --watch",
+    "build-prod": "webpack --env.prod"
   },
   "dependencies": {
     "angular": "^1.6.7",
index 12cc87e..531ac85 100644 (file)
@@ -6,17 +6,12 @@ module.exports = function(config){
     logLevel: config.LOG_INFO,
 
     files : [
-      '../common/build/js/jquery.min.js',
-      'build/js/lovefield.min.js',
-      'build/js/angular.min.js',
-      'build/js/angular-route.min.js',
+      'build/js/vendor.bundle.js',
+      'build/js/core.bundle.js',
       'node_modules/angular-mocks/angular-mocks.js', // testing only
       'node_modules/angular-file-saver/dist/angular-file-saver.bundle.min.js',
       'node_modules/ng-toast/dist/ngToast.min.js',
       'node_modules/angular-sanitize/angular-sanitize.min.js',
-      'build/js/ui-bootstrap.js',
-      'build/js/hotkeys.min.js',
-      'build/js/angular-cookies.min.js',
       /* OpenSRF must be installed first */
       '/openils/lib/javascript/md5.js',
       '/openils/lib/javascript/JSON_v1.js',
@@ -28,29 +23,10 @@ module.exports = function(config){
       'test/data/eg_mock.js',
 
       // service/*.js have to be loaded in order
-      'services/core.js',
-      'services/idl.js',
-      'services/strings.js',
-      'services/event.js',
-      'services/net.js',
-      'services/auth.js',
-      'services/pcrud.js',
-      'services/env.js',
-      'services/org.js',
-      'services/hatch.js',
-      'services/print.js',
-      'services/audio.js',
-      'services/coresvc.js',
-      'services/user.js',
-      'services/startup.js',
-      'services/ui.js',
       'services/grid.js',
-      'services/op_change.js',
       'services/patron_search.js',
-      'services/lovefield.js',
-      'services/navbar.js', 'services/date.js',
       'services/user-bucket.js',
-      'services/i18n.js',
+
       // load app scripts
       'app.js',
       'circ/**/*.js',
diff --git a/Open-ILS/web/js/ui/default/staff/webpack.config.js b/Open-ILS/web/js/ui/default/staff/webpack.config.js
new file mode 100644 (file)
index 0000000..1be4c7b
--- /dev/null
@@ -0,0 +1,158 @@
+const path = require('path');
+const merge = require('webpack-merge');
+const webpack = require('webpack');
+const CleanWebpackPlugin = require('clean-webpack-plugin');
+const UglifyJSPlugin = require('uglifyjs-webpack-plugin');
+const CopyWebpackPlugin = require('copy-webpack-plugin');
+
+const buildPath = 'build';
+
+const CSS_FILES = [
+  'node_modules/angular-hotkeys/build/hotkeys.min.css',
+  'node_modules/bootstrap/dist/css/bootstrap.min.css',
+  'node_modules/ng-toast/dist/ngToast.min.css',
+  'node_modules/ng-toast/dist/ngToast-animations.min.css',
+  'node_modules/angular-tree-control/css/tree-control.css',
+  'node_modules/angular-tree-control/css/tree-control-attribute.css',
+  'node_modules/angular-tablesort/tablesort.css'
+];
+
+const FONT_FILES = [
+  'node_modules/bootstrap/dist/fonts/glyphicons-halflings-regular.eot',
+  'node_modules/bootstrap/dist/fonts/glyphicons-halflings-regular.svg',
+  'node_modules/bootstrap/dist/fonts/glyphicons-halflings-regular.ttf',
+  'node_modules/bootstrap/dist/fonts/glyphicons-halflings-regular.woff',
+  'node_modules/bootstrap/dist/fonts/glyphicons-halflings-regular.woff2'
+];
+
+const IMAGE_FILES = [
+  'node_modules/angular-tree-control/images/sample.png',
+  'node_modules/angular-tree-control/images/node-opened-2.png',
+  'node_modules/angular-tree-control/images/folder.png',
+  'node_modules/angular-tree-control/images/node-closed.png',
+  'node_modules/angular-tree-control/images/node-closed-light.png',
+  'node_modules/angular-tree-control/images/node-opened.png',
+  'node_modules/angular-tree-control/images/node-opened-light.png',
+  'node_modules/angular-tree-control/images/folder-closed.png',
+  'node_modules/angular-tree-control/images/node-closed-2.png',
+  'node_modules/angular-tree-control/images/file.png'
+]
+
+// Some common JS files are left un-bundled.
+// https://github.com/webpack/webpack/issues/3128
+const JS_FILES = [
+  './node_modules/moment/min/moment-with-locales.min.js',
+  './node_modules/moment-timezone/builds/moment-timezone-with-data.min.js'
+]
+
+
+// Copy files as-is from => to.
+const directCopyFiles = [
+
+  // jquery is copied to the common build location, up one directory.
+  {from: './node_modules/jquery/dist/jquery.min.js', 
+     to: __dirname + '/../common/build/js'}
+];
+
+CSS_FILES.forEach(file => directCopyFiles.push({from: file, to: './css'}));
+FONT_FILES.forEach(file => directCopyFiles.push({from: file, to: './fonts'}));
+IMAGE_FILES.forEach(file => directCopyFiles.push({from: file, to: './images'}));
+JS_FILES.forEach(file => directCopyFiles.push({from: file, to: './js'}));
+
+// EG JS files loaded on every page
+const coreJsFiles = [
+  './services/core.js',
+  './services/strings.js',
+  './services/idl.js',
+  './services/event.js',
+  './services/net.js',
+  './services/auth.js',
+  './services/pcrud.js',
+  './services/env.js',
+  './services/org.js',
+  './services/startup.js',
+  './services/hatch.js',
+  './services/print.js',
+  './services/audio.js',
+  './services/coresvc.js',
+  './services/user.js',
+  './services/navbar.js',
+  './services/ui.js',
+  './services/i18n.js',
+  './services/date.js',
+  './services/op_change.js',
+  './services/lovefield.js'
+];
+
+// 3rd-party (AKA vendor) JS files loaded on every page.
+// Webpack knows to look in ./node_modules/
+const vendorJsFiles = [
+  'angular',
+  'angular-route',
+  'angular-ui-bootstrap',
+  'angular-hotkeys',
+  'angular-file-saver',
+  'angular-location-update',
+  'angular-animate',
+  'angular-sanitize',
+  'angular-cookies',
+  'ng-toast',
+  'angular-tree-control',
+  'iframe-resizer',
+  'angular-order-object-by',
+  'lovefield'
+];
+
+
+let commmonOptions = {
+  // As of today, we are only bundling common files.  Individual app.js
+  // and optional service files are still imported via script tags.
+  entry: {
+    core: coreJsFiles,
+    vendor: vendorJsFiles
+  },
+  plugins: [
+    new CleanWebpackPlugin([buildPath]),
+    new CopyWebpackPlugin(directCopyFiles, {copyUnmodified: true}),
+    new webpack.optimize.CommonsChunkPlugin({
+      names: ['core', 'vendor'], // ORDER MATTERS
+      minChunks: 2 // TODO: huh?
+    })
+  ],
+  output: {
+    filename: 'js/[name].bundle.js',
+    path: path.resolve(__dirname, buildPath)
+  }
+};
+
+// improve debugging during development with inline source maps
+// for bundled files.
+let devOptions = {
+  devtool: 'inline-source-map',
+  plugins: [
+    // Avoid minifiying the core bundle in development mode.
+    // TODO: Add other bundles as necessary, but leave the 'vendor'
+    // bundle out, since we always want to minify that (it's big).
+    new UglifyJSPlugin({
+      exclude: [/core/]
+    })
+  ],
+  watchOptions: {
+    aggregateTimeout: 300,
+    poll: 1000,
+    ignored : [
+        /node_modules/
+    ]
+  }
+};
+
+// minify for production
+let prodOptions = {
+  plugins: [
+    new UglifyJSPlugin()
+  ],
+};
+
+module.exports = env => env.prod ? 
+    merge(commmonOptions, prodOptions) : merge(commmonOptions, devOptions); 
+
index b870309..f82ff3d 100755 (executable)
@@ -83,7 +83,7 @@ while getopts ":hv:f:F:nptbrij:cx" opt; do
             echo "   -r prompt to preview upgrade SQL in editor before committing."
             echo "   -i skip i18n; primarily useful for (quickly) testing this script."
             echo "   -j opensrf javascript library path.  If osrf_config is found, the value derived from osrf_config --libdir."
-            echo "   -c build the experimental browser client;  requires nodejs/grunt-cli"
+            echo "   -c build the browser client;  requires nodejs"
             echo "   -x skip building the XUL client"
             echo "   NOTE: -t and -b override PREV_BRANCH/PREV_VERSION, but -b overrides -t."
             exit -1
@@ -336,7 +336,7 @@ if [ "$BUILD_BROWSER_CLIENT" == "YES" ]; then
     echo "Building browser staff client"
     cd Open-ILS/web/js/ui/default/staff/
     npm install   # fetch build dependencies
-    grunt build # copy to build dir and minify JS files
+    npm run build-prod # copy to build dir and minify JS files
     # npm cache is big and unnecessary in the final build. remove it.
     rm -r node_modules 
     cd ../../../../../../../ # release dir
index d651c88..20e0ccd 100644 (file)
@@ -152,13 +152,6 @@ steps in <<install_files_for_web_staff_client,Install files for web staff client
 1. Install the long-term stability (LTS) release of
 https://nodejs.org[Node.js]. Add the Node.js `/bin` directory to your
 environment variable `PATH`.
-+
-2. Install Grunt CLI
-+
-[source,sh]
-------------------------------------------------------------------------------
-% sudo npm install -g grunt-cli
-------------------------------------------------------------------------------
 
 [[install_files_for_web_staff_client]]
 Install files for web staff client
@@ -185,10 +178,10 @@ npm install   # fetch JS dependencies
 [source,sh]
 ------------------------------------------------------------------------------
 # build, run tests, concat+minify
-grunt all
+npm run build-prod
+npm run test
 ------------------------------------------------------------------------------
 
-
 Configuration and compilation instructions
 ------------------------------------------