Converting an IIFE to module.exports (and use Webpack) - javascript

I want to start using Webpack.
Currently, in one project I have the next lines:
<script defer src="https://cdnjs.cloudflare.com/ajax/libs/modernizr/2.8.3/modernizr.js"></script>
<script defer src="//ajax.googleapis.com/ajax/libs/jquery/3.1.0/jquery.min.js"></script>
<script defer src="/js/doubletaptogo.js"></script>
<script defer src="/js/init.js"></script>
I guess the following:
I should not download modernizr neither jquery because both are downloaded from their respective CDNs.
DoubleTapToGo is also a library and it is a minified local file. It is expressed via an immediately invoked function expression. So I should convert it into a module using module.exports, but I don't know how to do that and if I really should:
init.js should require DoubleTapToGo as a module, to produce just one file and finally have 2 libraries and 1 local JS file.
Please correct me.
Thank you in advance.
doubletaptogo.js has the following content:
;(function($,window,document,undefined){$.fn.doubleTapToGo=function(params){if(!('ontouchstart'in window)&&!navigator.msMaxTouchPoints&&!navigator.userAgent.toLowerCase().match(/windows phone os 7/i))return false;this.each(function(){var curItem=false;$(this).on('click',function(e){var item=$(this);if(item[0]!=curItem[0]){e.preventDefault();curItem=item;}});$(document).on('click touchstart MSPointerDown',function(e){var resetItem=true,parents=$(e.target).parents();for(var i=0;i<parents.length;i++)if(parents[i]==curItem[0])resetItem=false;if(resetItem)curItem=false;});});return this;};})(jQuery,window,document);

Related

React public folder scripts

Calling on the react experts haha.
I am trying to import/include some external javascript files into my React project, these js files cannot be changed or edit as per instructions from my company, as this is a base for many application that uses them.
For reasons i wont be putting the real filenames and folders.
There is a folder in my public folder called "testModules", so path is public/testModules/
all the files / 3 files that i need to include is in there.
What i have tried so far.
In my index.html file at the bottom i have tried the following
<script type="text/JavaScript" src="%PUBLIC_URL%/testModules/test1.js"></script>
<script type="text/JavaScript" src="%PUBLIC_URL%/testModules/test2.js"></script>
<script type="text/JavaScript" src="%PUBLIC_URL%/testModules/test3.js"></script>
and
<script type="text/JavaScript" src="./testModules/test1.js"></script>
<script type="text/JavaScript" src="./testModules/test2.js"></script>
<script type="text/JavaScript" src="./testModules/test3.js"></script>
and
<script type="application/javascript" src="./testModules/test1.js"></script>
<script type="application/javascript" src="./testModules/test2.js"></script>
<script type="application/javascript" src="./testModules/test3.js"></script>
and
Then i have also tried using the ScriptTag plugin "react-script-tag"
with the same examples as above, but instead of %PUBLIC_URL% i used process.env.PUBLIC_URL
When i try any of the above it works on my local development env. For example running npm run start and opening on localhost
But as soon as i move to application to a live server i get the following err
Refused to execute script from 'https://test.com/testModules/test.js'
because its MIME type ('text/html') is not executable, and strict MIME
type checking is enabled.
For all the files i added.
Now i open up my dev console and i can see the scripts are appended/included in the body at the bottom.
What is going on and how can i fix it.
Thanks You
If you wouldn't like to make any improvements to your deployment architecture, then you should pretty much talk to "your backend devs" so that they configure the web server so that this particular route would emit a different MIME type while serving this particular static file.
Alternatively, if possible, you could use Webpack to statically link the third-party code base to your React project so that they are distributed together. This way, if you use any implementation of Javascript modules, you will eliminate this crutch of your library being visible at the scope of the HTML host and this might bring improvement to your codebase.

How to include external libraries via CDN asynchronously in Webpack

