-
Notifications
You must be signed in to change notification settings - Fork 1.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: option to import helper methods instead of inlining them in transform API #1230
Comments
I think this is a good solution for |
The transformations would be done at the loader stage instead of the optimization stage. You may have missed this part:
|
The run-time code is currently in a single JavaScript file, which exists as a string (or more accurately a function that returns a string based on compiler options) within the compiler itself: This is a duplicate of #284. However this issue has more detail, so I will close that one in favor of this one instead. |
What's to stop us from just using tslib for this (at least, for done cases like decorators)? |
Not deduplicating helpers is causing our icon library ( So can't wait for this! ✨ |
For those who are also waiting for this feature, I sketched a small plugin for Rollup, which cuts out the helper for asynchronous functions and replaces it with import from a virtual module. I don't want to publish it to the npm because the template is stored as a string and can be changed at any time. However, if it will be useful to someone - take it and use it. I'm really looking forward to moving the helper into separate imports. import MagicString from 'magic-string';
import escape from 'escape-string-regexp';
const tmpl = `(__this, __arguments, generator) => {
return new Promise((resolve, reject) => {
var fulfilled = (value) => {
try {
step(generator.next(value));
} catch (e) {
reject(e);
}
};
var rejected = (value) => {
try {
step(generator.throw(value));
} catch (e) {
reject(e);
}
};
var step = (x) => x.done ? resolve(x.value) : Promise.resolve(x.value).then(fulfilled, rejected);
step((generator = generator.apply(__this, __arguments)).next());
});
}`;
const regex = new RegExp(`var (.+?) = ${escape(tmpl)};`);
export default function StripAsyncPlugin() {
return {
name: 'strip-async-plugin',
resolveId(source) {
if (source === 'virtual:async') {
return `\0${source}`;
}
return null;
},
load(id) {
if (id === '\0virtual:async') {
return `export default ${tmpl};`;
}
return null;
},
transform(code) {
if (!code.includes(tmpl)) return;
const builder = new MagicString(code);
builder.replace(regex, (code, name) => `import ${name} from "virtual:async";`);
return {
code: builder.toString(),
map: builder.generateMap(),
};
},
};
} |
+1 for a simple option to use tslib's async helper. It would be great if esbuild can cue into the tsconfig |
@evanw any thought given to this currently? Its the only downside to using esbuild for libraries in particular. Its less of a problem for apps, but I wouldn't expect people to compile down their This ends up leeading to workarounds I don't feel great about (currently, I don't let esbuild transpile my code, instead I use an SWC plugin to transpile code, but that feels icky, though its still reasonably fast, it does lead to a lack of congruence) Another potential alternative would be for esbuild to recognize the helpers and de-dupe, but that seems like more work and to be a service to the community, I imagine you'd need some mode you could run over |
esbuild doesn't have a good way to dedupe helpers when using the transform API, so I'm not gonna do this rn. See evanw/esbuild#1230
Problem
Currently, when applying syntax transformations via transform API, helper methods are inlined to the top of the file. Because they are inlined, they can be duplicated in a system where the transform API is applied per module.
Example
Input:
The following command outputs:
This happens in esbuild-loader so I have been recommending using the minifier to apply syntax transformations as a tip.
This was fine until I realized applying syntax transformations at the optimization stage could be dangerous as the input is the distribution asset rather than a module. As a result, the helpers can be inadvertently be inserted at the top of a JS chunk file and pollute the global scope and collide with other helpers in different chunks.
(As suggested in the thread, a possible solution here is to pass in
format: 'iife'
, but I think it's preferable to do transformations at the loader stage so it doesn't interfere with the format Webpack chunks are expected to be in.)I believe the helper duplication is happening in other tools that are powered by esbuild as well, such as rollup-plugin-esbuild and esbuild-register (Node.js).
Feature request
An
import-helpers
option/flag that imports the helpers instead of inlining them. With this option enabled, the example above would output something like this:This way, helper methods will only be declared once in a system.
The text was updated successfully, but these errors were encountered: