videojs/videojs-contrib-hls

Support for webpack?

hanfeisun opened this issue ยท 107 comments

In the version of 1.x videojs-contrib-hls, I can shim the package like this:

import vjs  from 'video.js';
window.videojs = vjs;

require('imports?this=>window!videojs-contrib-hls');

However, in 2.0.1 videojs-contrib-hls, this method doesn't work.

A dependency called webworkify will throw an error

Uncaught TypeError: Cannot convert undefined or null to object
module.exports  @   index.js:10
VirtualSourceBuffer @   virtual-source-buffer.js:66
addSourceBuffer @   html-media-source.js:168
setupSourceBuffer_  @   videojs-contrib-hls.js?./~/imports-loader?this=>window:621
handleSourceOpen    @   videojs-contrib-hls.js?./~/imports-loader?this=>window:532
data.dispatcher @   video.js:18626
trigger @   video.js:18730
EventTarget.trigger @   video.js:7950

Will videojs-contrib-hls plan to support webpack in the future?

dmlap commented

I think this was the issue behind videojs/mux.js#53. That was fixed in mux.js >= 2.0.1, which you should use if you build this project yourself (and in our next release when that happens). Do you see the same error if you build contrib-hls yourself?

+1

Going to try building contrib-hls myself now.

Eh - no luck... @hanfeisun did you find a solution?

@samward1985 No, it doesn't work under Webpack now.. So I am still using videojs-contrib-hls 1.3.11..

Hello all!)
You can set alias for hls in webpack config. It works for me:
resolve: { alias: { 'videojs-contrib-hls': __dirname + '/node_modules/videojs-contrib-hls/dist/videojs-contrib-hls' } }

videojs-contrib-hls v2.2.0

I think contrib-hls 2.2.0 won't require any aliases anymore. Though, unfortunately, that version also requires videojs 5.10.1 and up.

@gkatsev i have videojs v5.10.2, but webworkify breaks webpack build because of
no fallbacks for arguments

If webworkify is the only problem, we should consider swapping it out for another module with similar functionality that works in both webpack and browserify.

There seems to be a webworkify-webpack module which may work for webpack but it doesnt work for browserify. Someone should write a module that works for both.

After some thought and some discussion in babel's chatroom, it seems like the correct solution is to not rely on a packer transform or loader to the web worker inline but rather do it as a separate source transform. I saw https://github.com/mohayonao/inline-worker which may help but also maybe there's some babel plugin that allows us to do this.
Unfortunately, this is a low priority for us because there's more pressing specific issues and it can be worked around by using the dist file or maybe running webworkify-webpack over the code. If anyone is willing to submit a PR to fix this issue we'll definitely take a look and work with you to land it.
Thanks!

I was having the same issue with webpack and contrib-hls. I was able to get it working by aliasing webworkify to webworkify-webpack in my webpack config like so:

// ...
resolve: {
  alias: {
    webworkify$: 'webworkify-webpack'
  }
},
// ...

The strange caveat is that I need point to version 1.0.6 in my package.json instead of the current version (which is 1.1ish). Got that little tidbit from a separate issue here

Hope this helps anyone!

I am facing the same and added below code too.

resolve: {
alias:
{ 'videojs-contrib-hls': dirname + '/node_modules/videojs-contrib-hls/dist/videojs-contrib-hls',
webworkify$: 'webworkify-webpack'
}
},
and getting this error
19:31:03.939 TypeError: _videoJs2.default is undefined
[72]</<() bundle.js%20line%205005%20%3E%20eval:8312
[72]<() bundle.js%20line%205005%20%3E%20eval:7848
s() bundle.js%20line%205005%20%3E%20eval:7
s/<() bundle.js%20line%205005%20%3E%20eval:7
[71]</<() bundle.js%20line%205005%20%3E%20eval:7668
[71]<() bundle.js%20line%205005%20%3E%20eval:7640
s() bundle.js%20line%205005%20%3E%20eval:7
s/<() bundle.js%20line%205005%20%3E%20eval:7
[76]</<() bundle.js%20line%205005%20%3E%20eval:8886
[76]<() bundle.js%20line%205005%20%3E%20eval:8870
s() bundle.js%20line%205005%20%3E%20eval:7
s/<() bundle.js%20line%205005%20%3E%20eval:7
[94]</<() bundle.js%20line%205005%20%3E%20eval:14668
[94]<() bundle.js%20line%205005%20%3E%20eval:14627
s() bundle.js%20line%205005%20%3E%20eval:7
e() bundle.js%20line%205005%20%3E%20eval:7
bundle.js%20line%205005%20%3E%20eval:7
bundle.js%20line%205005%20%3E%20eval:7
bundle.js%20line%205005%20%3E%20eval:7
bundle.js%20line%205005%20%3E%20eval:1
bundle.js:5005
__webpack_require
() bundle.js:556
hotCreateRequire/fn() bundle.js:87
bundle.js%20line%204993%20%3E%20eval:29
bundle.js%20line%204993%20%3E%20eval:1
bundle.js:4993
webpack_require() bundle.js:556
hotCreateRequire/fn() bundle.js:87
bundle.js%20line%204081%20%3E%20eval:21
bundle.js:4081
webpack_require() bundle.js:556
hotCreateRequire/fn() bundle.js:87
bundle.js%20line%20691%20%3E%20eval:19
bundle.js:691
webpack_require() bundle.js:556
hotCreateRequire/fn() bundle.js:87
bundle.js:588
webpack_require() bundle.js:556
bundle.js:579
bundle.js:1
1 bundle.js%20line%205005%20%3E%20eval:8312:1

