react-router4 + webpack Code Splitting

本文介绍了如何在React Router 4项目中实施代码分割,以减少首屏加载时间并提升用户体验。通过webpack配置和自定义组件实现按需加载,有效利用浏览器缓存。

项目升级为react-router4后,就尝试着根据官方文档进行代码分割。https://reacttraining.com/react-router/web/guides/code-splitting

在实际项目中,js,css文件默认通过webpack打包的话会很大,动不动就好几兆。

在实际场景中,我们需要缩短首屏的时间展现时间,需要将 首屏没有 涉及到 其他页面的 业务和组件 进行代码分离,按需加载。

通过按需加载,如果只是修改了某个页面的逻辑,也不用整个项目文件加载,增加了浏览器缓存的利用

下面就一步一步的介绍在我的项目中是怎么实现Code Splitting的。

根据webpack文档 https://webpack.js.org/guides/code-splitting/ 推荐的代码分割的方式是  import(), 当然 require.ensure() 作为兼容,还是支持的。

而react-router4 文档上说到的 bundle-loader 组件就是通过 require.ensure 实现的。

实际项目中

a.太小的文件打个包也没有太大的意义,最终考虑的是 每个一级菜单 作为分割点进行打包加载.

b.能够通过参数配置 分割打包 还是 整体打包,尽可能的在webconfig中进行配置,可以参数化

c.打包文件名字要有意义,每次打包只是某个module文件修改的话,不会影响其他js文件hash值,提高缓存利用

 

下面介绍下最终的结果,其中有些坎坷的心路历程,只能简单的略过了

1./router/moduleA.router.jsx,把需要打包在一起的文件整理到对用的文件下,方便统一管理

2.webpack.config.js

