Classic scripts vs. module scripts in JavaScript - javascript

I was going through the WHATWG specifications for async and defer attributes for the <script> tag, when I saw this statement:
Classic scripts may specify defer or async; module scripts may specify async.
I went through the WHATWG definitions for classic and module scripts, but I didn't really get much clarity. In simple terms, what are the differences between classic and module scripts in JavaScript?

Here are the differences I have noted from various articles. If you want more details, read a complete article on the internet:
Modules are singleton. They will be loaded and executed only once.
Modules can use import and export.
Modules are always executed in strict mode.
All objects (class, const, function, let, or var) are private unless explicitly exported.
The value of this is undefined at the outer scope (not window).
Modules are loaded asynchronously.
Modules are loaded using CORS. see Access-Control-Allow-Origin: *.
Modules don't send cookies and authentication info by default. See crossorigin="use-credentials".
Imports are resolved statically at load time rather than dynamically at runtime.
HTML comments are not allowed.

A classic script is just a standard JavaScript script as you know it. A module script is one that contains an ES6 module, i.e. it uses (or: can use) import and export declarations.
From §8.1.3.8 Integration with the JavaScript module system:
The JavaScript specification defines a syntax for modules, as well as
some host-agnostic parts of their processing model. This specification
defines the rest of their processing model: how the module system is
bootstrapped, via the script element with type attribute set to
"module", and how modules are fetched, resolved, and executed.
[JAVASCRIPT]
Note: Although the JavaScript specification speaks in terms of "scripts" versus "modules", in general this specification speaks in
terms of classic scripts
versus module scripts,
since both of them use the script element.
Also have a look at https://blog.whatwg.org/js-modules.

Related

Why must export/import declarations be on top level in es2015?

I started using es2015 with babel in last project. When I try to do import or export inside if condition, I have an error 'import' and 'export' may only appear at the top level. I see a lot of cases for that and it works good with require, but not with es2015 modules. Is there any reason for this limitation?
JavaScript performs static analysis on ES6 modules. This means you cannot dynamically perform imports or exports. Read section 4.2 of this article for more information:
A module's structure being static means that you can determine imports and exports at compile time (statically) – you only have to look at the source code, you don’t have to execute it.
There are many reasons for this approach, some of which are to prepare JavaScript for future features that rely on the ability for a source file to be statically analysable, namely macros and types (discussed in the aforementioned article).
Another interesting article on this topic mentions cyclic dependencies and fast lookups as reasons.
______
If you want to perform an export within some nested block of a module, reconsider how you are writing the module and exposing its APIs/internals as it is almost certainly not necessary. The same goes for if you are currently requireing modules within nested blocks in your ES5 code. Why not require / import at the top of your module and consume their APIs/internals within the nested blocks? The main advantage of this approach, at least from a readability point of view, is that you can know the dependencies of a module without having to scan its source for require calls.

Can/will AMD modules load in-between in-line script tags?

For reasons that aren't relevant to the question, my coworker needs to load a script that uses the Universal Module Definition pattern. Our environment usually has an AMD tool loaded, but for more irrelevant reasons, my coworker needs the script to define a global rather than registering a module through AMD. The approach that is currently checked in on their branch is something along the lines of this:
<script>
var backupDefine = define;
define = null;
</script>
<script src="../path/to/some/script/using/UMD.js"></script>
<script>
define = backupDefine;
backupDefine = null;
</script>
My question is: Is this a horrible idea? Is there a guarantee in the way browsers load scripts from script tags that will ensure nothing other than loading the UMD-based script will happen between undefining define and restoring define? We have a very large, very heavily async asset load primarily based around AMD modules, so what I am concerned with is an AMD module attempting to define itself in that intermittent state where define is currently not defined.
So long as UMD.js in no way modifies the scripts in the DOM, those scripts are guaranteed to execute in the order that they're authored in before any asynchronous callbacks that may have been queued before the first script executes.
I see this as a bad idea and spec breaking even if the case where define is always necessary is rare or even non-existent due to <script> load order considering your case. In an AMD environment, define, require and the like should basically be treated as first class keywords since their goal is to help you to remove globals.
Realistically, you're treading into undefined behavior as far as I can tell and writing code that is hard to maintain. You're relying on a tricky case with a spec where you have to undefine something and them immediately redefine it hoping that nothing tried to use it in the mean time. I'd say that that's "unsafe".
If you really need this to happen, I'd comment and document it heavily to make sure a future developer doesn't misunderstand what you're doing. However, I would say the better course of action is to rewrite the UMD.js file so that you export your global your own way. Rhetorically, why are you trying to use UMD if you don't want it to UMD things?
You're writing this module to support AMD through UMD but then you say that you don't want it to be used by AMD. Rewrite the file to just export to the global and avoid messing with define before you accidentally conflict with an additional library that does something tricky with define.