this is giving the error of
webworkify-webpack: Could not locate module containing worker function! Make sure you aren't using eval sourcemaps and that you pass named functions to webworkify-webpack!

If anyone else encounters this issue again (or a similar one) and wants to use videojs-contrib-hls with Webpack:

webworkify-webpack shims window to {}, which causes global/window to return the wrong context in a web worker, which in turn causes things to fail. I've created a fork of webworkify-webpack that's compatible with the original webworkify and works with videojs-contrib-hls!

Just add webworkify-webpack-dropin@^1.1.9 to your dependencies and add the following alias to your Webpack config:

resolve: {
  alias: {
    webworkify: 'webworkify-webpack-dropin',
  },
}

It's been tested on videojs-contrib-hls v3.7.0-beta3 and video.js 5.12.6.

Anyone know of a babel webworkify plugin? If we can inline the webworker at that point, we can easily support both webpack and browserify without extra work on the user's part

@Ambroos also, thanks for making the dropin replacement package, seems like it'll make things a lot simpler in the meantime.

@Ambroos I've tried your solution and I'm getting an error thrown here in webworkify-webpack-dropin:

if (typeof key === 'undefined') {
        throw new Error('webworkify-webpack: Could not locate module containing worker function! Make sure you aren\'t using eval sourcemaps and that you pass named functions to webworkify-webpack!');
}

I've made sure that I'm not using eval sourcemaps.
I've upgraded my versions of videojs-contrib-hls and video.js to v3.7.0-beta3 and 5.12.6, respectively. The only difference is my project is a react app using nwb, if that makes any difference. Any ideas?

@vpowers Could you show me your webpack config? I can't really think of any reason for this error to appear.

@Ambroos Here is my nwb.config.js. Webpack configuration is passed in:

module.exports = {
...
  webpack: {
    devtool: 'cheap-source-map',
    html: {
      favicon: 'vendors/favicon.ico'
    },
    extra: {
      resolve: {
        alias: {
          webworkify: 'webworkify-webpack-dropin'
        }
      }
    }
  }
}

Here is the line in virtual-source-buffer.js (es5) from videojs-contrib-media-sources that executes webworkify-webpack-dropin:

// append muxed segments to their respective native buffers as
// soon as they are available
this.transmuxer_ = (0, _webworkify2['default'])(_transmuxerWorker2['default']);

I've attempted to isolate the issue by creating a small app using videojs-contrib-hls and bundling with webpack and @Ambroos 's solution does work. I had been testing this within a larger react app that uses nwb so somethings going on there. I'll provide an update if I can figure out the issue.

@Ambroos's solution worked for me, but I had to turn off eval for source maps in my large react app, @vpowers. (edit: I see now that you're using cheap-source-map, so that probably won't help you)

@dbryand My react app is using nwb for bundling instead of plain webpack. (nwb uses webpack under the hood). This seems to be the difference. Are you just using webpack?

Yes, a home-rolled webpack config.

I've created two small applications. One using webpack and video.js with hls plugin and a react app using nwb (https://github.com/insin/nwb) and video.js with hls plugin. Both of them are swapping out the webworkify module with @Ambroos's webworkify-webpack-dropin module. The webpack app is working with this solution but the react app using nwb is not. If anyone has any experience with nwb or is feeling helpful, take a look at these projects. Any help would be appreciated!

https://github.com/vpowers/simple-react-app
https://github.com/vpowers/simple-webpack-app

In case someone comes along and needs to support videojs-contrib-hls in a react app using nwb, I have forked @Ambroos webworkify-webpack-dropin to support how nwb bundles code:

https://github.com/vpowers/webworkify-nwb

Follow the instructions in this comment but use the module above instead.

I wonder if we can turn webworkify into a babel plugin. Then we could just run it at build time and users of contrib-hls won't need to bother with configuring their bundlers.