output: {
        //[chunkhash:8] 设置文件摘要,用于缓存
        filename: '[name].[chunkhash:8].bundle.js', //entry 对用生成文件的文件名规则
        chunkFilename : '[name].[chunkhash:8].js',  //不是entry定义的文件(分离打包的模块文件,提取的共同文件),对用生成文件的文件名规则
        path: TARGET,
        publicPath: '/public/'
    },
    plugins: [
        //...
        //...
        //** 设置打包id生成规则,以文件地址 + hash 形式,是生成的  webpack 模块id固定,参见参考文献
        new webpack.HashedModuleIdsPlugin(),
        //提取的共同文件插件配置
        new webpack.optimize.CommonsChunkPlugin({
            //在模块中如果存在的功用的话,也进行提取设置
            //如moduleA,moduleB 中都用了编辑器,entry中没有,则会抽出公用打包在一个  数字.hash.js 中
            async: true, 
            minChunks: 2 //有2处使用的js文件就提取
        }), 
        //vendor: entry文件中用到的共用文件打包在vendor文件
        //** manifest: 增加这个配置,则把一个加载的id信息统一到一个文件,这样就可以实现每次打包未改的文件生成的hash不变,参见参考文献
        new webpack.optimize.CommonsChunkPlugin({
            names: ['vendor', 'manifest']
        }),
        //对应的 chunks 加上 'manifest', 'vendor'
        new HtmlWebpackPlugin({
            filename: `${page.name}.html`,
            template: `${ROOT_PATH}/template.ejs`,
            chunks: ['manifest', 'vendor', page.name]
        }
    ],
    module: {
        rules: [{
                test: /\.router\.jsx/,
                loader: [
                    //根据文件后缀.router.jsx 设置规则,主要是name 和 regExp 的实现,这个可以查看bundle-loader源代码就能发现相关的支持
                    //现在的逻辑是取文件名,/router/moduleA.router.jsx 则打包成 moduleA.hash.js
                    'bundle-loader?lazy&name=[1]&regExp=([^\\\\\\/]*)\\.router\\.jsx',
                    'babel-loader',
                ],
                exclude: /node_modules|assets/
            }, {
                test: /\.jsx?$/,
                loader: 'babel-loader',
                exclude: /node_modules|assets/
            }
        ]
    },
bundle-loader name参数,regExp参数的应用是查看的源代码,一开始想看看是通过什么实现异步加载,就看见了相关插件的源代码
require.ensure(),想要打包的文件打包在一起,只需要下面代码中的 chunkNameParam 设置成同一个值就可以了,
实际情况考虑到更好的管理文件,就通过取.router.jsx前面的文件名 进行命名

  

 3.Bundle.jsx

 1 import React, { Component } from 'react'
 2 import { Route } from 'react-router-dom';
 3 const Loading = function () {
 4     return <div></div>
 5 }
 6 //注意props的传递,在组件与Switch,嵌套的时候会有涉及
 7 //增加lazyKey属性,对应moduleA.router.jsx对应的key值
 8 class Bundle extends Component {
 9     state = {
10         mod: null
11     }
12     componentWillMount() {
13         this.load(this.props)
14     }
15     componentWillReceiveProps(nextProps) {
16         if (nextProps.load !== this.props.load) {
17             this.load(nextProps)
18         }
19     }
20     load(props) {
21         var key = props.lazyKey || 'default';
22         this.setState({
23             mod: null
24         })
25         props.load(mod => {
26             this.setState({
27                 mod: mod[key] ? mod[key] : mod
28             })
29         })
30     }
31     render() {
32         return this.state.mod?<this.state.mod {...this.props} />:<Loading/>
33     }
34 }
35 //注意props的传递,在组件与Switch,嵌套的时候会有涉及
36 //通过isLazy进行是否分离打包配置,LazyRoute组件不是必要的,各自需求各自处理
37 class LazyRoute extends React.PureComponent{
38     componentMap = {};
39     render() {
40         let {menu, ...props} = this.props;
41         let {component, isLazy, componentKey, path} = menu;
42         componentKey = componentKey || 'default';
43         if (!isLazy) {
44             return (<Route component={component[componentKey] || component} {...props}/>);
45         } else {
46             //通过this.componentMap进行缓存,防止不必要的组件重新加载
47             if (!this.componentMap[path]) {
48                 this.componentMap[path] = function(props)  {
49                     return (<Bundle load={component} lazyKey={componentKey} {...props}></Bundle>)
50                 }
51             }
52             return (<Route component={this.componentMap[path]} {...props}/>);
53         } 
54     }
55 }
56 export {Bundle as default, LazyRoute}

 

实际的打包效果,还是可以的,代码得到了分离。有些地方还可以优化,比如 第3方lib包不怎么会变的,和 自己写的组件 进行不同的提取合并。文献中都有提及。

极致的按需加载 和 异步加载,对代码 组件了解的要求比较高,现在主要还是通过webpack 公共提取 做基本的优化

 

参考文件

http://geek.youkuaiyun.com/news/detail/135599    使用 Webpack 打包单页应用的正确姿势

https://sebastianblade.com/using-webpack-to-achieve-long-term-cache/   用 webpack 实现持久化缓存

 

转载于:https://www.cnblogs.com/legu/p/7251562.html

一、数据采集层:多源人脸数据获取 该层负责从不同设备 / 渠道采集人脸原始数据,为后续模型训练与识别提供基础样本,核心功能包括: 1. 多设备适配采集 实时摄像头采集: 调用计算机内置摄像头(或外接 USB 摄像头),通过OpenCV的VideoCapture接口实时捕获视频流,支持手动触发 “拍照”(按指定快捷键如Space)或自动定时采集(如每 2 秒采集 1 张),采集时自动框选人脸区域(通过Haar级联分类器初步定位),确保样本聚焦人脸。 支持采集参数配置:可设置采集分辨率(如 64480、1280×720)、图像格式(JPG/PNG)、单用户采集数量(如默认采集 20 张,确保样本多样性),采集过程中实时显示 “已采集数量 / 目标数量”,避免样本不足。 本地图像 / 视频导入: 支持批量导入本地人脸图像文件(支持 JPG、PNG、BMP 格式),自动过滤非图像文件;导入视频文件(MP4、AVI 格式)时,可按 “固定帧间隔”(如每 10 帧提取 1 张图像)或 “手动选择帧” 提取人脸样本,适用于无实时摄像头场景。 数据集对接: 支持接入公开人脸数据集(如 LFW、ORL),通过预设脚本自动读取数据集目录结构(按 “用户 ID - 样本图像” 分类),快速构建训练样本库,无需手动采集,降低系统开发与测试成本。 2. 采集过程辅助功能 人脸有效性校验:采集时通过OpenCV的Haar级联分类器(或MTCNN轻量级模型)实时检测图像中是否包含人脸,若未检测到人脸(如遮挡、侧脸角度过大),则弹窗提示 “未识别到人脸,请调整姿态”,避免无效样本存入。 样本标签管理:采集时需为每个样本绑定 “用户标签”(如姓名、ID 号),支持手动输入标签或从 Excel 名单批量导入标签(按 “标签 - 采集数量” 对应),采集完成后自动按 “标签 - 序号” 命名文件(如 “张三
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值