In webpack 1 docs is statement that in webpack 2 will use System.import() for dynamic require:
Luckily, there is a JavaScript API “loader” specification being
written to handle the dynamic use case: System.load (or
System.import). This API will be the native equivalent to the above
require variations.
And during that time all around the web was examples of using this System.import().
Before releasing webpack 2, authors decide to change System.import() to import():
add import() as Code Splitting construct. It should be used instead of
System.import when possible. System.import will be deprecated in
webpack 2 release (removed in webpack 3) as it's behavior is incorrect
according to the spec.
This import() is based on tc39/proposal-dynamic-import specification, and you can read more why they made this change here.
Can someone explain difference between System.import() and import()?
Despite different name, usage looks the same:
import(modulePath)
.then(module => module.default())
.catch(/* ... */);
System.import(modulePath)
.then(module => module.default())
.catch(/* ... */);
But in weback 2 doc is: "System.import() behavior is incorrect according to the spec" - so it suggest that there is difference between System.import() and import().
Here's what you're looking for: tc39 Proposal for Import
An actual function
Drafts of the Loader ideas collection have at various times had actual functions (not just function-like syntactic forms) named System.import() or System.loader.import() or similar, which accomplish the same use cases.
The biggest problem here, as previously noted by the spec's editors, is how to interpret the specifier argument to these functions. Since these are just functions, which are the same across the entire Realm and do not vary per script or module, the function must interpret its argument the same no matter from where it is called. (Unless something truly weird like stack inspection is implemented.) So likely this runs into similar problems as the document base URL issue for the importModule function above, where relative module specifiers become a bug farm and mismatch any nearby import declarations.
Related
Suppose I have a statement like this:
import * as bar from 'foo/bar';
I have a few questions:
What does the /bar bit mean?
Is there a sepcific (google-able) term for this?
Does this provide efficiency gains (reducing module bloat)?
How can I bundle a common-js module (ideally with Rollup) on NPM and support this syntax?
Breaking it down:
Firstly to provide context to your first and second question, let's go a bit further and break down all the parts of that statement:
import * as quux from 'foo/bar';
Note: The first bar instance in your example has been intentionally changed to quux to disambiguate the following points.
Collectively it is referred to as an Import Statement, or more specifically; an Import Declaration as defined in the ECMA-262 Imports Syntax Specification.
The import part is referred to as the Import Keyword.
The * as quux part is referred to as a NameSpace Import.
The asterisk * indicates that all exported bindings in bar will be imported to a newly created namespace object called quux. The resultant effect is that the quux object will hold all the exported members from bar.
The quux part of that is referred to as the Imported Binding and, as previously mentioned, it's used as the name for the newly created namespace object.
The from 'foo/bar' part is referred to as the From Clause.
The foo/bar part is a String Literal and is referred to as the Module Specifier... it's simply a filepath.
Answers to your specific questions:
What does the /bar bit mean?
It's part of the Module Specifier which is part of the From Clause. It is simply a reference to the name of the file whose exported member(s) will be imported from. In this example its exported member(s) will be imported into a new namespace object called quux.
With regards to what is that actual "part" called; ECMA-262 doesn't provide a specific reference/name for it, however, I refer to that part as the filename; (i.e. the filename in the filepath of the module to import).
As far as I know, /bar may or may not need to include a file extension (i.e. /bar.js). Again there's nothing in the ECMA-262 Imports Syntax that enforces this. ECMAScript only defines the syntax for modules and not the specific mechanism(s) for loading them. So the requirement for with or without a .js suffix may vary per implementation. For example:
In Apple's latest Safari browser built upon WebKit which runs on iOS the inclusion of the .js suffix is necessary.
In Modules docs for Node v8.10.0 they do include the .js file extension for imported files in their examples. Note: As ES6 Modules currently have a Stability Index 2 this could change.
Is there a specific (google-able) term for this?
Not per se, as ECMA hasn't named it specifically. You could try googling some of the terminology/nomenclature that I've previously mentioned.
Does this provide efficiency gains (reducing module bloat)?
I'm not sure I fully understand what you mean by "module bloat". However, If you mean will it result in less modules in application code? I think not, it's more likely result in an increased usage of modules.
Efficiency gains will be had from there being native ES6 Module support. Native support by it's very nature can bring speed/performance increases. Other benefits of ES6 Modules are:
ES6 Modules are statically analyzable which allows dead/unused code elimination via a process named Tree Shaking. More info here and here . So, if that's what you mean by the term "module bloat" - then yes; unused/dead code will be removed by tools that perform Tree Shaking.
Caveat; I'm not 100% certain whether tools that perform Tree Shaking are capable of removing dead code when using the wildcard/asterisk (*) in a NameSpace Import. It MAY be necessary to import specific member(s) that you'll use instead, i.e.
import { foo, bar, quux } from './foo/bar.js';
It's an official ECMAScript standard.
The example that you gave included a NameSpace Import, so there's another benefit - it will help to avoid namespace collisions.
More benefits are mentioned here.
How can I bundle a common-js module (ideally with Rollup) on NPM and support this syntax?
Rollup works with a plugin named #rollup/plugin-commonjs which will convert CommonJS modules to ES6, so they can be included in a Rollup bundle.
When declaring qx.log.appender.Native or qx.log.appender.Console, my IDE (PyCharm) complains about the syntax:
// Enable logging in debug variant
if (qx.core.Environment.get("qx.debug"))
{
qx.log.appender.Native;
qx.log.appender.Console;
}
(as documented here)
The warning I get is
Expression statement is not assignment or call
Is this preprocessor magic or a feature of JavaScript syntax I'm not aware yet?
Clarification as my question is ambiguous:
I know that this is perfectly fine JavaScript syntax. From the comments I conclude that here's no magic JS behavior that causes the log appenders to be attached, but rather some preprocessor feature?!
But how does this work? Is it an hardcoded handling or is this syntax available for all classes which follow a specific convention?
The hints how to turn off linter warnings are useful, but I rather wanted to know how this "magic" works
Although what's there by default is legal code, I find it to be somewhat ugly since it's a "useless statement" (result is ignored), aside from the fact that my editor complains about it too. In my code I always change it to something like this:
var appender;
appender = qx.log.appender.Native;
appender = qx.log.appender.Console;
Derrell
The generator reads your code to determine what classes are required by your application, so that it can produce an optimised application with only the minimum classes.
Those two lines are valid Javascript syntax, and exist in order to create a reference to the two classes so that the generator knows to include them - without them, you wouldn't have any logging in your application.
Another way to create the references is to use the #use compiler hint in a class comment, eg:
/**
* #use(qx.log.appender.Native)
* #use(qx.log.appender.Console)
*/
qx.Class.define("mypackage.Application", {
extend: qx.application.Standalone,
members: {
main: function() {
this.base(arguments);
this.debug("Hello world");
}
}
});
This works just as well and there is no unusual syntax - however, in this version your app will always refer to the those log appenders, whereas in the skeleton you are using the references to qx.log.appender.Native/Console were surrounded by if (qx.core.Environment.get("qx.debug")) {...} which means that in the non-debug, ./generate.py build version of your app the log appenders would normally be excluded.
Whether you think this is a good thing or not is up to you - personally, these days I ship all applications with the log appenders enabled and working so that if someone has a problem I can look at the logs (you can write your own appender that sends the logs to the server, or just remote control the user's computer)
EDIT: One other detail is that when a class is created, it can have a defer function that does extra initialisation - in this case, the generator detects qx.log.appender.Console is needed so it makes sure the class is loaded; the class' defer method then adds itself as an appender to the Qooxdoo logging system
This is a valid JS syntax, so most likely it's linter's/preprocessor's warning (looks like something similar to ESLint's no-unused-expressions).
Edit:
For the other part of the question - this syntax most likely uses getters or (rather unlikely as it is a new feature) Proxies. MDN provides simple examples of how this works under the hood.
Btw: there is no such thing as "native" JS preprocessor. There are compilers like Babel or TypeScript's compiler, but they are separate projects, not related to the vanilla JavaScript.
I've started using the intern library to write functional tests in js, and I realized that I couldn't understand this syntax:
var assert = require('intern/chai!assert');
var registerSuite = require('intern!object');
What is the purpose of the ! character in the argument of the require() method?
Short answer
It identifies a resource that is part of a plugin.
The structure of the identifier is: [plugin]![resource].
Long answer
In the documentation, you can find that:
Intern is built on top of a standard amd loader, which means that its modules are also normally written in the AMD module format.
That's why and how the require function is actually injected, so it's clear that you are not using the require module provided along with Node.JS.
It states also that:
[AMD format] Allows modules and other assets to be asynchronously or conditionally resolved by writing simple loader plugins
If you follow the link provided with the documentation when it cites the loaders, you find that:
Loader plugins extend an AMD implementation by allowing loading of resources that are not traditional JavaScript dependencies.
In particular, you can find that a dependency has the following form:
[Plugin Module ID]![resource ID]
It goes without saying that the default implementation of the loader you get by using intern adheres to the above mentioned standard.
That said, it follows that, if we consider:
intern/chai!assert
You can read it as inter/chai as plugin module and assert as actually required resource.
The purpose of the ! character in the argument of the require() method is to satisfy the requirements of the syntax used to identify a resource that is itself part of a plugin.
I got this answer for you extracted from this similiar question and very well explained by explunit:
The exclamation point syntax is reserved for plugins. Typically there would be something else following the exclamation point which indicates the resource that the plugin would load, e.g. text!myTemplate.html, but in the case of domReady! the plugin exists just as a way to wait until DOM loaded before invoking your callback function, so nothing needs to follow the exclamation point.
A while back I read that the System object is a required part of es6 modules, basically a new Object type with all the required semantics for module loading.
Is this a strict es6 requirement? It doesn't seem to be in the latest spec.
The global System object is not part of ES2015.
The module loading API, which includes System, was removed from the ES2015 spec in Draft 28, October 2014.
Module loading is now tracked by the separate WhatWG loader spec.
There is an implementation of the module loader API as specified in Draft 27 (including System) at https://github.com/ModuleLoader/es6-module-loader.
It seems that the API was dropped from ES2015, but will eventually be implemented.
I found this repository on GitHub, which talks a bit about the Module Loader API, but if you look at the issues, the first one is named "Programmatic module loader API Specification?". It includes a conversation on the subject.
The first comment says this:
The module loader API was actually removed from ES2015; it should
probably just be removed from this repo.
And this is also an interesting comment from there:
Worse, there's no way for import to even load modules, since it
doesn't have a loader to consult.
Eventually there will be a loader spec, but until then ES2015 just
specifies the syntax, and the syntax does nothing. (That is, the spec
contains points where it's like "consult the host environment to do
something useful here.")
The person who made both of the previous comments, links to these notes as a reference:
https://github.com/tc39/tc39-notes/blob/master/es6/2014-09/sept-25.md#loader-pipeline
Conclusion/Resolution
Loader pipeline goes into a separate spec: living document that deals
with integration
Is there any support for static typing in ECMAScript 6? How about ECMAScript 7?
No.
But on the ECMA-Script Wikipage there is a paragraph about changes in ECMA-Script 7:
The Seventh Edition is in a very early stage of development, but is intended to continue the themes of language reform, code isolation, control of effects and library/tool enabling from ES6. New features proposed include promises/concurrency, number and math enhancements, guards and trademarks (an alternative to static typing), operator overloading, value types (first-class number-like objects), new record structures (records, tuples and typed arrays), pattern matching, and traits.
Which may interest you.
Though this isn't part of the ES6 spec, Closure Compiler enforces JSDoc argument type annotations in JavaScript code when using its Advanced compilation level. Type annotations are specified using comments so they're ignored in development, but when you build your app for a production release a type mismatch will result in a compiler warning or, optionally, a compiler error.
An example of an enforced JSDoc type annotation:
/**
* #param {string} stringValue
* #return {number}
*/
function toInt(stringValue) {
return parseInt(stringValue, 10);
}
var val = toInt("10"); // Good
var val = toInt(false); // NaN in development, but throws an error (optional)
// or prints a warning (default) at build time
As an added bonus, JSDoc can build API documentation using this same syntax. So it's also handy if you document your code.
But a warning: for Closure Compiler to do its advanced optimization magic, every engineer on your project has to follow certain strict coding conventions. The compiler cannot enforce types unless it can reliably figure out what your code is doing, and that means giving up some of JavaScript's dynamic and wishy-washy syntax. If you don't follow them, errors can creep into your app and they can be very hard to diagnose after the fact. Most popular JavaScript frameworks and libraries do not follow them, though you can sometimes work around that using Compiler's externs feature. (jQuery is supported using externs, for example.)
So if you do use it, make sure you test your app thoroughly. I personally wouldn't even consider using this feature on a web app unless it has a Jenkins build bot and near-100% automated test coverage that can be run against your code after it's been optimized. That's a lot of work and is not for everyone; it took me months to get one of my projects up to that level. But personally, I think it's well worth the effort.
For more information, check out Advanced Compilation and Externs and Annotating JavaScript for the Closure Compiler.
No, there is no support for static typing in either ECMAScript 6 (ES2015).
As for ECMAScript 7 (ES2016), there is no proposal at any of stages 1, 2, 3, 4 or stage 0 for static typing.
I've seen a few proposals/ideas for static typing appear on the es-discuss mailing list, but none of these have actually been proposed for ES7 (ES2016).
If you want static typing right now, you're probably best looking into TypeScript or Flow.
Althought it's not pure ES6, Google's AtScript extending ES6 with type annotations and compiles into valid ES6 code once the compiler gets public: AtScript primer
As an option you can take a look at EsLint plugin https://github.com/yarax/typelint
It's not static check, but optional. The benefit of TypeLint is using already existing app data to build and use types automatically, unlike for example TypeScript or Flow, where you have to describe complex types by yourself.