Disposing a RequireJS Required Class - javascript

Im using requireJS to dynamically load JS modules in my html5 single page web application. Im just wanting to know whether I should dispose of the requireJS loaded modules once i have finished with them (so the garbage collector can clean them up)? And if so than how do you dispose a required module from requireJS?
Thanks in advance

It is possible to undefine a module:
There is a global function, requirejs.undef(), that allows undefining
a module. It will reset the loader's internal state to forget about
the previous definition of the module. However, it will not remove the
module from other modules that are already defined and got a handle on
that module as a dependency when they executed. So it is really only
useful to use in error situations when no other modules have gotten a
handle on a module value, or as part of any future module loading that
may use that module. See the errback section for an example. If you
want to do more sophisticated dependency graph analysis for undefining
work, the semi-private onResourceLoad API may be helpful.
http://requirejs.org/docs/api.html#undef
I'm not too sure on the internals but in my usage of the lib I've not found it necessary to do any manual clean up of modules.

Related

Ember why do we have to use import for certain bower dependencies

In an Ember app, when using certain dependencies like moment installed via bower, we have to also import the same in the ember-cli-build.js file:
app.import('bower_components/moment/moment.js');
My question is why is that needed, since I would assume everything inside node_modules as well as bower_components should be available for use inside the app.
Also if that is not the case, how do we identify which dependencies would require such explicit import to be able to use them ?
You don't have to, actually.
There is a package now that lets you 'just import' things: https://github.com/ef4/ember-auto-import
Some reading on the topic of importing: https://discuss.emberjs.com/t/readers-questions-how-far-are-we-from-being-able-to-just-use-any-npm-package-via-the-import-statement/14462?u=nullvoxpopuli
In in-depth answer to your question and the reasons behind why things are the way they are is posted here:
https://discuss.emberjs.com/t/readers-questions-why-does-ember-use-broccoli-and-how-is-it-different-from-webpack-rollup-parcel/15384?u=nullvoxpopuli
(A bit too long for stack overflow, also on mobile, and I wouldn't want to lose all the links and references in a copy-paste)
Hope this helps
Edit:
To answer:
I just wanted to understand "in what cases" do we need to use the import statement in our ember-cli-build (meaning we do not do import for all the dependencies we have in our package/bower.json)...But only for specific ones...I wanted to know what is the criteria or use case for doing import.
Generally, for every package, hence the appeal of the auto-import and / or packagers (where webpack may be used instead of rollup in the future).
Though, it's common for ember-addons to define their own app.import so that you don't need to configure it, like any of these shims, specifically, here is how the c3 charting library is shimmed: https://github.com/mike-north/ember-c3-shim/blob/master/index.js#L7
Importing everything 'manually' like this is a bit of a nuisance, but it is, in part, due to the fact that js packages do not have a consistent distribution format. There is umd, amd, cjs, es6, etc.
with the rollup and broccoli combo, we need to manually specify which format a file is. There are some big advantages to the rollup + broccoli approach, which can be demonstrated here
and here
Sometimes, depending on the transform, you'll need a "vendor-shim".
These are handy when a module has decided it wants to be available on the window / global object instead of available as a module export.
Link: https://simplabs.com/blog/2017/02/13/npm-libs-in-ember-cli.html
(self represents window/global)
however, webpack has already done the work of figuring out how to detect what format a js file is in, and abstracts all of that away from you. webpack is what ember-auto-import uses, and is what allows you to simply
import { stuff} from 'package-name';. The downside to webpack is that you can't pipeline your transforms (which most people may not need, but it can be handy if you're doing Typescript -> Babel -> es5).
Actually: (almost) everything!
Ember does, by default, not add anything to your app except ember addons. There are however some addons that dynamically add stuff to your app like ember-browserify or ember-auto-import.
Also just because you do app.import this does not mean you can use the code with import ... from 'my-package'. The one thing app.import does is it adds the specified file to your vendor.js file. Noting else.
How you use this dependency depends completely on the provided JS file! Ember uses loader.js, an AMD module loader. So if the JS file you app.imported uses AMD (or UMD) this will work and you can import Foo from 'my-package'. (Because this is actually transpiled to AMD imports)
If the provided JS file provides a global you can just use the global.
However there is also the concept of vendor-shims.. Thats basically just a tiny AMD module you can write to export the global as AMD module.
However there are a lot of ember addons that add stuff to your app. For example things like ember-cli-moment-shim just exist to automagically add a dependency to your project. However how it's done completely depends on the addon.
So the rule is:
If its an ember addon read the addon docs but usually you shouldn't app.import
In every other case you manually need to use the library either by app.import or manual broccoli transforms.
The only exception is if you use an addon that tries to generically add dependencies to your project like ember-browserify or ember-auto-import

