According to this question How do I include a JavaScript file in another JavaScript file?. It seems a lots of people are interested in breaking big Javascript projects into small modules and export/import modules for code reuse.
After some research, import/export are designed for this feature. According to the references, they're initially defined in ES6.
Update
Latest version of main browsers shipped with this feature implemented. To have the latest status, please always refer to the References.
(If you're using nodejs, Modules (https://nodejs.org/dist/latest-v5.x/docs/api/modules.html) is the best aproach)
Refrerences:
https://developer.mozilla.org/en/docs/web/javascript/reference/statements/import
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/export
In the current versions of JS there are a few methods of doing this. Require uses the AMD design pattern, and is the standard for frontend dependency injection / module loading. Frameworks such as Angular use this method.
Here is a link to the require docs.
http://requirejs.org/
Time goes by... Today I would rather suggest using Babel (within browserify or webpack) to turn ES modules into plain old javascript.
Then you have the full power of import/export syntax.
Require/AMD/CommonJS is just getting deprecated anytime soon.
Related
When a package with typescript code is imported. will the consumer use typescript or transpiled code (e.g. typescript to ES5).
Scenario #1: If the consumer uses transpiled code (which is not in typescript). How is VSCode able to recommend auto completions from the packages types?
Scenario #2: If the packages are served with typescript files.
What happens if the consumer is not using typescript?
How does the bundling at the consumer end happen?
TL;DR
Scenario #1: This is the most common scenario for public NPM packages, editors use external .d.ts files that contain type declarations
Scenario #2: I've only seen this with internal libraries
1) You'd need to compile the TS by yourself, but that would probably not be necessary because there will almost always be a compiled-to-js version of the library, too
2) This could go many ways, best case is that the library gives you a pre-optimized JS that is just bundled with your code, worst case is that you have to make sure you have all the right dependencies installed for the library to be able to be compiled with your code and they need to be compatible with the dependencies you're using yourself. In my opinion this isn't worth the hassle, having type declarations for NPM packages is sufficient for the level of type safety TypeScript can provide.
The Long Version
There are dozens of variants how people distribute their TypeScript based code via NPM. Most big libraries I know ship their compiled (and often minified) JS and add .d.ts declaration files for editor support - these may be hand-written or produced by using tsc from a codebase. VSCode uses its TypeScript language server for JavaScript files, too, so in many cases it doesn't even need additional declaration files to provide you with basic autocompletion. Libraries can declare a types field inside the package.json, VSCode and other editors will find types there. There is a rather large community that maintains mostly inofficial type declarations for most libraries on definitelytyped - you may be out of luck for obscure ones.
A few examples
Material UI
Is written in JavaScript
Has hand-written TypeScript declarations (which may or may not be accurate)
React
Is written in JavaScript
Provides no TypeScript declarations with the NPM package but VSCode knows where to find inofficial external ones
Angular
Is written in TypeScript
Uses the deprecated typings field to point to its type declarations
jQuery
Is written in JavaScript
Again, has no provided type declarations but your editor probably knows how to fetch inoffical ones
Seneca
Is written in JavaScript
Has inoffical type declarations that are two years old at the time of writing - good luck finding out whether the API really hasn't changed
Important take-aways:
There is no single way people do things in the JS ecosystem and by extension the TS ecosystem
Most type declarations you're using are not official ones but the ones maintained by the community, mostly on definitelytyped
The types might be lying to you (may be out-of-date, just be plain wrong or for an older TS version)
TypeScript is a superset of JavaScript, it comes with all the same gotchas by definition
All types are erased at runtime, in the end you're running plain JavaScript with all that this entails
I know that if there are multiple JS files to be rendered by the browser, which apparently have identifiers inside, the global scope is polluted by this identifiers. I also know that one way to avoid this is using modules which(in my understanding) are just objects which have the aformentioned identifiers as members, thus sort of imitating C++ namespaces. I am also learning Node.js and there is a built in module system which eases this task so my question is: how to use modules in js files that are sent to the browser to be rendered?
Thanks.
Tools like browserify and WebPack are exactly what you are looking for (I personally prefer browserify over WebPack). Have a look at this answer, it explains a lot of your concerns.
In Node.JS, you can export a module using module.exports keyword, but you cannot just import those modules in your browser by just requiring them in a <script> tag. That's because, the browser doesn't understand the module system and everything works in the context of a global window object there, so module.exports simply becomes window.module.exports which I'm sure you'll not want. Hence you use tools like browserify that process the Node.JS scripts into something that your browser will understand.
This problem is usually solved by module bundlers or module loaders (e.g Webpack, Browserify, RequireJS). They are able to understand relations between your JS modules, skip unused modules and produce output that just works in your browser. All of that without the need to worry too much about global scope if you follow some conventions.
Some time ago, before ES6, two different approaches to this problem were widely used:
CommonJS:
var module = require('my-module');
widely known from Node.js
AMD:
define(['jquery'] , function ($) {
return function () {};
});
Which was suited for browser usage since it by design supported asynchronous loading of modules.
Then ES6 was introduced with native support for modules:
import * as lib from 'lib';
Main problem with new technology in web is that you often have variety of browsers to support which for a long time prevented developers from using new features. Nowadays, we have code transpilers and sophisticated code bundlers (e.g. Webpack). With their help you can use latest version of language, compile and bundle your code and at the end single "bundle.js" file is emitted which supports older browsers at the cost of slower execution times.
Quick question. I am a bit confused about ES2015(ES6).
Let's say I use Babel to compile to ES6 Javascript to compliant ES5 for current browsers.
The import/export functions are already available in ES6 by using Babel. So why would I need something like Browserify or Webpack if I were to simply use these just to bundle my modules, when ES6 could do it for me?
Everywhere I go I see people using Babel in combination with Browserify or Webpack. Although I know something like Webpack can be used for more, but I wonder if it is also possible to bundle files using the ES6 syntax.
I might be totally in the wrong here and I might have gotten lost in the Javascript Jungle of 2016, so I hope someone can clarifty this for me.
Edit
Am I right to assume that the native ES6 import / export functionality simply does not bundle files? From what I have read so far I think you still need to include all the separate Javascript files but you simply import modules into each-others namespace by using the native import functionality?
Yes, using babel to transpile your ES6 imports into ES5 will work.
However, one advantage of using webpack is that creates one static file to be served up in your production environment.
Pre-ES6 has no native module system, so there are multiple systems constructed in userland code (e.g. CommonJS / Node modules and AMD). Those are what Babel converts ES6 module syntax to (and yes, you're correct that ES6 module syntax has no native bundling story anyway). Browsers have no knowledge of those userland APIs. Node implements its module system by wrapping a "module" in a function that injects require() etc. In a browser require() would just be a reference error. Browserify (or another bundler) makes it work in the browser, and bundles a whole dependency graph into a single script. So if the code is for the browser you're likely going to want to bundle it. If it's for Node you may not need to.
The import/export functions
Not functions, declarations.
if I were to simply use these just to bundle my modules, when ES6 could do it for me?
I wonder if it is also possible to bundle files using the ES6 syntax.
Am I right to assume that the native ES6 import / export functionality simply does not bundle files?
Yes. There's no native way to bundle ES6 modules. You can transpile ES6 module syntax to something like Node modules and bundle those.
From what I have read so far I think you still need to include all the separate Javascript files but you simply import modules into each-others namespace by using the native import functionality?
It's important to realize that while the syntax is standardized, a lot of the behavior isn't. There's a Loader spec under development to specify how modules will actually be located and loaded.
See also https://stackoverflow.com/a/33044085/1034448.
I've got a browserify javascript project, where I include modules with the require statement. I'm now adding in some typescript, and it's working fine when I simply require the compiled javascript.
But typescript also has its own module statement. How does this relate to browserify/node's modules? Should I be using both? That seems redundant. Which type of modules should be used, and under what circumstances?
Thanks.
In newer versions of TypeScript (1.5) the module is deprecated in favour of namespace keyword. The keyword is to be used to create internal modules - allows you to organise your code internally.
So now it is more obvious that those are different things. Still TypeScript provides ability to create browserify/node's modules - external modules. For that you can use ES6 module syntax or older TypeScript's syntax. Then use browserify plugin (such as tsify) for more convenient builds.
More documentation about TypeScript modules and namespaces can be found here (also describing the older external modules syntax)
Which type of modules should be used depends on the project and taste of developers. If you target Node.js it worth to use CommonJS modules (IMHO ES6 syntax in TS and transpile it to CommonJS). If you are using browserify it is reasonable to use external modules, too. Namespaces is recommended to use only inside one file - hence internal modules.
I maintain and collaborate on some JavaScript modules written in CommonJS that are in need of high-quality UMD wrappers.
The dependencies are sourced from npm but have at least CommonJS and AMD support (or I can add it).
The CommonJS version goes on npm The UMD wrapped module will be pushed to bower
The wrapper must work in browsers (AMD + globals), and in Node.js (any and other CommonJS systems if possible). Any automation should preferably happen using Grunt (I'm pretty handy in grunt).
I've spend ages trawling Google en SO but it is a huge mess.
Some hopeful ones that don't quite cut it (or I am missing something, which is entirely possible):
browserify
gluejs
grunt-umd
I'm finding desperate constructs like this everywhere: http://rathercurio.us/building-umd-modules-with-dependencies-with-browserify , but I'm not really cool with such hackery.
Any good tips on this? I'll take any pointer or link or tip.
Edit: clarification: that last thing said, the ideal solution should not require us to assemble chunks of boilerplate template code by hand and create new bugs. I cool with configuring and specifying stuff though.
Your 1st and last stop should be urequire.org, the Universal Module Converter that does much more that just converting CommonJS and AMD javascript modules to UMD (or AMD or CommonJS or a standalone using rjs/almond).
It allows you to manipulate Module's code and dependencies while converting: inject, replace or remove code and dependencies, export to global objects (window) or your bundle, inject & optionally merge common code (like initializations), add runtime information, minify and much much more.
Most of that using simple but hugely powerful declarations & optionally callbacks for fine grained manipulation. It works with standalone config files (.js, .coffee, .json, .yml etc) and as-is as a gruntjs config
uRequire compiles from source modules written in javascript, coffeescript, livescriped, coco & icedcoffeescript without any plugins.
Forget boilerplate, code ceremony and repeating requires. The conversion templates are based on the well known UMDjs but can be customized via declarations to hide or provide functionality.
uRequire is opensource, MIT license and hosted on github and authored by me :-)