美文网首页vue+webpack项目实战开发大前端
EasyDSS高性能流媒体服务器前端重构(五)- webpack

EasyDSS高性能流媒体服务器前端重构(五)- webpack

作者: penggy | 来源:发表于2017-09-13 11:14 被阅读62次

    为了让页面更快完成加载, 第一时间呈现给客户端, 也为了帮助客户端节省流量资源, 我们可以开启 vue-router 提供的按需加载功能, 让客户端打开页面时, 只自动加载必要的资源文件, 当客户端操作页面, 切换功能模块, 触发页面路由变化时, 再去加载相应需要的资源.

    本系列博客的前面几篇一直在讲利用 webpack + vue 开发多页面前端, 然而多页面并不是利剑所指. 本篇将重点介绍使用 vue-router 开发单页面前端, 并且实现按需加载的效果.

    关于 vue-router 的按需加载, 官方的文档点这里, 这篇博客主要是根据文档的内容, 结合实例代码, 按步骤,把需要的操作过一遍, 如果你觉得文档描述不够细节, 可以往下看看.

    下面, 我们基于 blog_4 的代码 , 把它改造成按需加载的单页面.

    安装 vue-router

    npm i vue-router -D
    

    修改 webpack.config.js 配置

    修改 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']
        },
        output: {
            path: resolve('dist'), // 指示发布目录
            chunkFilename: 'js/[name].[chunkhash:8].js',
            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
                }
            })
        ]
    };
    

    只保留一个 entry, 一个 HtmlWebpackPlugin
    在 output 中添加 chunkFilename 属性, 以对按需加载的 js 文件命名

    新建路由文件

    add src/router.js

    import Vue from 'vue'
    import Router from 'vue-router'
    import AdminLTE from 'components/AdminLTE.vue'
    
    import Index from 'components/Index.vue'
    // import Player from 'components/Player.vue'
    const Player = () => import(/* webpackChunkName: 'player' */ 'components/Player.vue')
    const About = () => import(/* webpackChunkName: 'about' */ 'components/About.vue')
    
    Vue.use(Router);
    
    const router = new Router({
        routes: [
            {
                path: '/',
                component: AdminLTE,
                children: [
                    {
                        path: '',
                        component: Index
                    }, {
                        path: 'player',
                        component: Player
                    }, {
                        path: 'about',
                        component: About
                    }
                ]
            }
        ],
        linkActiveClass: 'active'
    })
    
    export default router;
    

    / --> Inex 直接加载
    /player --> Player 懒加载
    /about --> About 懒加载

    其中, Player 和 About 两个组件以按需加载的方式的引入, 区别于 Index, 注意文件开始部分, import 的写法, 就是 vue-router 官方文档中 懒加载 部分的写法

    改造入口文件

    src/index.js

    import Vue from 'vue'
    import store from 'src/store'
    import router from 'src/router'
    
    new Vue({
      el: '#app',
      store,
      router,
      template: `
      <transition>
        <router-view></router-view>
      </transition>`
    })
    

    router-view 标签用于占位路由指向的目标组件

    修改 Sider 为路由导航

    components/Sider.vue

    <template>
      <aside id="slider" class="main-sidebar">
        <section class="sidebar">
          <ul class="sidebar-menu">
              <router-link class="treeview" v-for="(item,index) in menus" :key="index" tag="li" :exact="item.path == '/'" :to="item.path">
                <a>
                  <i :class="['fa', 'fa-' + item.icon]"></i>
                  <span>{{item.text}}</span>
                </a>
              </router-link>
          </ul>
        </section>
      </aside>
    </template>
    
    <script>
    export default {
      props: {
        menus : {
            default : () => []
        }
      }
    }
    </script>
    

    router-link 定义路由导航链接, 这里路由链接渲染为 li > a 的形式, 当前访问路径为 router-link 或者其子路由时, 该 router-link 自动触发为激活状态, 激活状态的 class name 可以通过 linkActiveClass 指定, 我们在前面的创建 router 的时候, 统一将其指定为 active

    如果只想让访问路径严格匹配路由时, 触发为激活状态, 即子路由激活时, 父路由不激活, 需要在父路由上使用 exact 标识. 这个选项, 常用于首页路由 /

    改造 AdminLTE.vue

    将原来的 slot 占位, 替换成 router-view 占位

    <template>
      <div class="wrapper">
        <NaviBar :logoText="logoText" :logoMiniText="logoMiniText"></NaviBar>
        <Sider :menus="menus"></Sider>
        <div class="content-wrapper">
          <section class="content">
            <transition>
              <router-view @btnClick="btnClick"></router-view>
            </transition>
          </section>
        </div>
      </div>
    </template>
    
    <script>
    import "font-awesome/css/font-awesome.css"
    import "admin-lte/bootstrap/css/bootstrap.css"  
    import "admin-lte/dist/css/AdminLTE.css"
    import "admin-lte/dist/css/skins/_all-skins.css"
    
    import "admin-lte/bootstrap/js/bootstrap.js"
    import "admin-lte/dist/js/app.js"
    
    import { mapState } from "vuex"
    import Vue from 'vue'
    
    import Sider from 'components/Sider'
    import NaviBar from 'components/NaviBar'
    
    export default {
      data() {
        return {
        }
      },
      mounted() {
        $(() => {
          $.AdminLTE.layout.fix();
        })
      },
      components: {
        NaviBar, Sider
      },
      computed: {
        //访问 vuex store 中的数据
        //此处用到 es6 stage-2 才有的三个点展开对象的语法, 对应 .babelrc 中的配置
        ...mapState([
          "logoText",
          "logoMiniText",
          "menus"
        ])
      },
      methods: {
        btnClick(msg){
          alert(msg);
        }
      }  
    }
    </script>
    
    

    运行程序, 看看效果

    npm run start
    
    懒加载效果

    如上图所示, 当首次点击 [HLS 播放器] 改变路由时, 从 Netwok 观察到加载 player.xxx.js , 表明懒加载开启成功

    代码位置: https://github.com/penggy/easydss-web-src/tree/blog_5

    相关文章

      网友评论

        本文标题:EasyDSS高性能流媒体服务器前端重构(五)- webpack

        本文链接:https://www.haomeiwen.com/subject/ybyksxtx.html