videojs / videojs-contrib-hls

HLS library for video.js
http://videojs.github.io/videojs-contrib-hls/
Other
2.84k stars 793 forks source link

Support for webpack? #600

Closed hanfeisun closed 6 years ago

hanfeisun commented 8 years ago

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?

correju commented 7 years ago

Can you send your webpack configuration?

ghost commented 7 years ago

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.

correju commented 7 years ago

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

videojs(video, {html5: {
  hls: {
    withCredentials: true
  }
}});
Logic-Punch commented 7 years ago

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 {

VadimBrodsky commented 7 years ago

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 7 years ago

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
zcoding commented 7 years ago

Browserify is dead. Please consider webpack only.

jide commented 7 years ago

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 7 years ago

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

latelt-j commented 7 years ago

@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...

moshest commented 7 years ago

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.

brainthinks commented 7 years ago

@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
mkhazov commented 7 years ago

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

markisme commented 7 years ago

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

AndrewKirkovski commented 7 years ago

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 7 years ago

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 :

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

brainthinks commented 7 years ago

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:

https://github.com/mishoo/UglifyJS2/issues/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:

Hope this helps!

brainthinks commented 7 years ago

@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 7 years ago

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 7 years ago

For me, the only working combination is @lionxcr answer https://github.com/videojs/videojs-contrib-hls/issues/600#issuecomment-273289790, 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 7 years ago

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: https://github.com/SRGSSR/videojs-hlsjs/issues/4

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

drexseoj commented 7 years ago

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

gregorskii commented 7 years ago

@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 7 years ago

@gregorskii like this:

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

const player = videojs(node, { techOrder: ['hlsjs', 'html5'] });
gregorskii commented 7 years ago

@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?

gregorskii commented 7 years ago

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 7 years ago

@gregorskii So everything's fine now ?

gregorskii commented 7 years ago

Ya, appears to be working with this plugin.

jide commented 7 years ago

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.

trinonsense commented 7 years ago

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')
}
rparjun commented 7 years ago

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 ! :smile:

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.

alexandrzavalii commented 7 years ago

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 ?

rparjun commented 6 years ago

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

AndrewKirkovski commented 6 years ago

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.

MCDELTAT commented 6 years ago

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.

rparjun commented 6 years ago

@MCDELTAT I am using the same in some production environments from December and no issues until now. :smiley:

mjneil commented 6 years ago

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"
mjneil commented 6 years ago

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

rparjun commented 6 years ago

@mjneil Thanks :smiley: I will take a look into it this weekend and let you know.

rparjun commented 6 years ago

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

alexandrzavalii commented 6 years ago

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

kapersoft commented 6 years ago

@mjneil I have tested it with a Laravel Mix / VueJS setup and it works like a charm! Thanks :smiley:

mjneil commented 6 years ago

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.

rparjun commented 6 years ago

@mjneil Thanks :smile:

ffischetti commented 6 years ago

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

kapersoft commented 6 years ago

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

thecotne commented 6 years ago

@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?

ffischetti commented 6 years ago

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.

thecotne commented 6 years ago

@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

thecotne commented 6 years ago

if you import like this

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

it should work (works for me)