Closed seangwright closed 8 years ago
This is the correct and expected behavior. What follows is an oversimplified explanation:
As languages evolve, they introduce new syntax and semantics.
In tandem they also introduce new functionality in their standard libraries.
For example, in addition to new syntax, such as =>
and const {x ,y} = z
, the ES2015 language specification introduced a new standard library function, Map
.
Many new features, be they syntactic additions such as the literal =>
token, semantics such as the lexical scoping of the this
keyword in =>
functions, or standard functions such as Map
, can be expressed in terms of constructs available in older versions of the language such as ES5.1.
In order to perform this process, which I will colloquially refer to as downleveling, different strategies are necessary depending on the kind of feature introduced.
For example, the syntactic and semantic behavior of =>
can be downleveled via a process called transpilation (compilation). This is the role of a transpiler. A transpiler transforms syntax and associated semantics, expressing them by way of constructs available in the target language.
As Map
is not a syntactic construct, it is largely outside the scope of transpilation. Instead, downleveling is achieved via polyfilling. A polyfill is simply a user-provided (e.g. not built in) library that adds to or augments an API such that it behaves like a newer version of the language. There is no syntactic process involved. To downlevel Map
we might write a polyfill.
For example it might be written (naively) as
window.Map = (function () {
function Map() {
this.entries = Array.prototype.slice.call(arguments, 0);
}
Map.prototype.forEach = function (action) {
var _this = this;
this.entries.forEach(function (entry) {
var key = entry[0];
var value = entry[1];
action(key, value, _this);
});
};
// ... rest of implementation
return Map;
})();
We can add downlevel support for Map
by including this code, but this is not transpilation.
You might argue that, whether via a library or via a syntactic transformation, TypeScript as a language supporting ES2015 should provide built in support for Map
, but as part of its standard library and include it automatically in all user code using Map
but they chose to work with existing polyfills.
Regardless this is not a syntactic process. There is nothing to transpile. There is no issue.
@aluanhaddad Thanks, that's helpful information. I thought transpiling covered all aspects of the language.
That said, could you point me towards the recommended way of currently importing babel-polyfill
of core-js
into an app? I've tried several variations of imports and jspm i
but nothing seems to be pulling the polyfills into my bundle.
I, obviously, am using jspm
/systemjs
and typescript
.
Examples:
In my app entrypoint main.ts
I have tried the following lines
import "babel/polyfill";
import "babel-polyfill";
import "babel-polyfill/dist/polyfill";
and I have the following installed via jspm
map: {
"babel": "npm:babel-core@6.17.0",
"babel-polyfill": "npm:babel-polyfill@6.16.0",
"babel-runtime": "npm:babel-runtime@5.8.38",
"core-js": "npm:core-js@1.2.7",
The polyfills never end up in my bundle but if I include them as a separate script tag in my page then everything loads correctly.
I have a very similar setup on several of my projects (jspm 0.17 + plugin-typescript + core-js. I am not sure in your specific case but it the problem is likely that you have the babe-polyfills installed as dev-dependencies, or possibly that you have certain settings like "babelOptions.include": ["runtime"]
configured a certain way. Those polyfills are specific to specific versions of babel and jspm, also, their version numbers seem to be incompatable.
Regardless, for TypeScript, the following should work just fine
~/my-app> jspm install core-js
main.ts
import 'core-js';
// bootstrap application.
@aluanhaddad Thanks again. Knowing that you were able to get the import working like that led me to investigate other issues. The problem I was experiencing was due to the fact that after I added the polyfill imports I only re-bundled and didn't re-transpile the typescript, so there was no source .js entrypoint file with the import it in.
This all gelling for me now.
One last question, are you using rollup.js
/tree shaking
in your bundling and if so does that allow you to import only the core-js
polyfills that you need? Currently the only es2015 type we are using is Map
so it would be great to just import that polyfill. If so is there documentation for configuring this?
--- UPDATE
I replaced the full core-js
import with one importing only the Map
type
Replace
import "core-js";
with
import "core-js/modules/es6.map";
and both the build.js
size and number of files from npm:core-js@2.4.1/modules/
pulled into the bundle has gone down considerably.
Just wanted to add - this problem kind of stems from the fact that plugin-typescript defaults to using lib.es6.d.ts
(for historical reasons). You can limit the features of es6 which are supported by the type-checker using the new lib
option (see here) so if you want to just use Map then it might be
lib: [ 'dom', 'es5', 'es2015.collection' ]
(I haven't tested this...)
@frankwallis I was looking into the lib
option but I don't really understand what it is doing.
By limiting which features are supported by the type checker what would I gain in my project?
The way I'm reading this, if I used the above lib
options then any es2015 type (other than those in es2015.collection
would cause an error when compiling my Typescript through the plugin. Is that correct?
yes that is correct, it is a way of aligning typescript with what you are planning to provide via polyfills
Here is my
tsconfig.js
Here is part of my
config.js
In my final output
build.js
I end up with code that looks like the followingMy original Typescript defines an instance of the
Map
type and that type is not available in ES5 but it ends up in thebuild.js
file. The command I'm running to generate mybuild.js
isjspm bundle app --inject
.Why isn't Typescript transpiling my
Map
type to something compatible with ES5? If I includebabel-polyfills.js
in the scripts loaded beforebuild.js
then everything runs fine in IE11 but if I don't include it then the app blows up as soon as it hits amap.set()
call.