11

I need to write a module that will be available on the window global.
I'm using es6 to create the module and every single class I define has it's own file.
I'm using webpack to babelify and bundle these classes.
The entry point of my module is also the file containing the global to be exposed.

I've tried every method to make this possibe, icluding:

  • expose-loader
  • import-loader
  • expoert-loader
  • output: library
  • black-magic :(

Example of code I've tried:

I want to get: window.MyMod

// mymod.js
export class MyMod {
    constructor(aaa) {
        this.aaa = aaa;
    }
    toString() {
        return this.aaa;
    }
}

// webpack.config
var entries = [
    './src/mymod.js'
];
module.exports = {
    ...,
    module: {
      loaders: [
            {
                test: require.resolve('./src/mymod.js'),
                loader: 'expose?MyMod'
            },
            {
                test: /\.js$/,
                exclude: /node_modules/,
                loader: 'babel-loader',
                query: {
                    presets: ['es2015']
                }
            }
    ]
}

This only gets me an object MyMod on the window that contains MyMod as a constructor.

Any help will be appreciated.

sdgluck
  • 24,894
  • 8
  • 75
  • 90
bldoron
  • 1,050
  • 4
  • 20
  • 37
  • not a config solution but can't you just have an index file for your module that does `import lib from './lib'; window.lib = lib` – Daniel Lizik Aug 15 '16 at 12:33
  • Correct me if i'm wrong, but you are saying: *I'm using webpack to babelify and bundle these classes...* and *...This only gets me an object MyMod on the window that contains MyMod as a constructor.* Isn't that exactly what bable is doing when compiling ES6 ? Classes will be compiled to constructor functions, because in ES5 classes do not exist. – DavidDomain Aug 15 '16 at 12:37
  • Maybe I should somehow wrap the class in an anonymous self invoking function returning MyMod? – bldoron Aug 16 '16 at 06:49
  • Did you try using the [ProvidePlugin](https://webpack.js.org/plugins/provide-plugin/)? – Vedran Apr 27 '18 at 22:13

2 Answers2

5

You should combine export default class Foo with the library and libraryTarget settings in Webpack's config. Something like:

// src/Foo.js
export default class Foo { ... }

// webpack.config.json
{
  "output": {
    "library": "Foo",
    "libraryTarget": "var"
  }
}

You should be able to use the library as window.Foo once the bundle has been loaded.

ssube
  • 47,010
  • 7
  • 103
  • 140
4

This is basically the same issue as Exporting a class with Webpack and Babel not working , except that you have a named export instead of a default export. Your entry file should be

import {MyMod} from './mymod';
module.exports = MyMod;

or

module.exports = require('./mymod').MyMod;

If you don't want to do any of these and keep './src/mymod.js' as entry file, use a CommonJS export instead of an ES6 export in that file:

// mymod.js
exports.MyMod = class MyMod {
    constructor(aaa) {
        this.aaa = aaa;
    }
    toString() {
        return this.aaa;
    }
}
Community
  • 1
  • 1
Felix Kling
  • 795,719
  • 175
  • 1,089
  • 1,143
  • You might want to be more specific, otherwise it's not possible to help you. – Felix Kling Aug 16 '16 at 06:37
  • Sorry, you're correct. Your first solution is impossible, because i'm not importing the file anywhere, I need it to be built. The second one, I did try, but this: `require.resolve('./src/mymod.js')` and this `require.resolve('./src/mymod.js').MyMod` resulted in the same window.MyMod.MyMod. – bldoron Aug 16 '16 at 06:46
  • *"Your first solution is impossible, because i'm not importing the file anywhere,"* I said you have to create a *new entry file* with that content, instead of using `./src/mymod.js` as entry file. I.e. create a file `./src/entry.js` with the content from my answer and configure webpack to use that: `var entries = [ './src/entry.js'];` – Felix Kling Aug 16 '16 at 06:55
  • I've been trying to avoid that, it sounds like a hack. I think I'll do what jquery did and somehow wrap the class in an anonymous self invoking function returning MyMod. I'll report back with this try- though it also is a hack. – bldoron Aug 16 '16 at 07:01
  • 1
    Well, you are trying to make ES6 modules work together with a tool that is built for CommonJS modules. If you don't want use any of the suggestions and keep `./src/mymod.js` as entry file then you should use a CommonJS module definition instead of ES6: `exports.MyMod = class MyMod {};`. Implementing a wrapper like jQuery does is completely unnecessary because that's exactly what webpack does for you. – Felix Kling Aug 16 '16 at 07:19
  • What finally worked was: module.exports = class MyMod {...} and exposing it as I did: test: require.resolve('./src/mymod.js'), loader: 'expose?MyMod' – bldoron Aug 17 '16 at 15:48
  • @bidoron can you write an answer that sums up how to do this? All I get is an empty global var. – Jacob Phillips Oct 18 '18 at 20:07