webpack: Can't create UMD build which can be required by Node

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

bug

What is the current behavior?

If you require a module in the target output UMD you get this error:

ReferenceError: window is not defined
    at Object.<anonymous> (/mnt/c/Users/foo/webpack-umd-node/dist/main.js:1:272)

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

What is the expected behavior?

You shouldn’t see a ReferenceError.

If this is a feature request, what is motivation or use case for changing the behavior?

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

Node v8.9.4, webpack v4.0.0-beta.2


According to https://webpack.js.org/configuration/output/#module-definition-systems the UMD build should not include window.

About this issue

  • Original URL
  • State: open
  • Created 6 years ago
  • Reactions: 64
  • Comments: 28 (5 by maintainers)

Commits related to this issue

Most upvoted comments

Setting globalObject: 'typeof self !== \'undefined\' ? self : this' produces exactly the same UMD header as in WebPack 3

With target: 'node' it throws Uncaught ReferenceError: global is not defined if the UMD build is loaded in the browser 😄

globalObject: 'this' works for Node and the browser. Is this a new setting? I haven’t seen it before. Is this the right way to do it or is it a bug that I need to do that? I’ll update my linked example.

To add to this, we ran into an issue combining optimization.splitChunks with the targetObject. To get around this, we added parens around the suggestion from @bhovhannes (https://github.com/webpack/webpack/issues/6522#issuecomment-371120689):

  output: {
    ... configuration for multiple entry points
    libraryTarget: 'umd',
    globalObject: "(typeof window !== 'undefined' ? window : this)",
  },
  optimizations: {
    splitChunks: {
      cacheGroups: {
        base: {
          name: 'common-chunk',
          chunks: 'initial',
          minChunks: 2,
        },
      },
    },
  }

Our situation might be unique, but we are creating a shared library where we want to ship N components, along with a common chunk to provide at build-time with shared code between the components.

e.g.

import '@our_ns/our-lib/common-chunk`
import '@our_ns/our-lib/Component1`
import '@our_ns/our-lib/Component2`

not having parens around (typeof window !== 'undefined' ? window : this) resulted in the following code in the commons chunk:

typeof window !== 'undefined' ? window : this["webpackJsonp"] = typeof window !== 'undefined' ? window : this["webpackJsonp"] || []).push([["common-chunk"]

Clearly in the browser that first conditional will be false typeof window === 'object', causing the rest of the ternary op to be ignored and window.push to be run.

Adding parens around the globalObject outputs this code:

((typeof window !== 'undefined' ? window : this)["webpackJsonp"] = (typeof window !== 'undefined' ? window : this)["webpackJsonp"] || []).push([["common-chunk"],{

It’s a hack that really depends heavily on the internals of webpack, but I don’t see another way around it until this is solved.

Sorry if this doesn’t work for you, this is DEFINTELY a “works on my machine” kinda solution

@zacharyfmarion @yairEO I found a solution; add the following line to your webpack.config.js. globalObject: "typeof self !== 'undefined' ? self : this". Kind of frustrating that webpack hasn’t fixed the bug yet though.

@aendrew We are based on browserslist by default, if you support globalThis by versions, we will use globalThis and it will work everywhere

According to the docs include output.globalObject into webpack.config.js:

module.exports = {
  output: {
    libraryTarget: 'umd',
    globalObject: 'this'
  }
}

To make UMD build available on both browsers and Node.js, set output.globalObject option to ‘this’.

// Rant mode on That hilarious, as i see it was in 4 beta already. Now its 4.8.3, and its still there without a proper fix. Spent a day for this. Behaviour so inconsistent that i wanted to break something xD So many combinations and only one really worked for me. // Rant mode off

Proposed solution from above ( globalObject: ‘typeof self !== 'undefined' ? self : this’ ) simply dont work for me in browser. my lib

const LibraryModule = {
  x: 'y'
}
export default LibraryModule;

my import logging code

import * as x from "mylib"
console.log('import', x)

On server it as expected produce import { default: { x: 'y' } } In browser it produce import {__esModule: true} So empty module in browser for some reason. If i set globalObject: 'this', It almost worked. On server it was fine like in previous case. But in browser it was

import {mylib: {default: { x: 'y' } }, __esModule: true}

Basically it was adding for some reason mylib in browser. But not in node. Really consistent… And only removing from config library: "mylib", made it behave same for me in browser and node.

TLDR ONLY globalObject: 'this' AND removing option from config library: "mylib" made it work same in browser and node for me. And im not really sure yet if it will work properly or no. It just feels so hacky and inconsistent that it might break anytime. And the fact that it behave differently from the solution\comments from above just make that feeling worse…

any updates? migrate from webpack 4 to 5 ejected CRA app - and if do “globalObject: ‘this’” then my build is broken

hmm… I see.

Try target: "node" or output.globalObject: "xxx"

According to the docs include output.globalObject into webpack.config.js:

module.exports = {
  output: {
    libraryTarget: 'umd',
    globalObject: 'this'
  }
}

To make UMD build available on both browsers and Node.js, set output.globalObject option to ‘this’.

@vbabak This is not working anymore somehow once I add:

optimization: { 
  runtimeChunk: true 
}

to my webpack config 🙁

Since the issue has been open for nearly a year, it does not appear a fix will be forthcoming. In that case, perhaps the solution is to add the work-arounds mentioned here to the documentation pages:

Setting globalObject: 'typeof self !== \'undefined\' ? self : this' produces exactly the same UMD header as in WebPack 3

Thanks, at first I thought this in combination with setting libraryExport: 'default' allowed me to require my modules as expected with CommonJS.

However, I see quite strange, seemingly random behavior with the following actions:

  1. run webpack --mode development
    • builds appropriately; bundle.js shows:
...
})(typeof self !== 'undefined' ? self : this, function() {
...
  1. save a file without any changes being made:
    • bundle.js reverts to the following without even running webpack --mode development again:
...
})(window, function() {
...
  1. run webpack --mode development again
    • builds appropriately
  2. make a change and save file without building again
    • reverts to window again

Similarly random behavior can be seen by running webpack --mode development --watch, then saving a file with or without making any changes. One of the following 2 results occur:

  1. builds appropriately or
  2. reverts to window

The strange thing is that when saving a file without any changes being made, bundle.js is not even rebuilt; but still, the line })(typeof self !== 'undefined' ? self : this, function() { randomly changes back and forth to })(window, function() {.

One thing I tried was deleting node_modules/.cache/babel-loader (as I was setting cacheDirectory to true in development mode). But turning that setting off and deleting .cache/ entirely made no change to the above behavior.

Edit: Also tried deleting node_modules and running npm install for a clean slate just in case there was some kind of webpack cache buried inside, although I’m not sure that’s actually implemented (unplug it and plug it back in). No change to above behavior.

Should I create a separate issue for this, or does it seem related? Let me know if more environment details are needed.