Hi, guys, could please someone explain how to use this inside SPA? I tried @vpowers solution, but I still get webworkify-webpack: Could not locate module containing worker function! Make sure... I'm using vuejs

Thank you in advance.

Running into this issue here as well, same error as @oleynikd is reporting - any updates since last month on this? Also using vuejs and importing as es6 module, compiling with webpack. Tried the webworkify-webpack-dropin plugin but no dice.

So Basically here is the setup you need to get this up and running.

I am using node 7.4 and a boiler from create-react-app.

This is my webpack config:

resolve: {
        // This allows you to set a fallback for where Webpack should look for modules.
        // We read `NODE_PATH` environment variable in `paths.js` and pass paths here.
        // We use `fallback` instead of `root` because we want `node_modules` to "win"
        // if there any conflicts. This matches Node resolution mechanism.
        // https://github.com/facebookincubator/create-react-app/issues/253
        fallback: paths.nodePaths,
        // These are the reasonable defaults supported by the Node ecosystem.
        // We also include JSX as a common component filename extension to support
        // some tools, although we do not recommend using it, see:
        // https://github.com/facebookincubator/create-react-app/issues/290
        extensions: ['.js', '.json', '.jsx', ''],
        alias: {
            'videojs-contrib-hls':paths.appNodeModules+'/videojs-contrib-hls/dist/videojs-contrib-hls.min.js'
        }
    }

I am also using this plugin to set videojs globally on my scope:

new webpack.ProvidePlugin({
            videojs: "video.js",
            "window.videojs": "video.js"
        }),

Additionally on my video component JS I use the following:

import 'videojs-contrib-hls';
let video;

Later on my component did mount:

componentDidMount(){
        const options = {
            height: "100%",
            width: "100%",
            hls: {
                withCredentials: true
            }
        };
        video = window.videojs("video-player", options);
    }

finally you need to set your src m3u8 file and type using Javascript if not this will not work:

video.src({
                src:'https://master.m3u8',
                type: 'application/x-mpegURL'
            });
video.play();

render(){
    return(
         <video id="video-player" controls preload className="video-js" poster="videoposter.jpg"/>
     );
}

Finally got my video to play hope this helps!

You will need to use the same plugin and change the alias in your production configuration so the library can run properly:

USE THE ES5 VERSION

'videojs-contrib-hls':paths.appNodeModules+'/videojs-contrib-hls/es5/videojs-contrib-hls.js'

ADD THE WEBWORKIFY DROPIN

'webworkify$': 'webworkify-webpack-dropin',

NPM Modules used:

"video.js": "^5.12.6",
 "videojs-contrib-hls": "^3.7.0-beta3",
"webworkify-webpack-dropin": "^1.1.9"

Thanks for this @lionxcr, I was able to set it up following your guide.
Is there no other way to integrate it more seamlessly without additional Webpack config?
Thanks!

@icetronics You are so welcome! As far as I know contrib-hls is not supported in webpack just yet so by far this is the best hack to get m3u8 videos to work properly in react.

The reason why is because we use browserify to build out the pre-build standalone file. To do that we use the webworkify module that you're replacing with the dropin one for webpack. What would need to happen is to switch to either a babel plugin or something external to the bundler to do the webworker inlining.

Thanks @gkatsev! Would you be able to provide an example or some further pointers so I could try setting it up?

In case there are people having the same problems as I did:

I have been trying to make this work with webpack 2.2.1, video.js 5.18.4 and videojs-contrib-hls 5.3.3. I was able to get webworkify-webpack-dropin to work with a small change: https://github.com/Ambroos/webworkify-webpack-dropin/pull/1/files . I am hoping @Ambroos will merge the PR and release the version to NPM soon. Change in plans. I am trying to release a fix as a separate npm package, yet still trying to figure out how to make it work with uglify-js atm. Gave up :(

@cansin and anyone else who's using webpack's UglifyJsPlugin. I found that if I set compress to false and mangle to true, like so:

plugins: [
    ...
    new webpack.optimize.UglifyJsPlugin({
      compress: false, // leave false for now. This breaks the videojs-contrib-hls package
      mangle: true,
      sourceMap: true
    }),
    ...
],

This will uglify it without breaking the videojs-contrib-hls package. For me, it was like less than 40KB difference between compress being true vs false.

I'm also importing the package like so: import 'videojs-contrib-hls/dist/videojs-contrib-hls.min.js'

This is a nice workaround for me until videojs-contrib-hls is compliant with the compression tool

I actually couldn't figure out how to make webworkify-webpack-dropin work with my case. Instead I ended up separating videojs-contrib-hls through:

require.ensure(['videojs-contrib-hls/dist/videojs-contrib-hls.min'], require => {
    require('videojs-contrib-hls/dist/videojs-contrib-hls.min');
}, 'package-videojs-contrib-hls');

