Describe the feature
Currently, swc trips up on a lot of code that shares property names with ES library code; leading it to incorrectly deduce that a certain up-versioned ES feature is used by the code when it isn't, which then leads to unnecessary core-js polyfills being injected.
For example, the following TypeScript when compiled w/ swc targeting ie6 (swc 1.3.74, jsc.parser.syntax = "typescript", module.type = "es6", env.targets.ie = "6", env.mode = "usage", env.coreJS = "3"), results in the output with a number of unnecessarily applied polyfills to the output:
Input:
class Foo {
value: string;
trim(): Foo {
const trimmed = this.value.replace(/^\s+|\s+$/g, "");
return new Foo(trimmed);
}
constructor(s: string) {
this.value = s;
}
toString(): string {
return this. value;
}
}
const hello = new Foo(" hello ");
console.log(`hello: "${hello}"`);
console.log(`hello.trim(): "${hello.trim()}"`);
console.assert(hello.trim().toString() == "hello");
Output:
function _class_call_check(instance, Constructor) {
if (!(instance instanceof Constructor)) {
throw new TypeError("Cannot call a class as a function");
}
}
function _defineProperties(target, props) {
for(var i = 0; i < props.length; i++){
var descriptor = props[i];
descriptor.enumerable = descriptor.enumerable || false;
descriptor.configurable = true;
if ("value" in descriptor) descriptor.writable = true;
Object.defineProperty(target, descriptor.key, descriptor);
}
}
function _create_class(Constructor, protoProps, staticProps) {
if (protoProps) _defineProperties(Constructor.prototype, protoProps);
if (staticProps) _defineProperties(Constructor, staticProps);
return Constructor;
}
function _define_property(obj, key, value) {
if (key in obj) {
Object.defineProperty(obj, key, {
value: value,
enumerable: true,
configurable: true,
writable: true
});
} else {
obj[key] = value;
}
return obj;
}
require("core-js/modules/es.string.replace.js");
require("core-js/modules/es.regexp.exec.js");
require("core-js/modules/es.array.concat.js");
require("core-js/modules/es.string.trim.js");
require("core-js/modules/es.object.to-string.js");
require("core-js/modules/es.date.to-string.js");
require("core-js/modules/es.regexp.to-string.js");
var Foo = function() {
"use strict";
function Foo(s) {
_class_call_check(this, Foo);
_define_property(this, "value", void 0);
this.value = s;
}
_create_class(Foo, [
{
key: "trim",
value: function trim() {
var trimmed = this.value.replace(/^\s+|\s+$/g, "");
return new Foo(trimmed);
}
},
{
key: "toString",
value: function toString() {
return this.value;
}
}
]);
return Foo;
}();
var hello = new Foo(" hello ");
console.log('hello: "'.concat(hello, '"'));
console.log('hello.trim(): "'.concat(hello.trim(), '"'));
console.assert(hello.trim().toString() == "hello");
The polyfills injected:
es.string.replace.js,
es.regexp.exec.js,
es.array.concat.js,
es.string.trim.js,
es.object.to-string.js,
es.date.to-string.js,
es.regexp.to-string.js
I could be mistaken, but so far as I can see, the presence of es.array.concat is because of the "hello: ".concat(...) call, es.string.trim is because of the call to hello.trim(), es.date.to-string is because of hello.trim().toString(), and I'm not sure about es.regexp.to-string but it seems to also be erring on the side of caution from the same.
It seems to me that these false positives for polyfill-required properties could be avoided if the type information from the source TypeScript code were used. In particular, es.string.trim should only be used if the AST reveals that in the case of obj.trim(), obj extends string, es.date.to-string should only be injected in the case of obj.toString() where obj extends Date, es.regexp.to-string should only be injected in the case of obj.toString() where obj extends RegExp, and es.array.concat should only be required in the case of obj.concat() where obj extends Array.
(I'm not sure why es.string.replace and es.regexp.exec are injected since ie6 has full support for the both of them, and I think the same is also true of es.object.to-string but I can't be sure!)
Babel plugin or link to the feature description
No response
Additional context
I am aware that type inference would probably be out-of-scope for the swc compiler itself and I am not suggesting that this approach necessarily change.
This is mainly a brainstorming issue/feature request that I'm humbly opening to just bring in some perspective of a user that sees a wonderful tool possibly not availing itself of all the info it has access to, and wondering if there is something that could be done about it.
I envision one such way this could play out is an swc plugin that adds a new env.mode that goes a step further than env.mode = "usage"; perhaps an env.mode = "type-usage". This plugin would in turn depend on typescript and lean on that to produce the type-enhanced ast which could then either be fed back to swc core by the plugin for purposes of eliminating unnecessary polyfills or otherwise the plugin could take over the usage-based detection of polyfills using that type-enhanced ast and generate a more efficient list of polyfills to be used (but in the case of the plugin not feeding that info back to core, that would necessarily involve a great level of duplication between the polyfill detection and filtering that happens in core and that happens in the plugin).
Thank you for considering this unusual issue, thanks for making this amazing tool, and thanks for being awesome ♥.
Describe the feature
Currently, swc trips up on a lot of code that shares property names with ES library code; leading it to incorrectly deduce that a certain up-versioned ES feature is used by the code when it isn't, which then leads to unnecessary core-js polyfills being injected.
For example, the following TypeScript when compiled w/ swc targeting ie6 (swc 1.3.74,
jsc.parser.syntax = "typescript",module.type = "es6",env.targets.ie = "6",env.mode = "usage",env.coreJS = "3"), results in the output with a number of unnecessarily applied polyfills to the output:Input:
Output:
The polyfills injected:
es.string.replace.js,es.regexp.exec.js,es.array.concat.js,es.string.trim.js,es.object.to-string.js,es.date.to-string.js,es.regexp.to-string.jsI could be mistaken, but so far as I can see, the presence of
es.array.concatis because of the"hello: ".concat(...)call,es.string.trimis because of the call tohello.trim(),es.date.to-stringis because ofhello.trim().toString(), and I'm not sure aboutes.regexp.to-stringbut it seems to also be erring on the side of caution from the same.It seems to me that these false positives for polyfill-required properties could be avoided if the type information from the source TypeScript code were used. In particular,
es.string.trimshould only be used if the AST reveals that in the case ofobj.trim(),obj extends string,es.date.to-stringshould only be injected in the case ofobj.toString()whereobj extends Date,es.regexp.to-stringshould only be injected in the case ofobj.toString()whereobj extends RegExp, andes.array.concatshould only be required in the case ofobj.concat()whereobj extends Array.(I'm not sure why
es.string.replaceandes.regexp.execare injected since ie6 has full support for the both of them, and I think the same is also true ofes.object.to-stringbut I can't be sure!)Babel plugin or link to the feature description
No response
Additional context
I am aware that type inference would probably be out-of-scope for the swc compiler itself and I am not suggesting that this approach necessarily change.
This is mainly a brainstorming issue/feature request that I'm humbly opening to just bring in some perspective of a user that sees a wonderful tool possibly not availing itself of all the info it has access to, and wondering if there is something that could be done about it.
I envision one such way this could play out is an swc plugin that adds a new
env.modethat goes a step further thanenv.mode = "usage"; perhaps anenv.mode = "type-usage". This plugin would in turn depend on typescript and lean on that to produce the type-enhanced ast which could then either be fed back to swc core by the plugin for purposes of eliminating unnecessary polyfills or otherwise the plugin could take over the usage-based detection of polyfills using that type-enhanced ast and generate a more efficient list of polyfills to be used (but in the case of the plugin not feeding that info back to core, that would necessarily involve a great level of duplication between the polyfill detection and filtering that happens in core and that happens in the plugin).Thank you for considering this unusual issue, thanks for making this amazing tool, and thanks for being awesome ♥.