Global variable problem with `library`

Do you want to request a feature or report a bug?

Bug.

What is the current behavior?

(Code below) After bundled, I import mylib-bundle.js by <script>, and I see my expected object is wrapped by a property default, which means I have to use something like mylib.default.fn1 to access its properties.

However, if I change export default in mylib.js to module.exports =, it works well.

If the current behavior is a bug, please provide the steps to reproduce.

// mylib.js

import fn1 from './fn1';
import fn2 from './fn2';

export default {
    fn1,
    fn2
};



// Part of webpack.config.js

{
    entry: 'mylib.js',

    output: {
        filename: 'mylib-bundle.js',
        library: 'mylib',
        libraryTarget: 'umd', // Or 'var' by default
        umdNamedDefine: true
    
}

What is the expected behavior?

<script src="mylib-bundle.js"></script>
<script>
    mylib.fn1(); // Not `mylib.default.fn1();`
</script>

Please mention other relevant information such as the browser version, Node.js version, Operating System and programming language.

  • Windows 10
  • Node 7.2.0
  • Webpack 2.2.0-rc.2

Author: Fantashit

5 thoughts on “Global variable problem with `library`

  1. @sokra but what if I export single class?

    i.e:

    export class ID3Writer {
    }

    Using umd module with name ID3Writer I have to call constructor like this: new ID3Writer.ID3Writer() but why not just new ID3Writer()?

  2. That’s how the ES2015 module spec work.

    export class ID3Writer {}

    with { library: "ID3Writer", libraryTarget: "umd" }

    import { ID3Writer } from "./mylib-bundle";
    <script src="mylib-bundle.js"></script>
    <script>
        new ID3Writer.ID3Writer();
    </script>

    with { library: undefined, libraryTarget: "umd" }

    import { ID3Writer } from "./mylib-bundle";
    <script src="mylib-bundle.js"></script>
    <script>
        new ID3Writer();
    </script>
  3. Just to clarify, if one wants to leverage tree shaking and es6, it is impossible to build a UMD library that can:

    1. be directly required with commonjs (var foo = require('mylib'), which should also make import foo from 'mylib' possible with webpack) and
    2. set to the right browser global value (e.g. mylib if that is what is specified).

    Am I right? In my humble opinion, this is very sad because the above looks exactly how any good library should work.

    It was already a problem since babel6.. One usually had to rely on an entry point written in commonjs instead of es6 to make sure their library was properly handled by webpack (module.exports = require('./main').default;). I hoped webpack 2 would finally fix that…
    Moreover, if I am not wrong, using this usual workaround would even make tree-shaking inoperative, am I right?

  4. @boringer No I think your concern is valid. There is something very inconvenient in the way webpack is currently dealing with UMD bundling which, IMHO, makes it mostly useless. The example you provided with jquery is exactly how one would want a library to work. Building such library is, as far as I know, currently impossible with webpack and es6.
    The main reason is that webpack “dumbly” wraps whatever is exported when you use UMD targets (except for the odd loop for global variable when library is undefined that @sokra was talking about earlier, I am not too sure why there is an exception there, it looks quite dangerous when you have a default export).
    If you use ES6 (the only way to leverage tree-shaking), you can only export ES6 modules (previous versions allowed you to export commonjs even from ES6 modules but that is now forbidden). As a result, you end up wrapping an ES6 modules in a UMD wrapper. In my opinion it does not make much sense as the whole point of UMD is to make your library usable using different module systems. It does not make much sense that when using commonjs, one has to write require("mylib").default. I understand why it does that, but this is not what is needed for a library or a UMD wrapper. I would have expected webpack to adapt the module instead of just wrapping it. Maybe not by default, but at least to allow it…

Comments are closed.