and then disabled UglifyJS for this separate bundle via:

new webpack.optimize.UglifyJsPlugin({
    sourceMap: false,
    compress: {
        warnings: false,
    },
    exclude: /package-videojs-contrib-hls/,
})

I know this is less than ideal, yet it works for now. Could be an alternative to what you did @everett1989 .

@cansin I'll try it out, thanks for the example

hi all, does anyone know if this webpack fix works when deploying to heroku? I am currently trying to deploy to heroku and I am getting an 'Uncaught SyntaxError: Unexpected token {'

EDIT: With the help of zshenker on Slack I followed @Ambroos but that required me to turn off my source maps. This got me over the error referenced above, but then it ultimately fails to load because I get a simple syntax error "Uncaught SyntaxError: Unexpected token {". Is their really no way to turn on source map with webworkify?

EDIT2: So the syntax error problem appears to be occurring because of the common UglifyJs plugin in my webpack.config. When I get rid of it, the error goes away, but unfortunately that leaves me with a file that went from 1.04MB to 2.86MB. Ideas on how to fix those syntax errors and still use Uglify?

EDIT3: It appears to be a problem with the version of uglify that is bundled with the latest Webpack v1 (1.14.0). I installed uglifyjs globally and ran the bundle.js file through the command line manually, with no syntax error. It also maintains roughly the same as listed above. So I guess I'll try to update to Webpack 2 soon and verify if the error exists there.

it's not UglifyJs's bug it's bug in this code https://github.com/Ambroos/webworkify-webpack-dropin/blob/master-v1/index.js#L92

it appears when code is minimized and unused function names are removed

