From 8c774bec276dd76792316709cb7e1215ad67d159 Mon Sep 17 00:00:00 2001 From: Leo McArdle Date: Mon, 21 Jun 2021 11:54:54 +0100 Subject: [PATCH] expose globals in webpack this should get our js working properly over time we can go through and remove these vars from the global scope, instead importing them only in the files they're needed, and take full advantage of what webpack has to offer --- kitsune/sumo/static/sumo/js/upload.js | 24 +++---- package-lock.json | 47 ++++++++++++++ package.json | 3 + webpack.config.js | 2 + webpack/entrypoints.js | 1 + webpack/eslintrc.js | 2 +- webpack/global-expose-rules.js | 92 +++++++++++++++++++++++++++ webpack/protocol-compat.js | 2 + 8 files changed, 160 insertions(+), 13 deletions(-) create mode 100644 webpack/global-expose-rules.js create mode 100644 webpack/protocol-compat.js diff --git a/kitsune/sumo/static/sumo/js/upload.js b/kitsune/sumo/static/sumo/js/upload.js index 98410880e..5fc0f4c11 100644 --- a/kitsune/sumo/static/sumo/js/upload.js +++ b/kitsune/sumo/static/sumo/js/upload.js @@ -1,3 +1,15 @@ +function dialogSet(inner, title) { + var kbox = new KBox($('

').text(inner), { + title: title, + destroy: true, + closeOnOutClick: true, + modal: true, + id: 'upload-dialog', + container: $('body') + }); + kbox.open(); +} + $(document).ready(function () { var UPLOAD = { max_filename_length: 80, // max filename length in characters @@ -6,18 +18,6 @@ $(document).ready(function () { error_login: gettext('Please check you are logged in, and try again.') }; - function dialogSet(inner, title) { - var kbox = new KBox($('

