[转] react-router4 + webpack Code Splitting

项目升级为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.csdn.net/news/detail/135599    使用 Webpack 打包单页应用的正确姿势

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

原文地址:https://www.cnblogs.com/chris-oil/p/8457528.html

时间: 2024-10-08 22:19:49

[转] react-router4 + webpack Code Splitting的相关文章

[Webpack 2] Maintain sane file sizes with webpack code splitting

As a Single Page Application grows in size, the size of the payload can become a real problem for performance. In this lesson, learn how to leverage code splitting to easily implement lazy loading for your application to load only the code necessary

webpack - code splitting

Code splitting is one of the most compelling features of webpack. This feature allows you to split your code into various bundles which can then be loaded on demand or in parallel. It can be used to achieve smaller bundles and control resource load p

webpack优化之code splitting

作为当前风头正盛的打包工具,webpack风靡前端界.确实作为引领了一个时代的打包工具,很多方面都带来了颠覆性的改进,让我们更加的感受到自动化的快感.不过最为大家诟病的一点就是用起来太难了. 要想愉快的使用,要使用n多的配置项,究其原因在于文档的不够详细.本身默认集成的不足.也不能说这是缺点吧,更多的主动权放给用户就意味着配置工作量的增加,这里就不过多探讨了.当历尽千辛万苦,你的项目跑起来之后,可能会发现有一些不太美好的问题的出现,编译慢.打包文件大等.那么,我们还要花些时间来看看怎么优化相关配

webpack 和 code splitting

Code Splitting指的是代码分割,那么什么是代码分割,webpack和code splitting又有什么样的联系呢? 使用npm run dev:"webpack-dev-server --config ./build/webpack.dev.js.",会看不到打包生成的dist目录. 所以我们使用一个新的,不要启用dev-server服务.使用npm run dev-build:"webpack --config ./build/webpack.dev.js&q

React +ES6 +Webpack入门

React +ES6 +Webpack入门 React已成为前端当下最热门的前端框架之一 , 其虚拟DOM和组件化开发让前端开发更富灵活性,而Webpack凭借它异步加载和可分离打包等优秀的特性,更为React的开发提供了便利.其优秀的特性不再赘述.本文将详细的记录react babel webpack的环境搭建,以及搭建的过程中遇到的一些坑. 一.新建React项目 1.如图为新建react项目结构,其中 entry.js放置react入口代码,index.js放置react组件代码,asse

There is an internal error in the React performance measurement code.Did not expect componentDidMount timer to start while render timer is still in progress for another instance

一.There is an internal error in the React performance measurement code.Did not expect componentDidMount timer to start while render timer is still in progress for another instance 二._this3._toDetail is not a function.(In ‘this3._toDetail()’,’_this3._

reactjs学习一(环境搭配react+es6+webpack热部署)

reactjs学习一(环境搭配react+es6+webpack热部署) reactjs今年在前端圈里很火,用了三四个月,感觉确实很适合前端开发人员使用,值得深入一下,所以这里记录一下我简单的学习过程,首先是react的环境,由于现在react的新版本已经很稳定了,所以推荐使用es6+webpack来搭建开发环境. 首先,安装nodejs,略过,安装gitbrach,略过,直接搜索到相对应软件的官网,下载最新正式版本的软件,然后就下一步下一步完成安装就可以了,很简单的过程,但是不容忽略,如有问题

React+ES6+Webpack深入浅出

React已成为前端当下最热门的前端框架之一 , 其虚拟DOM和组件化开发让前端开发更富灵活性,而Webpack凭借它异步加载和可分离打包等优秀的特性,更为React的开发提供了便利.其优秀的特性不再赘述.本文将详细的记录react babel webpack的环境搭建,以及搭建的过程中遇到的一些坑. 一.新建React项目 1.如图为新建react项目结构,其中 entry.js放置react入口代码,index.js放置react组件代码,assets文件是webpack打包之后生成文件的存

spring + spring mvc + mybatis + react + reflux + webpack Web工程例子

最近写了个Java Web工程demo,使用maven构建: 后端使用spring + spring mvc + mybatis: 前端使用react + reflux + webpack,使用ES6语法:顺带用了下jquery,bootstrap,echarts等插件,写了两个小demo 初版,还需不断完善. 先来个整体感觉吧, 贴几张图: 后端,熟悉的人自然熟悉: 前端, 有没感觉前端的写法越来越像后端了,对于我这种业余前端选手来说,挺喜欢这种目录结构和语法的,哈哈哈: 运行效果: 后端说明