evanw / esbuild

An extremely fast bundler for the web
https://esbuild.github.io/
MIT License
37.92k stars 1.13k forks source link

Option to assign default export to globalName for iife format #3740

Open Paul-Browne opened 4 months ago

Paul-Browne commented 4 months ago
// foo.js
const awesomeFunction = () => {
    // bunch of code
}

export default awesomeFunction

// bundle.js
await esbuild.build({
    entryPoints: ['foo.js'],
    minify: true,
    format: "iife",
    globalName: "awesomeFunction",
    outfile: 'foo.min.js'
})

in the browser window.awesomeFunction is the object {__esModule: true}, where as window.awesomeFunction.default is the actual function. I understand why this is the case, but the solution from when the issue was mention earlier was to change the exported function type to module.exports. But wouldn't it be nicer/more convienient if there was an option in the builder to assign the default export directly to the globalName?

// bundle.js
await esbuild.build({
    entryPoints: ['foo.js'],
    minify: true,
    format: "iife",
    globalName: "awesomeFunction",

    assignDefault: true,    // default can be false if ommited, so it'll be backward compatible

    outfile: 'foo.min.js'
})

...Or, is there a way to do this already, without having to change the import

Extending on this... Maybe an option for using the name of the function (if it has been named) from the import as the globalName

// bundle.js
await esbuild.build({
    entryPoints: ['foo.js'],
    minify: true,
    format: "iife",
    globalName: true,    // not sure how one could pass implicity naming??? 
                         // Probably would require a fallback incase there wasn't a default (or if it wasn't named) 
    outfile: 'foo.min.js'
})
hyrious commented 4 months ago

To achieve something similar to what you're asking for, I'm using esbuild to generate the ESM bundle, then feeding it to rollup to produce other formats like CJS and IIFE (which will reduce some code of preserving ESM bindings semantics).

Rollup Repl | esbuild playground | Full build script

Paul-Browne commented 4 months ago

Yeah, i would really want to avoid having to involve another bundler... another option is to proxy the import and export it as a module.exports


// proxy.cjs
import awesomeFunction from "foo.js";
module.exports = awesomeFunction;

// bundle.js
await esbuild.build({
    entryPoints: ['proxy.cjs'],
    bundle: true,
    minify: true,
    format: "iife",
    target: "esnext",
    globalName: "awesomeFunction",
    outfile: 'foo.min.js'
})
Paul-Browne commented 4 months ago

...or, this is even possible without the proxy.cjs. By using stdin

await esbuild.build({
    stdin: {
        contents: 'import a from "./foo.js";module.exports = a;',
        resolveDir: '.'
    },
    bundle: true,
    minify: true,
    sourcemap: false,
    format: "iife",
    target: "esnext",
    globalName: "awesomeFunction",
    outfile: 'foo.min.js'
})