Do I still need a module loader if I'm using ES6 modules?

Unfortunately my knowledge of JavaScript module loaders is still growing and I'm trying to understand their relationship to the new ES6 Modules. As far as I can tell using a module loader like CommonJS or RequireJS using ES5 compliant JavaScript really needed the use of an asynchronous module loader to increase performance and load only as needed using the respective module loader's syntax.
However looking at the ES6 module documentation and reading other information, it appears to me that module loading is natively supported via the import and export keywords. If this is the case am I correct that ES6 JS modules natively support asynchronous module loading and therefore I do not need to use an additional tool like CommonJS or RequireJS?
it appears to me that module loading is natively supported via the import and export keywords.
Not exactly. The import and export declarations only define the dependencies and the interface of each module. They allow to statically extract strings that name the required modules, nothing else.
If this is the case, do I not need to use an additional tool like CommonJS or RequireJS?
No. You still need to use a loader for ES6 modules, which resolves the names or paths or whatever from the imports to actual module files and loads them with an implementation-dependent method.
There are many tools or toolchains available, examples for the different solutions are
webpack: bundles everything into one large script
System.js: loads single modules dynamically and asynchronously (similar to what require.js does)
native: node.js and web browsers are still figuring out how to support module loading without additional libraries
babel transpilation: you can convert ES6 modules to AMD or CommonJS format and use the known tools like require.js for these
As far as my understanding goes, ES6 supports the syntax for defining and importing modules. The actual act of importing the modules that are required are a job of the infrastructure.
In modern browsers (as of 2016 that is) do not have built in functionality to support module loading and as such you will still need something like SystemJS to do the actual loading.
ES6 JavaScript Files are inherently treated as a module. if you define anything in a .js file, it will only be visible within that file (local scope ). what export does is, it exposes the classes / variables defined as export, visible to outside. then you can import it to a another module. There are other ways to define modules such as using Commonjs or AMD etc.. . Module loaders are required if you want to dynamically lazy load modules. ex. Systemjs is a such a Dynamic Module loader. it will fetch the physical module file from server dynamically when it is requested, and will prevent having multiple loads the same file. in SPA application in past had to load everything at the beginning to it to work. with dynamic module loaders now we can have only the files we need to do the intended job. hope this will help you.
https://github.com/systemjs/systemjs

Webpack & Testing: Helper to delete/replace modules from the require cache

For our tests we need to be able to replace or delete modules from the require cache, e.g. to replace them with a fake implementation.
In order to achieve this we implemented a little helper function:
fakeModule = function(modulePath, fakeExportsObject){
require.cache[require.resolve(modulePath)] = {exports: fakeExportsObject}
}
However when we run this through webpack we get the following critical warning: "the request of a dependency is an expression" and all JavaScript files in the project are included in the webpack build.
Is there any possibility to disable the interpretation of the helper function? In our tests we can safely assume that we are only deleting/replacing existent modules from the require cache. Even if not, it wouldn´t really matter.
Have you looked at rewire and rewire-webpack? I just started looking into testing with webpack and will need to find a way to accomplish this as well. Rewire sounds promising, but I haven't used it yet.

ES6 Modules are loaded Synchronously or Asynchronously?