moduleWrapperStrings[moduleId] = wrapperFuncString.substring(0, wrapperFuncString.length - 1) 
+ '\n' + fnString.match(/function\s?(.+?)\s?\(.*/)[1] + '();\n}';

this regex is matching function name but if there is none it will match some weird shit

and syntax error will appear after compilation in webworker code generated at runtime in browser

@thecotne Thanks. I had suspected that because for debugging purposes I also moved to Webpack 2, and that didn't fix the issue (has more up to date Uglifyjs) I temporarily solved it by running uglify as part of my "npm build" script outside of webpack. Looks like he just needs to pull from where he forked from because they claim to have a fix that works with Uglify. I'll look at that today.

serv commented

When I try to compress the js bundle using webpack and uglify, in the browser console, I get this error

Uncaught ReferenceError: e is not defined

@serv Yep. As was discussed in my posts above, there is a very strict regex function in the current version of webworkify-webpack-dropin. Uglify gains one of its shrinkage abilities by deleting functions that it determines are unused, but webworkify is still looking for them. For now, just turn off uglify in webpack, or you can make a npm script that builds your webpack and then runs uglify, which I did with success. I will be trying to get @Ambroos to update his fork here soon, given that I suggested that people use it in the webpack docs.

Ok... So webworkify-webpack worked for a few weeks to months, then webworkify-webpack-dropin worked for a few more. Now I am on the latest of everything (contrib-hls: 5.4.1, video.js: 5.19.2 as of this writing) and everything is working! Here is how I did it:

Alias videojs-contrib-hls per @lionxcr's suggestion:

// webpack.config.js
var path = require('path');
// ...
  resolve: {
    alias: {
      'videojs-contrib-hls': path.join(
        __dirname,
        'node_modules',
        'videojs-contrib-hls',
        'dist',
        // You can use the unminified version and let the minifier minify!
        'videojs-contrib-hls.js'
      ),
    }
  }
// ...

Make videojs global (also per @lionxcr's suggesiont):

// webpack.config.js
// ...
  plugins: [
    new webpack.ProvidePlugin({
        videojs: "video.js",
        "window.videojs": "video.js"
    })
  ]
// ...

After all of that, I was getting the same error as @serv. After some digging, I found the DefinePlugin. It turns out uglify was doing strange things with global, so I aliased typeof global to "undefined" so that the minifier would remove it!

// webpack.config.js
// ...
  plugins: [
    new webpack.DefinePlugin({
      'typeof global': JSON.stringify('undefined')
    })
  ]
// ...

Also, if at some point had you aliased webworkify, un-alias it!

// webpack.config.js
// ...
  resolve: {
    alias: {
      // webworkify$: 'webworkify-webpack',
      // webworkify$: 'webworkify-webpack-dropin',
    }
  }
// ...

Phew! That works for now... Hope this helps!

So far I can create development bundle without a problem and plugin works perfectly, but when I build production I get this error in run-time:

Uncaught ReferenceError: n is not defined blob:http://localhost/659f9283-bbc2-4836-ae79-ebb3cd70a83a:1

I solve this issue passing:
devtool: (isProd ? '#eval' : '#source-map')
my original set up is
devtool: (isProd ? false : '#source-map')

The problem is that my bundle pass from 1.3MB to 4.3MB when I set eval to devtool.
has anyone solve this issue completely?

The solution by @ScottLNorvell worked for me, but this part led to some very tricky to debug issues with another library (GSAP) in my app.

       new webpack.DefinePlugin({
         'typeof global': JSON.stringify('undefined')
       }),

In retrospect it seems obvious that other libs may rely on the typeof global and this could blow things up.

EDIT: In removing this I don't see any impact to video.js / hls.

?? Decided to visit this again today because I got the classic error 'fs is not defined' in Safari (but not Chrome). But I still can't get webpack to run uglify from the config file. It passes, but then gives like above, 't is not defined in blob' when the page is opened. So I'm going back to my method of just running webpack, and then using uglify after the fact. Somehow that doesn't cause any problems.

Now have confirmed that I'm getting the dreaded 't is not defined', too, when I package and ship to s3.

EDIT: I turned off uglification in the app and it works.

@dbryand same here "t is not defined" . Did you find any solution?

Yes, I dropped videojs and just went with html5 + hls.js. Sorry I can't be more helpful :)

Can you send your webpack configuration?

After trying everything with the latest stable releases to no avail, I was able to get everything up and running with a modified version of @ScottLNorvell 's solution.

I used the same versions (contrib-hls: 5.4.1, video.js: 5.19.2) and the following lines are all I have in regards to video.js in my webpack conf:

resolve: {
    alias: {
        'videojs-contrib-hls': path.resolve(__dirname, 'node_modules/videojs-contrib-hls/dist/videojs-contrib-hls.js'),
    }
},
plugins: [
    new webpack.ProvidePlugin({
        'window.videojs': 'video.js/dist/video.js',
    }),
]

I then simply require('videojs-contrib-hls'); and what do ya know, no more Code 4 errors and I can read, and most likely play, .m3u8 playlist.

Only one small problem, my cookies are not being sent with the request. I can generate a signed url and access the playlist, unfortunately, the subsequent requests fail of course so I haven't gotten to test playback yet.

@GJordan904 I had same problem I solved I solved using this

videojs(video, {html5: {
  hls: {
    withCredentials: true
  }
}});

Man this is a bit of a headache.. :(
Any fix for using uglify? I'm getting these errors
e is not defined
and/or
Unexpected token {

This Uglify issue was already fixed in Uglify 3.0.17, but Webpack's uglifyjs-webpack-plugin does not support Uglify JS 3 yet.

My solution was to downgrade uglifyjs-webpack-plugin and webpack for now, to versions before the breaking change.

// package.json
{
    "uglify-js": "2.7.5",
    "uglifyjs-webpack-plugin": "0.2.2",
    "webpack": "2.2.1"
}
jou commented

I've convinced videojs-contrib-hls to work with Webpack and Uglify by using the dist file and imports-loader to define global as undefined. This causes the check for global (which causes the t is not defined thingie) to be short circuited and everything seems to be working so far:

// webpack.config.js

resolve: {
    alias: {
        'videojs-contrib-hls': 'videojs-contrib-hls/dist/videojs-contrib-hls',
    }
},
plugins: [
    new webpack.ProvidePlugin({
        'videojs': 'video.js',
        'window.videojs': 'video.js',
    }),
]

// videojs-with-plugins.js (we have a wrapper module that loads video.js plugins and set up the strings we use)

import videojs from 'video.js'

// If you're not using `webpack.ProvidePlugin` anyways, you can also shim `videojs` here direcly
import 'imports-loader?global=>undefined!videojs-contrib-hls'

export default videojs

Browserify is dead. Please consider webpack only.

jide commented

Folks, there is a much much simpler solution.

Just require the dist bundle like this :

import 'videojs-contrib-hls/dist/videojs-contrib-hls.js';

You may need to make videojs global too :

import videojs from 'video.js';
window.videojs = videojs;
jide commented

The main entry in package.json should definitely point at the dist bundle imho.

@jide I try your solution but I have this error : Uncaught TypeError: Cannot read property 'EventTarget' of undefined

Did you add import 'videojs-contrib-hls/dist/videojs-contrib-hls.js'; on your React Component ? I'm a little lost...

This is my solution:

// webpack.config.js
{
  resolve: {
    alias: {
      'video.js$': 'video.js/dist/video.cjs.js',
      'videojs-contrib-hls': 'videojs-contrib-hls/dist/videojs-contrib-hls',
    },
  },

  plugins: [
    // Make videojs global
    new webpack.ProvidePlugin({
      videojs: 'video.js',
      'window.videojs': 'video.js',
    }),

    // Fix UglifyJsPlugin global
    new webpack.DefinePlugin({
      'typeof global': JSON.stringify('undefined'),
    }),
  ],
}

EDIT: Add fix for UglifyJsPlugin.

@moshest - your answer worked for me - thank you!

Here is the code I used in my actual application after including @moshest webpack config:

import videojs from 'video.js';

window.videojs = videojs;

// @see - https://github.com/videojs/videojs-contrib-hls/issues/600#issuecomment-321281442
require('videojs-flash');
require('videojs-contrib-hls');

// ... rest of my application

I've tried every solution described in this issue, and also http://docs.videojs.com/tutorial-webpack.html, but I always get VIDEOJS: ERROR: (CODE:4 MEDIA_ERR_SRC_NOT_SUPPORTED) No compatible source was found for this media error.

I use
video.js@6.2.5
videojs-contrib-hls@5.9.0
webpack@2.7.0

So....there is still no some fix is working??

I'm getting a different issue
_videoJs.EventTarget is not a constructor in playlist-loader

This applies to dist and es5 way of including hls plugin

Making videojs global has no effect, it seems require('video.js') in playlist-loader is returning {default: ...} object instead of videojs itself

Anybody has this problem?

jide commented

Oh my... This is driving me nuts. My own solution does not seem to work anymore.

I now have the same issue as @AndrewKirkovski.

There is so much confusion, a dozen solutions here + instructions here, each trying to solve a different issue.

Here is a list of the different issues discussed here :

  • webworkify causes uglifyjs error (also makes nwb production build break)
  • videojs global
  • package.json "main" field not pointing to the dist bundle
  • videojs dep returning "default"

Willing to help making sense of all this, but confused atm :

  • Are there compatibility issues with videojs versions here ?
  • Why doesn't main point to a bundled file ?
  • Why is the videojs global needed ?

I started getting the same problem that @correju ran into:

Uncaught ReferenceError: n is not defined

When I run my project through webpack using uglify. After some googling, it seems that there is another project, react-mapbox-gl has this problem as well. The issue they came up with is documented here:

mishoo/UglifyJS#2011

In order to get rid of the error, I had to add the following option to my uglify plugin:

{ 
  compress: {
    comparisons: false,
  },
}

That option is documented here:

https://github.com/mishoo/UglifyJS2#compress-options

My uglify plugin in my webpack config looks like this now:

// webpack.config.js
{
  // other webpack config options
  plugins: [
    // other plugins
    new webpack.optimize.UglifyJsPlugin({
      compress: {
        comparisons: false,
        // other uglify compress options
      },
    }),
  ],
}

So, all in all, I had to implement the following:

  • the compress option from this comment (above)
  • all options from this comment: #600 (comment)
  • everything from my previous comment: #600 (comment)

Hope this helps!

@AndrewKirkovski @jide - are you trying to create a package that utilizes video js, then import your package in another project?

I ask because I got the error you describe in that scenario. If that is the problem you're running into, here is how I was able to fix it:

// webpack.config.js
{
  output: {
      library: {
        root: 'myCustomPlayer',
        amd: 'myCustomPlayer',
        commonjs: 'myCustomPlayer',
      },
      libraryTarget: 'umd',
  },
}

See https://webpack.js.org/guides/author-libraries/

kenju commented

Hi all,

Would anyone publish the working sample repository? ๐Ÿ™

There are so many workarounds here, and I really appreciate that. However the specific versions of libraries (webpack, videojs, videojs-contrib-hls, etc) are also important, still each workarounds are missing them. That is why a bunch of workarounds have sprung up but no one still finds the best solution.

Then we can figure out which workarounds work with which library versions, whose are noted in the package.json.

(I personally hope someone write a working repo with webpack v2 version, not v1)

jide commented

For me, the only working combination is @lionxcr answer #600 (comment), with exactly the versions used (they are mentioned at the end of the comment). Which is sad, because I could not make this work with newer releases.

And if you also need to support youtube with this, you need to use videojs-youtube@2.2.0.

jide commented

So, I decided to give https://github.com/benjipott/videojs-hlsjs a try, and it works well. So I thought you should know.

The fun thing is it needs some webpack tricks too, but it was much easier: SRGSSR/videojs-hlsjs#4

And from my early testing, it works better (seeking is faster for example).

After 2 days of trying different solutions to get this running with webpack and react I finally found a simple solution which does not require any change to the webpack config file.

  1. npm install expose-loader --save
  2. import videojs and videojs-contrib-hls as follow
import "expose-loader?videojs!../node_modules/video.js/dist/video.js";
import "../node_modules/videojs-contrib-hls/dist/videojs-contrib-hls.js";

Tested with:
video.js 6.2.7
videojs-contrib-hls 5.11.0

@jide what does your client code look like with videojs-hlsjs? I tried the details on your linked issue but I have the same code 4 error.

Not having luck with the other solutions in this package. I get the library to load correctly, but I get the Code 4 error consistently.

jide commented

@gregorskii like this:

import videojs from 'video.js';
import 'videojs-hlsjs';

const player = videojs(node, { techOrder: ['hlsjs', 'html5'] });

@jide Thanks for this. I did not know about the techOrder. I added that and I can more clearly see the issue. videojs-hls sets the global videojs value with the correct techOrder, but it's not available outside of the videojs-hls module scope.

My output in the console ends up being this:

screenshot 2017-10-11 15 46 56

Inside the videojs-hlsjs plugin I consoled window.videojs, window.Hls, and window.videojs.options.

Inside the plugin everything is correct, the tech order gets set, outside its the original videojs that I imported in my module.

I don't want to harp too much on videojs-hlsjs as it's not this plugin, but what do you think?

Similar to @drexseoj this finally appears to be registering:

alias: {
      'video.js': 'video.js/dist/video.js',
      'videojs-contrib-hls': 'videojs-contrib-hls/dist/videojs-contrib-hls.js',
    }
{
  test: /video.js$/,
  use: {
    loader: 'expose-loader',
    query: 'videojs'
  }
},
{
  test: /videojs-contrib-hls$/,
  use: {
    loader: 'imports-loader',
    query: 'video.js'
  }
},
import videojs from'video.js';
import 'videojs-contrib-hls';
console.log(window.videojs);

screenshot 2017-10-11 16 43 06

jide commented

@gregorskii So everything's fine now ?

Ya, appears to be working with this plugin.

jide commented

If you have errors using ProvidePlugin, be aware that it does not actually expose the module on window, it mimics it, that's why when having some complex setups, exposed modules won't be on window object.

See this comment: https://stackoverflow.com/a/39891365/302731

That's why using expose-loader works in these cases, as @drexseoj said.

I got a running solution with the uglifyJS issue (Unexpected token {):

package.json

"video.js": "^6.2.8",
"videojs-contrib-hls": "^5.12.0",
"webpack": "1.14.0"

webpack.config.js

// plugins
new webpack.ProvidePlugin({'window.videojs': 'video.js'}), 
new webpack.optimize.UglifyJsPlugin({
  mangle: true,
  comments: false,
  compress: {warnings: false}
})

MyVideo.jsx

import videojs from 'video.js'

// react class
componentDidMount() {
    require('videojs-contrib-hls/dist/videojs-contrib-hls.min')
}

Combining inputs from comment and videojs guide I was able to make it work with react-babel-webpack project:

webpack: "^3.4.1"
babel: "^6.5.2"

yarn add video.js@6.2.8
yarn add videojs-contrib-hls@5.11.0

Webpack config:

plugins = [ 
  new webpack.ProvidePlugin({
    videojs: "video.js",
   "window.videojs": "video.js"
  })
],

module:{
  loaders: [
    {
      test: /\.(png|woff|woff2|eot|ttf|svg)$/,
      loader: 'url-loader?limit=100000',
    }
  ]
}

resolve: {
  alias: {
    webworkify: 'webworkify-webpack-dropin',
    'videojs-contrib-hls': 'videojs-contrib-hls/dist/videojs-contrib-hls.min.js'
  }
}

React component:

import React from 'react';
require('video.js/dist/video-js.css');
import 'videojs-contrib-hls';

class Videojs extends React.Component{
  componentDidMount() {
    this.player = window.videojs(this.videoNode, {});
  }
  render(){
    return(
      <video ref={ node => this.videoNode = node } controls className="video-js vjs-default-skin">
        {/*
          <source src="/media/arjun/ABC4121123424.mp4" type="video/mp4" />
        */}
        <source src="/media/arjun/31_TEST.m3u8" type="application/x-mpegURL" />
      </video>
    )
  }
}
export default Videojs;

We can also lazy load this component to the app.

Thanks @lionxcr ! ๐Ÿ˜„

Edit

Even though above method worked in dev environment, when running webpack in production mode(webpack -p) or when we pass the bundle to uglify, the output file will throw a syntax error while loading as mentioned in this comment

Ended up using https://github.com/Peer5/videojs-contrib-hls.js which uses hls.js.

Thanks @rparjun :)
I managed to make it work with your webpack config on AngularJS.
The only mystery remaining is that I have to console.log(HLS) before using it. Yes, sounds very strange :)

import * as HLS from 'videojs-contrib-hls';
require('!style-loader!css-loader!video.js/dist/video-js.css');
export function VideoController(...) {
  let player,
       $video = $element.find('video');

function onInit() {
        console.log(HLS); //if I remove this HLS is not loaded.
        const options = {};
        player = videojs($video[0], options);

        player.src({
            src:'https://s3.amazonaws.com/_bc_dml/example-content/bipbop-advanced/bipbop_16x9_variant.m3u8',
            type: 'application/x-mpegURL'
        });
        player.play();

}

Any ideas to solve this ?

@alexandrzavalii Please check the edits in my comment, the config may not work in production environment.

I've done a lot of digging and it seems there is no reliable solution while webworkify-webpack-dropin is used. Problem with that module is that is searches for webpack modules by toString() of default export and matches whatever comes first. (See potentialFnModuleIds.find logic)

Default export can be as simple as function(t){ new d(t)} I've encountered situation where 2 modules has exactly same minified string for default export function. So sometimes it work, sometimes it doesn't and that depends on how minification behaves and if you use other minified dependencies.

webworkify-webpack is using searching by moduleId since v2 and that works reliably. Unfortunately it is no longer a drop in replacement as needs usage modifications i.e. require.resolve instead of regular require\import

I've ended up using own hacked webworkify-webpack-dropin version that is better aware of what's it is looking for and has function name regexp patched. If I manage to make it less hacky I'll post it somewhere.

For what it's worth, I started working on a new project for a client and wanted to investigate if I needed to change anything up, and I decided to test out the regular 'videojs-contrib-hls' and was getting all of those same fun problems. Instead I followed @rparjun and his comment above to use https://github.com/Peer5/videojs-contrib-hls.js and everything worked right out of the box. I haven't compiled a production webpack build yet, but I'm feeling good about that.

@MCDELTAT I am using the same in some production environments from December and no issues until now. ๐Ÿ˜ƒ

I've got some (hopefully) good news for you all. I've created webwackify, which is basically the webworkify and webworkify-webpack-dropin projects combined into a single module. I've got an experimental build of videojs-contrib-hls using this project and it can be bundled with browserify and webpack with no extra config options as seen in this example project.

However, this example is extremely basic so I was hoping some of you could try out this build without the tricks mentioned in this thread and see if it resolves the issues you are having. If successful we can bring this in upstream.

The build has been published under the qa tag as version 5.12.3-rc-1, and you can install with

npm install videojs-contrib-hls@qa

or you can specify the version directly in package.json

"videojs-contrib-hls": "5.12.3-rc-1"

Has anyone been able to give the build in my previous comment a try? Would really appreciate any feedback on whether it works in any of your custom builds or what breaks.
Pinging a few people that have been active recently @rparjun @MCDELTAT @AndrewKirkovski @brainthinks @jide @gregorskii

@mjneil Thanks ๐Ÿ˜ƒ
I will take a look into it this weekend and let you know.

Hi @mjneil , videojs-contrib-hls@qa is working fine. I was able to verify it with multiple streams, all looks good. ๐ŸŽ‰

@mjneil
Big thanks!
Tested thoroughly , all works
Finally we have a clean solution!

@mjneil I have tested it with a Laravel Mix / VueJS setup and it works like a charm! Thanks ๐Ÿ˜ƒ

Thank you @rparjun @alexandrzavalii and @kapersoft for testing it out and confirming it works. v5.13.0 of videojs-contrib-hls has been released that include these fixes! Anyone looking to support webpack should upgrade to 5.13.0 and should be able to include the project without extra webpack configuration.

I am closing this issue as resolved. Please reopen the issue or create a new one if you experience any issues after updating.

@mjneil Thanks ๐Ÿ˜„

@mjneil thanks for the awesome effort. FYI, with v5.13.0 I'm still getting the unexpected identifier issue Anyone else have that problem?

@ffischetti I have tested v5.13.0 with my Laravel Mix / VueJS setup and didn't experience any problems.

@ffischetti do you import videojs-contrib-hls/dist/videojs-contrib-hls.min or videojs-contrib-hls ?

i have webpack + react + videojs + videojs-contrib-hls and with latest version everything works fine

do you still have any "hacks" left maybe?

Thanks @thecotne

I'm doing: import 'videojs-contrib-hls,' as when I try to import videojs-contrib-hls/dist/videojs-contrib-hls.min, I get the following error: videojs-contrib-hls.min.js:2 Uncaught TypeError: Cannot read property 'EventTarget' of undefined

https://github.com/Peer5/videojs-contrib-hls.js works fine. But video-js-contrib-hls throws the unexpected token '{' error.

FYI, the app is bootstrapped with create-react-app.

@ffischetti videojs-contrib-hls.js is completely different package and what i am saying is that this package videojs-contrib-hls works for me and maybe you are doing something wrong

if you import like this

import 'videojs-contrib-hls'
import videojs from 'video.js'

it should work (works for me)