Skip to content
Permalink
Browse files

Time for webpack (#1936)

* Remove usage of `with`

Per https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/with
"Use of the with statement is not recommended,
as it may be the source of confusing bugs and compatibility issues."

* Document the current JavaScript bundle size

Important before switching to Webpack as it shows us how this
changes when we adopt

* JS is now built via Webpack

Let's make our JavaScript easier to reason with and more
importantly make it testable so we can prevent future bugs.
Right now I am focusing on the OpenLibrary specific JavaScript,
not the vendor specific JS (this will come later)

Switching to Webpack shaves 5kb off our JavaScript! Yay!

Changes:
* Export functions in all the individual files
* Declare functions on window object inside index.js so we have
any easy reference to all the JS we expose
* Remove unused vars eslint comments now they are also used
* Remove eslint-disable-next-line no-extra-semi comments now we are
no longer blindly concatenating
* Update the script in static/js/all.jsh
* Versions are pinned so we get predictable outputted JavaScript

Fixes: #1489

* Define a browser support matrix and allow transpiling

We will use Wikipedia's browser support matrix as it is based
on traffic for Wikipedia. Given Wikipedia's traffic, I think we
can be confident this will also be suitable for OpenLibrary.

Add a transpiler to allow us to adopt ES6 syntax in the codebase.
The addition of the babel loader and browserslistrc ensures that the
code we ship to end users will always be suitable syntax for those
users. Note we must still be careful when adopting ES6/7/8 functions
as no polyfills are provided, so care must still be taken by frontend
developers working with this codebase. We can add protection via
eslint later if that becomes a problem.

A single variable is changed to a `const` which does not appear
in the built assets in static/build to demonstrate this is working.

note the minor bundlesize update (but remember we just shaved 5kb off!)

Fixes: #1180
  • Loading branch information...
jdlrobson authored and mekarpeles committed Mar 20, 2019
1 parent 17cd172 commit b7fefd63db2b73fdc66c902be6d5c5fb990fb0cd
@@ -0,0 +1,3 @@
{
"presets": [ "@babel/preset-env" ]
}
@@ -0,0 +1,18 @@
# This is based on Wikipedia/MediaWiki's browser support matrix
# Which is defined at https://www.mediawiki.org/wiki/Compatibility#Modern_(Grade_A)

# https//en.wikipedia.org/wiki/Google_Chrome_version_history
chrome 13

ie 11

# https//en.wikipedia.org/wiki/Firefox_version_history
firefox 4.0

safari 5.0

opera 15

ios 6.0

android 4.1
@@ -4,6 +4,10 @@
"browser": true,
"jquery": true
},
"parserOptions": {
"sourceType": "module",
"ecmaVersion": 6
},
"globals": {
},
"rules": {
@@ -37,7 +37,7 @@ css:
js:
mkdir -p $(BUILD)
bash static/js/vendor.jsh > $(BUILD)/vendor-v2.js
bash static/js/all.jsh > $(BUILD)/all.js
npm run build-assets:webpack

i18n:
$(PYTHON) ./scripts/i18n-messages compile
@@ -1,6 +1,5 @@
/* eslint-disable no-unused-vars */
// used in templates/account/email.html
function validateEmail() {
export function validateEmail() {
$("form.email").validate({
invalidHandler: function(form, validator) {
var errors = validator.numberOfInvalids();
@@ -30,11 +29,9 @@ function validateEmail() {
}
});
}
/* eslint-enable no-unused-vars */

/* eslint-disable no-unused-vars */
// used in templates/account/password.html
function validatePassword() {
export function validatePassword() {
$("form.password").validate({
invalidHandler: function(form, validator) {
var errors = validator.numberOfInvalids();
@@ -68,5 +65,3 @@ function validatePassword() {
}
});
}
/* eslint-enable no-unused-vars */

@@ -14,10 +14,7 @@
* - On cancel/close:
* - value of the select is set to "" to select "select xxx"
*/
// We are blindly concatenating JS. The ; protects us in case the concatenation
// goes wrong. This can be removed when we make use of a JS bundler e.g. webpack
// eslint-disable-next-line no-extra-semi
;(function($){
export default function($){
$.fn.add_new_field = function(_options) {
$(this).each(function() {
var options = _options || {href: "#" + this.id + "-popup"};
@@ -100,4 +97,4 @@
return this;
});
};
})(jQuery);
}
@@ -1,9 +1,6 @@
// jquery plugins to provide author and language autocompletes.

// We are blindly concatenating JS. The ; protects us in case the concatenation
// goes wrong. This can be removed when we make use of a JS bundler e.g. webpack
// eslint-disable-next-line no-extra-semi
;(function($) {
export default function($) {
/**
* Some extra options for when creating an autocomplete input field
* @typedef {Object} OpenLibraryAutocompleteOptions
@@ -120,4 +117,4 @@
update_visible();
});
};
})(jQuery);
}
@@ -1,11 +1,9 @@
/**
* Setup actions on document.ready for standard classNames.
*/

jQuery(function($) {
export default function($) {
// Flash messages are hidden by default so that CSS is not on the critical path.
$(".flash-messages").show();

// close-popup
$("a.close-popup").click(function() {
$.fn.colorbox.close();
@@ -44,4 +42,4 @@ jQuery(function($) {
$("button[name='_save']").submit(function() {
$(this).attr("disabled", true);
});
});
}
@@ -19,8 +19,7 @@
var getAvailabilityV2, updateBookAvailability, updateWorkAvailability;
/* eslint-enable no-unused-vars */

$(function(){

function init() {
var btnClassName = 'cta-btn';
// pages still relying on legacy client-side availability checking
var whitelist = {
@@ -263,4 +262,7 @@ $(function(){
/* eslint-enable no-unused-vars */
updateBookAvailability();
}
});
}

init();
export { getAvailabilityV2, updateBookAvailability, updateWorkAvailability };
@@ -1,6 +1,5 @@
// Make Borrow links act as if POSTing to Borrow page

jQuery(function() {
export default function() {
$('.borrow-link').on('click', function(event) {
event.preventDefault();
var $this = $(this);
@@ -16,4 +15,4 @@ jQuery(function() {
window.archive_analytics.ol_send_event_ping({'category': 'BorrowLink', 'action': 'bookreader'});
}
});
});
}
@@ -1,6 +1,5 @@
/* eslint-disable no-unused-vars */
// used in templates/covers/add.html
var Carousel = {
const Carousel = {
add: function(selector, a, b, c, d, e, f) {
a = a || 6;
b = b || 5;
@@ -62,4 +61,4 @@ var Carousel = {
});
}
};
/* eslint-enable no-unused-vars */
export default Carousel;
@@ -1,6 +1,5 @@
/* eslint-disable no-unused-vars */
// used in templates/lists/preview.html
function sprintf(s) {
export function sprintf(s) {
var args = arguments;
var i = 1;
return s.replace(/%[%s]/g, function(match) {
@@ -10,21 +9,15 @@ function sprintf(s) {
return args[i++];
});
}
/* eslint-enable no-unused-vars */

// dummy i18n functions

/* eslint-disable no-unused-vars */
// used in plugins/upstream/code.py
function ugettext(s) {
export function ugettext(s) {
return s;
}
var _ = ugettext;
/* eslint-enable no-unused-vars */

/* eslint-disable no-unused-vars */
// used in templates/borrow/read.html
function ungettext(s1, s2, n) {
export function ungettext(s1, s2, n) {
return n == 1? s1 : s2;
}
/* eslint-enable no-unused-vars */
@@ -0,0 +1,81 @@
import { validateEmail, validatePassword } from './account.js';
import autocompleteInit from './autocomplete';
import addNewFieldInit from './add_new_field';
import automaticInit from './automatic';
import { getAvailabilityV2,
updateBookAvailability, updateWorkAvailability } from './availability';
import bookReaderInit from './bookreader_direct';
import Carousel from './carousels';
import loadStyle from './loadStyle';
import { ungettext, ugettext, sprintf } from './i18n';
import { addFadeInFunctionsTojQuery } from './jquery.others';
import jQueryRepeat from './jquery.repeat';
import { ForLoop, enumerate, htmlquote, websafe, foreach, join, len, range } from './jsdef';
// Note this import will also load various jQuery plugins.
// (jQuery.ScrollTo, jquery.hoverIntent, jquery.dataTables, dataTableExt,
// highlight, removeHighlight, jTruncate, columnize)
import { plot_tooltip_graph, plot_minigraph } from './lazy';
import initAnalytics from './ol.analytics';
// Also pulls in jQuery.fn.exists
import init, { closePop, bookCovers,
isScrolledIntoView, Browser } from './ol.js';
import { commify } from './python';
import { Subject, urlencode, renderTag, slice } from './subjects';
import Template from './template.js';
// Add $.fn.toggleText, $.fn.focusNextInputField, $.fn.ol_confirm_dialog, $.fn.tap, $.log
import { closePopup, initShowPasswords, truncate, cond } from './utils';
import initValidate from './validate';

// Eventually we will export all these to a single global ol, but in the mean time
// we add them to the window object for backwards compatibility.
window.bookCovers = bookCovers;
window.closePop = closePop;
window.closePopup = closePopup;
window.commify = commify;
window.cond = cond;
window.enumerate = enumerate;
window.foreach = foreach;
window.getAvailabilityV2 = getAvailabilityV2;
window.isScrolledIntoView = isScrolledIntoView;
window.htmlquote = htmlquote;
window.len = len;
window.loadStyle = loadStyle;
window.plot_tooltip_graph = plot_tooltip_graph;
window.plot_minigraph = plot_minigraph;
window.range = range;
window.renderTag = renderTag;
window.slice = slice;
window.sprintf = sprintf;
window.truncate = truncate;
window.updateBookAvailability = updateBookAvailability;
window.updateWorkAvailability = updateWorkAvailability;
window.urlencode = urlencode;
window.validateEmail = validateEmail;
window.validatePassword = validatePassword;
window.websafe = websafe;
window._ = ugettext;
window._ungettext = ungettext;
window._uggettext = ugettext;

window.Browser = Browser;
window.Carousel = Carousel;
window.ForLoop = ForLoop;
window.Subject = Subject;
window.Template = Template;

// Extend existing prototypes
String.prototype.join = join;

// Initialise some things
$(function () {
initValidate($);
autocompleteInit($);
addNewFieldInit($);
automaticInit($);
bookReaderInit($);
addFadeInFunctionsTojQuery($);
jQueryRepeat($);
initAnalytics($);
init($);
initShowPasswords($);
});
@@ -1,6 +1,6 @@
// FIX IE FADE PROBLEMS
// COURTESY: Ben Novakovic http://blog.bmn.name/2008/03/jquery-fadeinfadeout-ie-cleartype-glitch/
(function($) {
function addFadeInFunctionsTojQuery($) {
$.fn.customFadeIn = function(speed, callback) {
$(this).fadeIn(speed, function() {
if(jQuery.browser.msie)
@@ -37,7 +37,8 @@
if (options.callback != undefined) options.callback();
});
};
})(jQuery);
}

// ADD FADE TOGGLE
// COURTESY: Karl Swedberg http://www.learningjquery.com/2006/09/slicker-show-and-hide
jQuery.fn.fadeToggle = function(speed, easing, callback) {
@@ -49,3 +50,5 @@ jQuery.fn.toggleText = function(a, b) {
jQuery(this).text(jQuery(this).text() == a ? b : a);
});
};

export { addFadeInFunctionsTojQuery };
@@ -3,7 +3,7 @@
*
* Used in addbook process.
*/
(function($){
export default function($){
// For v2 and v1 page support. Can be removed when no v1 support needed
var isOldJQuery = $('body').on === undefined;
$.fn.repeat = function(options) {
@@ -99,4 +99,4 @@
$(document).on("click", removeSelector, onRemove);
}
}
})(jQuery);
}
Oops, something went wrong.

0 comments on commit b7fefd6

Please sign in to comment.
You can’t perform that action at this time.