Module loader is responsible for loading modules.
What I know is module loader loads modules in browser asynchronously whereas in Node.js it loads synchronously.
I wanted to confirm whether this information is correct or not.
ES6 module loaders will be asynchronous while node.js module loaders are not.
Here are some key aspects of module loaders:
Module code automatically runs in strict mode and there’s no way to opt-out of strict mode.
Variables created in the top level of a module are not automatically added to the shared global scope. They exist only within
the top-level scope of the module.
The value of this in the top level of a module is undefined. Does not allow HTML-style comments within the code (a leftover feature from
the early browser days).
Modules must export anything that should be available to code outside of the module.
https://leanpub.com/understandinges6/read#leanpub-auto-modules
Modules, in general, solve several problems for developers. First,
they allow the developer to separate code into smaller pieces, called
modules. Second, they make it easy for developers to load (inject)
those modules into other sections of code. Having modules injected
like this helps keep project code uncoupled from the module (read:
improved testability). And third, modules can load scripts
asynchronously. This means that apps can begin loading faster, as
they don’t require all scripts to be loaded prior to executing code.
http://chimera.labs.oreilly.com/books/1234000001623/ch03.html#_default_values
On the other hand because node.js is based on require which is synchronous this means node.js does not provide an asynchronous variant out of the box.
Of course there are async module loaders for node (async-require), but natively (with require) is not supported.
ESM is intentionally async (to accomodate loading over networks) and the rationale behind import also aims at knowing during code interpretation what dependencies exist (e.g. allowing bundlers to do treeshaking etc). This is also the reason to have imports at the beginning of your files and they can't be conditional (unless you use the await import() syntax).
You can also not eval(readFileSync(moduleFile)) if you use ESM syntax in the loaded file.

How can you ensure that angular module dependencies get resolved?

Angular's documentation on modules (http://docs-angularjs-org-dev.appspot.com/guide/module) says:
Dependencies
Modules can list other modules as their dependencies.
Depending on a module implies that required module needs to be loaded
before the requiring module is loaded. In other words the
configuration blocks of the required modules execute before the
configuration blocks or the requiring module. The same is true for the
run blocks. Each module can only be loaded once, even if multiple
other modules require it.
I created this example (http://jsbin.com/IRogUxA/34/edit) which creates a controller module that depends on two "mid-level" modules, each of which depend on two "low-level" modules. So, I have two "mid-level" modules and four "low-level" modules.
Clearly, order does not matter in the JS source. In the example above I've defined the high level modules before the low level ones they reference. I understand that Angular makes use of dependency injection to wire up the dependencies, but the way it does so is mysterious to me.
My question: How does one ensure that the config blocks of the various modules are run in the proper order? Or more broadly, how is it that Angular can resolve all of my dependencies when they are defined in any order I choose (within the JS source code)?
All the angular module API methods, such as "config", "factory" etc, are wrapped in a "invokeLater" function. In another word, when the dependency module is evaluated, the module.config, module.factory etc are not really called at that time. Instead those invocations are simply pushed into a queue.
Consider this example:
var demo = angular.module('demo', ['module1']);
demo.config( function( ) {
console.log("In app.config")
} ).run(function(){
console.log("Angular run");
});
angular.module("module1", []).factory('myservice', function(){
return {};
}).controller('mycontroller', function(){} );
For each module it has its own queue: (for the main module "demo")
var invokeQueue = [];
invokeQueue.push("demo.config", xxx);
invokeQueue.push("demo.run", xxx);
For module1:
var invokeQueue = [];
invokeQueue.push("module.factory", xxx);
invokeQueue.push("module.controller", xxx);
Once all the scripts are loaded and DOMContentLoaded event is fired , angular starts actually load/eval all the modules. At this time angular already constructed a full module dependency tree. The dependency module is always loaded first before the main module so in this case module1 will be loaded first and it's invokeQueue is called in the original order(module.factory, module.controller etc). Then back to the main module demo's invokeQueue, demo.config, demo.run
I think it helps to think of modules as their own applications, not relying on ordering of other (external) dependencies.
If order is important, then you can introduce a module that simply composes other modules and coordinates their interactions.
We avoid taking hard module references in our angular.module({moduleName},[deps]) calls, preferring to have those rolled up by a higher level module. That makes testing in isolation lots easier and you can stub out the services you rely on with lighter weight.

Categories

Resources