Webpack 3 locates .mp4 file but video is not playable

ihodonald picture ihodonald · Aug 12, 2017 · Viewed 8.6k times · Source

Webpack 3 locates .mp4 file but video is not playable

Clone this project on GitHub

I've created an animation in Adobe's new Animate CC and exported it as an .mp4 file

In my webpack.config.js file, I stated that the file-loader should be used to load my .mp4 file like so:

webpack.config.js

  {
    test: /\.(mov|mp4)$/,
    use: [
      'file-loader'
    ]
  }

(You can find my webpack.config.js source code below)

So why, when I run webpack (or rather locally, webpack as an npm script)

package.json

"build:dev": "webpack --watch",

does the browser locate the .mp4 file

index.html

<video loop autoplay controls>
  <source id="arrows" src="c31...random_hash...1611.mp4" type="video/mp4">
</video>

but not play it?

Other things I've tried

  • setting the video tag's src attribute in JavaScript
  • placing the video file next to the index.html in the same directory
  • Using a different format (.mov)

Here is my source code:

webpack.config.js

const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const ExtractTextPlugin = require('extract-text-webpack-plugin');
const webpack = require('webpack');

module.exports = {
  entry: './src/js/main.js',
  output: {
    filename: 'bundle.js',
    path: path.resolve(__dirname, 'dist')
  },
  devtool: 'inline-source-maps',
  devServer: {
    contentBase: './dist',
    port: 3033
  },
  module: {
    rules: [
      {
        test: /\.html$/,
        use: [
          'html-loader'
        ]
      },
      {
        test: /\.scss$|\.css$/,
        use: ExtractTextPlugin.extract({
            fallback: "style-loader",
            use: ["css-loader", "sass-loader"]
        })
      },
      {
        test: /\.(png|svg|jpg|gif)$/,
        use: [
          'file-loader'
        ]
      },
      {
        test: /\.(woff|woff2|eot|ttf|otf)$/,
        use: [
          'file-loader'
        ]
      },
      {
        test: /\.(mov|mp4)$/,
        use: [
          'file-loader'
        ]
      },
      {
        test: /\.(mov|mp4)$/,
        use: [
            'url-loader'
        ]
      }
    ]
  },
  plugins: [
    new HtmlWebpackPlugin({
      template: 'src/html/index.html',
      favicon: 'src/images/icon.png'
    }),
    new ExtractTextPlugin('styles.css'),
    new webpack.ProvidePlugin({
        $: "jquery",
        jQuery: "jquery"
    })
  ],
  resolve: {
        alias: {
            jQuery: "src/js/jquery",
            $: "src/js/jquery"
        }
    }
}

main.js

import mov from '../media/arrows.mp4';

function render_arrows() {
  var vidtag;
  vidtag = document.getElementById('arrows');
  vidtag.src = mov;
}

render_arrows();

As I mentioned earlier, you could also clone this project on GitHub.

Answer

ihodonald picture ihodonald · Aug 12, 2017

Specify output file name in webpack.config.js

  1. View the Wepback Documentation: file-loader

  2. Here is what your loader should look like:

    {
      test: /\.(mov|mp4)$/,
      use: [
        {
          loader: 'file-loader',
          options: {
            name: '[name].[ext]'
          }  
        }
      ]
    }
    

    Important!

    You must also import your videos into your main.js file like so:

    main.js

    import video_2 from '../media/video_1.mp4';
    import video_1 from '../media/video_2.mov';

  3. Now, in index.html (inside your src/ directory), you can set the src attribute of your video tag to a relative path that would point to your video when it loads into the dist/ directory.
    Your path should look something like this:

        <video loop autoplay controls>
          <source src="./video_1.mp4" type="video/mp4">
        </video>
    
  4. Now run npm run build or npm run build:dev

You can optionally specify a path like so:

webpack.config.js

    {
      test: /\.(mov|mp4)$/,
      use: [
        {
          loader: 'file-loader',
          options: {
            name: '[path][name].[ext]'
          }  
        }
      ]
    }

Update

You can also use a CDN to deliver your video. Simply set the src of your video element to a URL.

ie.

src="https://cloudflare.com/?user=574983038&video=cat.mp4"

If you don't want to pay for a CDN, you can always just use a remote server. I realize that also costs money, but chances are, you probably already have one. Just make sure you have CORS set to deliver to your website:

Example using PHP

header("Access-Control-Allow-Origin: *");
header("Access-Control-Allow-Methods: GET, POST");

Since NodeJS has become very popular, this is probably the best method of delivery anyways. As of today (5/11/19), if you try to load your video from a relative path inside your component from a NodeJS server whilst making a GET request to any path other the root directory, it won't be able to find your file. For example, if you have a video located at https://example.com/videos/593020, and someone makes a GET request to that URL, your video won't load because NodeJS won't know where to find it.

I could be wrong. You might be able to load it by importing it somewhere else. What I do know is that Node attempts to get your video from whatever path you specify using the path of window.location.href. Using a CDN is much easier.