What is exactly define(function(require){...}) in JavaScript

I understand that define is used to define a module, and function is an anonymous function, but what does the argument 'require' in the function hold?
If I write anything in define(function(require){...}), when will this be called? How to give a call to his anonymous function?
Please help, I am new to advanced JS.
This is part of the requireJs api, it's not vanilla JS.
You can see the full docs in here:
http://requirejs.org/docs/api.html#define
"require" in the above example is actually the "require" code, this pattern allows you to require a JS and, than only when loading the JS is completed, load yet another dependency, but do so in the scope of the previously required file.
At large, this pattern allows you to break your app into multiple small JS files, and load them in an async way to speed up the loading process of web pages.
Some would argue that this is all going to be less needed when SPDY and HTTP2 are going to be more widely used. In any case, this is surely promotes a better modularity in the code design.

Is it possible to load requirejs under a different name

I know that for design reasons requirejs doesn't offer a way to load itself in noContext mode, bound to a different variable. Is it possible to do this manually somehow, or does require utilize the specific word "require" to execute its code? I know that it needs to the "require" and "requirejs" global variables to work - is it possible to change these names?
A little context: I am building Chrome extension which needs to load requireJS on a page to load a decent number of modules. However, some pages (upworthy.com and slate.com being 2 prominent examples) have critical functionality already bound to the name "require" (in the case of upworthy, they use requirebin or browserify). So I want to load requireJS without interfering with whatever native functionality is already assigned to require.
The JavaScript execution environment of content scripts are separated from the page, so you should not have any namespace collisions.
If you really need to inject the script in the page, then I strongly recommend to use r.js to generate one single JavaScript file, wrapped in an anonymous self-invoking function. Then, the require variable of your script will not conflict with the one in the page.

closure compiler - keep unused functions and don't rename the undefined

So closure compiler is great but exporting functions and defining externs seems to be too much manual work. Is there a way to tell the compiler that it should not remove any functions and should not rename any undefined functions?
I have 2 major reasons behind this:
If a function or property is not defined in the scope of the javascript document, then it's probably defined in an external file. Therefore, I wouldn't like these to be renamed.
If the function is defined in a given scope but isn't being called within the same scope, then it's probably being called in some external code. Therefore, I would like to keep this function in the file without renaming it.
This way, we could simply compile javascript files without worrying about external libraries and exporting functions that are called from html pages.
It very much sounds like you should run the compiler with the optimization level of SIMPLE_OPTIMIZATIONS. Don't be fooled by the name, as it still fully compiles your code. The main difference is that SIMPLE_OPTIMIZATION will not rename or eliminate dead code in the global scope. This means the requirements of externs and exports are no longer present.
To avoid this, I run the closure compiler on a complete script that is the concatenation of all the scripts of my application. So this is a two-step process :
1 - concatenate all
2 - run the closure compiler
Additionally, you may want (as I often do, due to problems with jquery before v1.8) to run the compiler with compilationLevel="simple".
Concatenation is very important as in general the slowness isn't related to the total size but mainly to the number of requests.
EDIT : of course you have to automate all this. I can provide you an ant task definition if you use ant.

Categories

Resources