Prior to posting this question, I consulted the following threads on this topic:
How to include external CDN link into webpack project
Webpack and external libraries
how to use webpack to load CDN or external vendor javascript lib in js file, not in html file
How to include jQuery CDN in Webpack?
Webpack externals documentation
Based on all the above, it appears that in order to load a third-party library via a CDN, the standard method would be to use webpack externals, which produces the following script tag in the index.html file (per Webpack docs).
<script
src="https://code.jquery.com/jquery-3.1.0.js"
integrity="sha256-slogkvB1K3VOkzAI8QITxV3VzpOnkeNVsKvtkYLMjfk="
crossorigin="anonymous">
</script>
While this solution works if you have one or two libraries, how are you supposed to load 10 libraries (for arguments sake) via CDNs asynchronously (to maximise pageload performance) using externals in Webpack?
My current solution to this problem is to manually include the following script tags in my index.html file with relevant "async" and "defer" tags; however, I need to update the index.html file in my dist folder every time I include a new library, which leads me to believe I'm doing this completely wrong. Below is what my index.html file currently looks like, which is also replicated in the dist folder.
<!DOCTYPE html>
<html lang="en">
<head>
<title>App</title>
<link rel="stylesheet" href="https://afeld.github.io/emoji-css/emoji.css">
</head>
<body>
<div id="app"></div>
</body>
<script src="https://cdn.jsdelivr.net/npm/moment#2.20.1/moment.min.js" async defer></script>
<script src="https://cdn.jsdelivr.net/npm/lodash#4.17.4/lodash.min.js" async defer></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/mathjs/4.0.0/math.min.js" async defer></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/axios/0.18.0/axios.min.js" async defer></script>
<script src="https://widget.cloudinary.com/global/all.js" async defer></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.4.0/Chart.min.js" async defer></script>
<script src="/dist/build.js" async defer></script>
</html>
While I'm sure there's a "hack-ey" way of achieving my goal (which I'm open to seeing), my question is whether I can accomplish the above through an officially supported method (like through externals). If not, how does most of the web development world use libraries given that CDNs are known to almost always improve pageload performance?
EDIT: For some context, I'm using Webpack because I'm using vue-loader to build my VueJS SPA (as a learning project).
EDIT 2: This question was asked using incorrect assumptions about Webpack and how web development works. The conclusion is that you shouldn't be using CDNs as liberally as I have if you're using Webpack. Refer to the comment section for clarification.

modules[moduleId] from webpack is undefined in Firefox Quatum 58.0b16

I'm getting a strange error from webpack in my prod environment in the following line only on FF. I've tried Chrome, Safari and there are no issues.
function __webpack_require__(moduleId) {
...
// Execute the module function
modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
}
If I break on that line and reload the page the issue does not happen which leads me to think it some kind of race condition on a file which is loaded.
I have 4 webpack output files in the following order.
<script type="text/javascript" src="/manifest-4.e05278c43f895122ca44.js" async=""></script>
<script type="text/javascript" src="/vendor-2.e05278c43f895122ca44.js" async=""></script>
<script type="text/javascript" src="/main-0.e05278c43f895122ca44.js" async=""></script>
<script type="text/javascript" src="/bootstrap-3.e05278c43f895122ca44.js" async=""></script>
I've looked at Github & SO for similar issues but don't think they directly relate to my issue.
[UPDATE]
Debugged the exact moduleId to be 49. Contents of main bundle file is empty for the 49th module which means it must be in vendor bundle. Suspect the loading speed of main and vendor bundle might be causing some issues.
Figured out the answer myself.
As suspected this was because vendor bundle loading after main bundle. Even though vendor bundle is specified before main there are couple of reasons causing this.
async attribute might cause race conditions when fetching the bundle
Apart from async we were also preloading the main bundle
We removed both as we did not have any use for them.

Error using crossroads.js in optimized (r.js) require setup

I have developed an application using RequireJS, with no optimization layer - Require downloads each file separately. Here is the outer markup:
<!DOCTYPE html>
<html lang="en">
<head>
<script type="text/javascript">
var require = {
//some basic config
};
</script>
</head>
<body>
<!--snip-->
</body>
<script type="text/javascript" data-main="main" src="scripts/lib/require.min.js"></script>
</html>
This functions without any issue, but with 100+ files the load time is really getting up there. So, time to introduce r.js optimization! I use node and r.js to create a combined file, and change data-main="main" to data-main="_build/main".
I get the following error:
Error: Mismatched anonymous define() module: (the entire body of crossroads.js)
Thoughts:
There are no manual / out-of-band define() calls or anonymous modules. Everything goes through the optimizer into this one file.
This isn't even our file - it's crossroads.min.js, which Require is able to handle just fine when the optimizer isn't involved.
I am still digging, but hoping someone can save me some time here.
TL;DR; Use the unminified version of crossroads.js, since you are doing a r.js build it will already compress the source file.
crossroads uses an unnamed define and is wrapped into a custom UMD (universal module definition). The minified version won't work well since r.js can't add the proper module name.
before minification:
(function(define){define(["signals"], ...
after minification:
(function(a){a(["signals"], ...
r.js can't figure out what a means, it only looks for define calls.

How can you specify which requirejs modules should load in a html file

I can't find an answer to this anywhere. Does this need to be done or does the optimiser do this somehow?
If a minified requirejs file became very large would it be suitable to break my_main.js down and possibly use my_main1 and my_main2?
<script type="text/javascript" data-main="my_main.js" src="scripts/require.js"></script>
You specify which modules you want via your "require" and "define" calls...
Your index.html will have a tag such as:
<script type="text/javascript" data-main="my_main.js" src="scripts/require.js"></script>
Inside "my_main.js" you'd do something like:
require(["module1", "module2"], function(module1, module2) {
});
which would load in module1 and module2.
When you decide to optimise your code, the optimiser will look through all the modules you load and all their dependencies and put them in a single minified file. You'll only need to load that minified file in your index.html in an optimized build.

Categories