').text(inner), { - title: title, - destroy: true, - closeOnOutClick: true, - modal: true, - id: 'upload-dialog', - container: $('body') - }); - kbox.open(); - } - $('input.delete', 'div.attachments-list').each(function () { var $form = $(this).closest('form'); $(this).wrapDeleteInput({ diff --git a/package-lock.json b/package-lock.json index 20329c238..18ca23630 100644 --- a/package-lock.json +++ b/package-lock.json @@ -6776,6 +6776,29 @@ "fill-range": "^2.1.0" } }, + "exports-loader": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/exports-loader/-/exports-loader-3.0.0.tgz", + "integrity": "sha512-b23Yg5SKR63ZvikGrQgfGgwd40MDehaYb7vOXgD7C0fMV04wS8U1I4f7n1j1wEhtQNKUqgdFox/ol2rOruOpOA==", + "dev": true, + "requires": { + "source-map": "^0.6.1" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + } + } + }, + "expose-loader": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/expose-loader/-/expose-loader-3.0.0.tgz", + "integrity": "sha512-X7ncrzmiQbJHOyLwuymECHk4NYvoPFwnsINMYFaRrm4fxuxR59hV1v65bho3TpIoWieP8WZmhz6micKny8orWg==", + "dev": true + }, "ext": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/ext/-/ext-1.4.0.tgz", @@ -8304,6 +8327,24 @@ } } }, + "imports-loader": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/imports-loader/-/imports-loader-3.0.0.tgz", + "integrity": "sha512-PhDB+rxpc95/1cM8ehxWAcuDIDi3eXhqHhax09iyUeAYBJ2bT6QbBp7aDj8IfU9Ns+2l1K226GhoWVAU823CTA==", + "dev": true, + "requires": { + "source-map": "^0.6.1", + "strip-comments": "^2.0.1" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + } + } + }, "imurmurhash": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", @@ -15552,6 +15593,12 @@ "is-utf8": "^0.2.0" } }, + "strip-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-comments/-/strip-comments-2.0.1.tgz", + "integrity": "sha512-ZprKx+bBLXv067WTCALv8SSz5l2+XhpYCsVtSqlMnkAXMWDq+/ekVbl1ghqP9rUHTzv6sm/DwCOiYutU/yp1fw==", + "dev": true + }, "strip-eof": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", diff --git a/package.json b/package.json index 8c8742675..a1fc036ad 100644 --- a/package.json +++ b/package.json @@ -74,6 +74,9 @@ "cssnano": "^4.1.10", "eslint": "1.10.3", "html-webpack-plugin": "^5.3.2", + "exports-loader": "^3.0.0", + "expose-loader": "^3.0.0", + "imports-loader": "^3.0.0", "kss": "^3.0.0-beta.25", "mocha": "2.3.2", "mocha-jsdom": "^2.0.0", diff --git a/webpack.config.js b/webpack.config.js index 868845be0..b6a508350 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -2,6 +2,7 @@ const path = require("path"); const entrypoints = require("./webpack/entrypoints"); const entrypointsHtml = require("./webpack/entrypoints-html"); +const globalExposeRules = require("./webpack/global-expose-rules"); module.exports = (env, argv) => { const config = { @@ -25,6 +26,7 @@ module.exports = (env, argv) => { loader: "babel-loader", }, }, + ...globalExposeRules, ], }, entry: entrypoints, diff --git a/webpack/entrypoints.js b/webpack/entrypoints.js index 1dd26b967..b7c955f63 100644 --- a/webpack/entrypoints.js +++ b/webpack/entrypoints.js @@ -25,6 +25,7 @@ module.exports = { "sumo/js/instant_search.es6", "sumo/js/responsive-nav-toggle.js", "sumo/js/profile-avatars.js", + "./webpack/protocol-compat.js", "protocol/js/protocol-base.js", "protocol/js/protocol-utils.js", "protocol/js/protocol-supports.js", diff --git a/webpack/eslintrc.js b/webpack/eslintrc.js index c71ca988d..3c41287ac 100644 --- a/webpack/eslintrc.js +++ b/webpack/eslintrc.js @@ -10,7 +10,7 @@ module.exports = { "no-undef": 2 }, "globals": { - // globals we need to expose in webpack + // globals exposed in webpack/global-expose-rules.js "_": "readonly", "moment": "readonly", "nunjucks": "readonly", diff --git a/webpack/global-expose-rules.js b/webpack/global-expose-rules.js new file mode 100644 index 000000000..d76a75012 --- /dev/null +++ b/webpack/global-expose-rules.js @@ -0,0 +1,92 @@ +// because most of our JS stack was written well before modules were a thing, +// many files place variables in the global scope for other files to use. +// in webpack, unless a file explicitly places a variable under `window.`, +// we have to expose each of these variables manually: +module.exports = [ + // expose these library exports globally: + expose("underscore/underscore.js", "_"), + expose("moment/moment.js", "moment"), + expose("nunjucks/browser/nunjucks-slim.js", "nunjucks"), + expose("codemirror/lib/codemirror.js", "CodeMirror"), + expose("../kitsune/sumo/static/sumo/js/libs/rickshaw.js", "Rickshaw"), + expose( + "../kitsune/sumo/static/sumo/js/protocol-details-init.js", + "detailsInit detailsInit" + ), + expose("../kitsune/sumo/static/sumo/js/sumo-tabs.es6", "tabsInit tabsInit"), + // wrap these files to make them behave like an es6 module, exporting the named variable, and expose that globally: + exportAndExpose( + "../kitsune/sumo/static/sumo/js/libs/uitour.js", + "Mozilla.UITour" + ), + exportAndExpose("../kitsune/sumo/static/sumo/js/analytics.js", "trackEvent"), + exportAndExpose( + "../kitsune/sumo/static/sumo/js/dnt-helper.js", + "_dntEnabled" + ), + exportAndExpose( + "../kitsune/sumo/static/sumo/js/libs/django/urlify.js", + "URLify" + ), + exportAndExpose("../kitsune/sumo/static/sumo/js/upload.js", "dialogSet"), + // making jquery and jquery-ui play nice, and exposed globally is a bit difficult, but this works: + { + test: require.resolve("jquery"), + loader: "exports-loader", + options: { + type: "module", + exports: "default $", + }, + }, + { + test: require.resolve("../kitsune/sumo/static/sumo/js/jquery-ui-custom.js"), + loader: "exports-loader", + options: { + type: "module", + exports: "default $", + }, + }, + // this library attempts to expose a bunch of stuff globally by adding them to `this`, imports-loader makes that work: + { + test: require.resolve( + "../kitsune/sumo/static/sumo/js/libs/diff_match_patch_uncompressed.js" + ), + loader: "imports-loader", + options: { + wrapper: "window", + }, + }, +]; + +function expose(path, exposes) { + // expose a module's export globally + return { + test: require.resolve(path), + loader: "expose-loader", + options: { + exposes, + }, + }; +} + +function exportAndExpose(path, funcName) { + // export a function or variable from a module, and expose it globally + return { + test: require.resolve(path), + use: [ + { + loader: "expose-loader", + options: { + exposes: `${funcName} default`, + }, + }, + { + loader: "exports-loader", + options: { + type: "module", + exports: `default ${funcName}`, + }, + }, + ], + }; +} diff --git a/webpack/protocol-compat.js b/webpack/protocol-compat.js new file mode 100644 index 000000000..331369223 --- /dev/null +++ b/webpack/protocol-compat.js @@ -0,0 +1,2 @@ +// Necessary until we upgrade protocol to include this fix: https://github.com/mozilla/protocol/issues/687 +window.Mzp = {};