LiveQing 高性能流媒体服务器前端重构(四): webpack + video.js 打造流媒体服务器前端

video.js 介绍

Video.js - open source HTML5 & Flash video player

作为一款高性能流媒体服务器的前端, 必不可少会用到流媒体播放器. 在播放器的选择上, 我们选中了功能强大并且开源的 video.js . 它可以用来播放 RTMP/HLS 直播流.

本篇介绍在 webpack 中集成 video.js 播放器组件, 我们将要完成一个 HLS 播放器 的小例子. 先来看一下效果图吧:

LiveQing 高性能流媒体服务器前端重构(四): webpack + video.js 打造流媒体服务器前端_第1张图片
LiveQing 高性能流媒体服务器前端重构(四): webpack + video.js 打造流媒体服务器前端_第2张图片

安装 video.js

我们要开发的 HLS 播放器 需要用到 video.js 的一个官方插件: videojs-contrib-hls

尽管 video.js 官方文档中给出了 webpack 集成的说明(http://docs.videojs.com/tutorial-webpack.html), 但是在实际开发过程中, 我还是和其他人一样遇到了很多坑(https://github.com/videojs/videojs-contrib-hls/issues/600) 最后, 算是将 video.js 集成好, 却发现插放 HLS 流, 不能切换到 Flash 模式. 最终, 我决定采用外部依赖的方式集成 video.js, 正好借此熟悉一下 webpack externals 的用法. 这里介绍的也就是 “外部依赖法”.

既是"外部依赖法", 那我们首先把外部依赖的 video.js 文件准备好. 在 src 目录下新建 externals 目录, 把事先下载好的 video-js-5.19.2 目录文件拷贝到这里.

修改 template.html 如下:


    
        <%= htmlWebpackPlugin.options.title %>
        
        
        

        
        
        
                
    
    
        

修改 webpack.dll.config.js 如下:

const HtmlWebpackPlugin = require('html-webpack-plugin');
const CleanWebpackPlugin = require('clean-webpack-plugin');
const CopyWebpackPlugin = require('copy-webpack-plugin');
const webpack = require('webpack');
const path = require('path');

function resolve(dir) {
    return path.resolve(__dirname, dir)
}

module.exports = {
    entry: {
        //提取共用组件, 打包成 vendor.js
        vendor: ['jquery', 'vue', 'vuex', 'babel-polyfill',
            'font-awesome/css/font-awesome.css', 'admin-lte/bootstrap/css/bootstrap.css',
            'admin-lte/dist/css/AdminLTE.css', 'admin-lte/dist/css/skins/_all-skins.css',
            'admin-lte/bootstrap/js/bootstrap.js', 'admin-lte/dist/js/app.js']
    },
    output: {
        path: resolve('dll'),
        filename: 'js/[name].[chunkhash:8].js',
        library: '[name]_library'
    },
    resolve: {
        extensions: ['.js', '.vue', '.json'],
        alias: {
            'vue$': 'vue/dist/vue.common.js',
            'jquery$': 'admin-lte/plugins/jQuery/jquery-2.2.3.min.js'
        }
    },
    module: {
        rules: [{
            test: /\.css$/,
            loader: 'style-loader!css-loader'
        },
        {
            test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
            loader: 'url-loader?limit=10000&name=images/[name].[hash:8].[ext]'
        },
        {
            test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/,
            loader: 'url-loader?limit=10000&name=fonts/[name].[hash:8].[ext]'
        },
        {
            test: /\.(mp4|webm|ogg|mp3|wav|flac|aac)(\?.*)?$/,
            loader: 'url-loader?limit=10000&name=media/[name].[hash:8].[ext]'
        }]
    },
    plugins: [
        new webpack.ProvidePlugin({
            $: 'jquery',
            jQuery: 'jquery',
            "window.jQuery": 'jquery',
            "window.$": 'jquery'
        }),
        new CleanWebpackPlugin(['dll']),
        new CopyWebpackPlugin([
            { from: 'src/externals' }
        ]),
        new webpack.DllPlugin({
            path: resolve("dll/[name]-manifest.json"),
            name: "[name]_library",
            context: __dirname
        }),
        new HtmlWebpackPlugin({
            filename: 'template.html',
            title: '<%= htmlWebpackPlugin.options.title %>',
            inject: 'head',
            chunks: ['vendor'],
            template: './src/template.html',
            minify: {
                removeComments: true,
                collapseWhitespace: false
            }
        })        
    ]
};

引入 CopyWebpackPlugin 将 externals 目录下的外部依赖文件拷贝到 dll 目录, 最终, 这些外部依赖文件将被拷贝到发布目录下

修改 webpack.config.js 如下:

const HtmlWebpackPlugin = require('html-webpack-plugin');
const CleanWebpackPlugin = require('clean-webpack-plugin');
const CopyWebpackPlugin = require('copy-webpack-plugin');
const webpack = require('webpack');
const path = require('path');
require("babel-polyfill");

function resolve(dir) {
    return path.resolve(__dirname, dir)
}

module.exports = {
    //定义页面的入口, 因为js中将要使用es6语法, 所以这里需要依赖 babel 垫片
    entry: {
        index: ['babel-polyfill', './src/index.js'],
        player: ['babel-polyfill', './src/player.js'],
        about: ['babel-polyfill', './src/about.js']
    },
    output: {
        path: resolve('dist'), // 指示发布目录
        filename: 'js/[name].[chunkhash:8].js' //指示生成的页面入口js文件的目录和文件名, 中间包含8位的hash值
    },
    externals: {
        //video.js 作为外部资源引入
        'video.js': 'videojs'
    },
    //下面给一些常用组件和目录取别名, 方便在js中 import
    resolve: {
        extensions: ['.js', '.vue', '.json'],
        alias: {
            'vue$': 'vue/dist/vue.common.js',
            'jquery$': 'admin-lte/plugins/jQuery/jquery-2.2.3.min.js',
            'src': resolve('src'),
            'assets': resolve('src/assets'),
            'components': resolve('src/components')
        }
    },
    module: {
        //配置 webpack 加载资源的规则
        rules: [{
            test: /\.js$/,
            loader: 'babel-loader',
            include: [resolve('src')]
        }, {
            test: /\.vue$/,
            loader: 'vue-loader'
        }, {
            test: /\.css$/,
            loader: 'style-loader!css-loader'
        },
        {
            test: /\.less$/,
            loader: "less-loader"
        },
        {
            test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
            loader: 'url-loader?limit=10000&name=images/[name].[hash:8].[ext]'
        },
        {
            test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/,
            loader: 'url-loader?limit=10000&name=fonts/[name].[hash:8].[ext]'
        },
        {
            test: /\.(swf|mp4|webm|ogg|mp3|wav|flac|aac)(\?.*)?$/,
            loader: 'url-loader?limit=10000&name=media/[name].[hash:8].[ext]'
        }]
    },
    plugins: [
        //引入全局变量
        new webpack.ProvidePlugin({
            $: 'jquery',
            jQuery: 'jquery',
            "window.jQuery": 'jquery',
            "window.$": 'jquery'
        }),
        new webpack.DllReferencePlugin({
            context: __dirname,
            manifest: require('./dll/vendor-manifest.json')
        }),
        new CopyWebpackPlugin([
            { from: 'dll', ignore: ['template.html', 'vendor-manifest.json'] }
        ]),
        //编译前先清除 dist 发布目录
        new CleanWebpackPlugin(['dist']),
        //生成视频广场首页, 在这个页面中自动引用入口 index --> dist/js/index.[chunkhash:8].js
        //以 src/index.html 这个文件作为模板
        new HtmlWebpackPlugin({
            filename: 'index.html',
            title: '视频广场',
            inject: true, // head -> Cannot find element: #app
            chunks: ['index'],
            template: './dll/template.html',
            minify: {
                removeComments: true,
                collapseWhitespace: false
            }
        }),
        new HtmlWebpackPlugin({
            filename: 'player.html',
            title: 'HLS 播放器',
            inject: true,
            chunks: ['player'],
            template: './dll/template.html',
            minify: {
                removeComments: true,
                collapseWhitespace: false
            }
        }),
        //生成版本信息页面, 在这个页面中自动引用入口 about --> dist/js/about.[chunkhash:8].js
        //以 src/index.html 这个文件作为模板
        new HtmlWebpackPlugin({
            filename: 'about.html',
            title: '版本信息',
            inject: true,
            chunks: ['about'],
            template: './dll/template.html',
            minify: {
                removeComments: true,
                collapseWhitespace: false
            }
        })
    ]
};

重点是在 externals 块下面声明 videojs 作为外部资源使用
然后, 我们添加一个新的静态页面配置, 用做 HLS 播放器的入口

添加左侧菜单项

打开 src/store/index.js, 修改如下:

import Vue from "vue";
import Vuex from "vuex";

Vue.use(Vuex);

const store = new Vuex.Store({
    state: {
        logoText: "EasyDSS",
        logoMiniText: "DSS",
        menus: [
            {
                path: "/index.html",
                icon: "mouse-pointer",
                text: "视频广场"
            }, {
                path: "/player.html",
                icon: "play",
                text: "HLS 播放器"
            }, {
                path: "/about.html",
                icon: "support",
                text: "版本信息"
            }
        ]
    },
    getters : {

    },
    mutations: {

    },
    actions : {
        
    }
})

export default store;

编写HLS 播放器 页面

将 video.js 简单封装成组件, 新建 src/compontents/VideoJS.vue




封装 video.js api

编写播放器弹出框组件, 新建 src/components/VideoDlg.vue




封装 bootstrap 模态框

编写HLS播放器页面内容, 新建 src/components/Player.vue




这里顺带演示了 element-ui 的 Message 用法
点击播放按钮, 消息向父组件传递, 播放地址作为参数一起传递

编写入口 js , 新建 src/player.js

import Vue from 'vue'
import store from "./store";
import AdminLTE from './components/AdminLTE.vue'
import Player from './components/Player.vue'
import VideoDlg from './components/VideoDlg.vue'

new Vue({
  el: '#app',
  store,
  template: `
  
    
    
  `,
  components: {
    AdminLTE, Player, VideoDlg
  },
  methods: {
      play(video){
          this.$refs.videoDlg.play(video.videoUrl, video.videoTitle);
      }
  }
})

接收 Player 组件传来的播放消息, 打开播放器弹出框, 完成视频播放

运行

我们修改了 template.html 和 webpack.dll.config.js , 所以先要重新 build 共用组件库

npm run dll

然后

npm run start

WEB:www.liveqing.com

你可能感兴趣的:(LiveQing 高性能流媒体服务器前端重构(四): webpack + video.js 打造流媒体服务器前端)