html 打包优化,webpack打包优化

记一次react项目优化的过程

优化前,用uglifyjs-webpack-plugin插件压缩js后得到的大小,实际大小1.3M,如图:

a88c98ddcf8e?utm_campaign=maleskine&utm_content=note&utm_medium=seo_notes&utm_source=recommendation

image.png

以上图形化界面,可下载webpack-bundle-analyzer插件包查看。

可以发现打包出来的main.js内主要包含了两部分:node_modules包及js业务代码,所以第一步就是要拆分node_modules包及业务代码:

//业务代码与node_modules分离

new webpack.optimize.CommonsChunkPlugin({

name: 'vendor',

minChunks: ({ resource }) => (

resource &&

resource.indexOf('node_modules') >= 0 &&

resource.match(/\.js$/)

),

}),

打包效果:

a88c98ddcf8e?utm_campaign=maleskine&utm_content=note&utm_medium=seo_notes&utm_source=recommendation

image2.png

第二步:分离node_modules包中比较大的包,并通过CDN或以静态文件的方式引入到项目中,在webpack中用externals指定即可,如:

externals: {

'react': 'React',

'react-dom': 'ReactDOM',

'redux': 'Redux',

'redux-thunk': 'ReduxThunk',

'react-redux': 'ReactRedux',

'redux-form': 'ReduxForm',

'immutable': 'Immutable',

'babel-polyfill': 'window', // polyfill 直接写 {} 也是可以的,

'transit-js': 'transit',

}

分离后在externals中所指定的包就不会打包的vendor.js中。

1.在index.html中通过CDN的方式引入在externals中指定过的包,如:

//注:以下插件包需找项目中对应版本的包且是min.js压缩版的

什么是CDN?

cdn(内容分发网络)的作用是加速网络传输,通过将资源部署到服务器,来加快资源到获取速度。目前用到的CDN主要是由Bootstrap 中文网支持并维护的前端开源项目免费 CDN 服务。

2.以静态文件的方式引入资源包

在当前项目的public目录下创建新的目录resource,将以上cdn引用包全都保存到resource目录(注:通过create-react-app创建的react项目中public目录下默认会有static目录,这里不能将js到静态文件放到static目录,在index.html中直接引入static目录下到文件会报错 Unexpected token

a88c98ddcf8e?utm_campaign=maleskine&utm_content=note&utm_medium=seo_notes&utm_source=recommendation

image3.jpg

既然用CDN加速来加载引入的包,为什么还要用静态文件的方式引入呢?

答案当然是本地引入文件会更快,毕竟cdn也是服务环境,请求服务环境的资源也是耗时间的,可参考cdn加速与js引入文件的比较

分离后vendor.js的大小:从原来的1.06M减少到584.42kb,小了一半

a88c98ddcf8e?utm_campaign=maleskine&utm_content=note&utm_medium=seo_notes&utm_source=recommendation

image4@2x.png

注:细心的同学会发现,上图中的antd-mobile包为什么没有通过js引用?

原因是antd-mobile包在经过按需打包后所得大小是147kb,而通过cdn引入的antd-mobile竟然有373kb,远超出了打包所得大小,所以不建议通过js引入,

可参考cdn antd-mobile

3.第三步-拆分js业务代码,按需加载

可看上图image2,右侧蓝色部分,业务代码实际大小只有93kb,但在页面初次加载资源时会将整个js业务代码都加载进来,特别是在网络环境差时,会加载的比较慢

业务代码主要分三个模块:买家账户(放account目录),卖家(放seller目录),登录、产品等页面(放sys目录),再加上公共代码(common\component目录),总共分四个块,项目中用到react-router-dom路由,接下来就按路由的方式拆分代码,所用工具react-loadable

//目录结构

Projects

--js

--common

--component

--App.web.js

--pages

--index.web.js

--account

--sys

--seller

index.web.js

//App.web.js

import {

AsyncSys,

AsyncSeller,

AsyncAccount,

} from './pages/index.web'

import {Route, Redirect, Switch } from 'react-router-dom'

class Root extends Component {

render() {

return (

(

)}/>

)

}

}

//./pages/index.web.js 这里按路由拆分

import Loadable from 'react-loadable';

import AsyncJSLoading from '../component/AsyncJSLoading'

const AsyncSys = Loadable({

loader: () => import(/* webpackChunkName: 'sys' */'./sys/index.web'),

loading: AsyncJSLoading

});

const AsyncSeller = Loadable({

loader: () => import(/* webpackChunkName: 'seller' */'./seller/index.web'),

loading: AsyncJSLoading

});

const AsyncAccount = Loadable({

loader: () => import(/* webpackChunkName: 'account' */'./account/index.web'),

loading: AsyncJSLoading

});

export {

AsyncSys,

AsyncAccount,

AsyncSeller,

}

//./sys/index.web.js

import {Route, Switch} from 'react-router-dom';

import Product from './ProductDetails.web';

import Login from './Login.web';

import SupplyData from './SupplyData.web';

export default class extends React.Component {

render() {

return (

)

}

}

//./seller/index.web.js 、./account/index.web.js 与 sys/index.web.js写法一样,这里不列举了

3点注意:

1.在 pages/index.web.js中通过import分割相应模块,模块内的文件在当前分割js中不可再次引用,否则分割失效,如:

//./pages/index.web.js

import Loadable from 'react-loadable';

import AsyncJSLoading from '../component/AsyncJSLoading'

import Login from './sys/Login.web' //再次引入sys目录下的文件

const AsyncSys = Loadable({

loader: () => import(/* webpackChunkName: 'sys' */'./sys/index.web'),

loading: AsyncJSLoading

});

2.import() 会返回一个Promise,对于不支持Promise浏览器需要在页面上注入Promise polyfill,如:

另外import()语法还没有加入到ECMAScript标准里,所以项目中需要安装一个Babel插件 babel-plugin-syntax-dynamic-import,并且将其加入.babelrc中:

{

plugins: [

"syntax-dynamic-import"

],

}

3./* webpackChunkName: 'sys' */ 的含义是为动态生成的Chunk赋予一个名称,以便我们追踪和调试代码

//filename中的name 就是 webpackChunkName所指定的名称

output: {

path: paths.appBuild,

filename: 'resource/js/[name].[chunkhash:8].js',

chunkFilename: 'resource/js/[name].[chunkhash:8].chunk.js',

publicPath: publicPath,

},

最后看看分割的结果:按预期分成功了四大块:main.js 主要是公共代码、account.js 是买家模块、seller.js 是卖家模块、sys.js 是 登录、产品页部分

a88c98ddcf8e?utm_campaign=maleskine&utm_content=note&utm_medium=seo_notes&utm_source=recommendation

image5.png

const CompressionWebpackPlugin = require('compression-webpack-plugin');

webpackConfig.plugins.push(

new CompressionWebpackPlugin({

asset: '[path].gz[query]',

algorithm: 'gzip',

test: new RegExp('\\.(js|css)$'),

threshold: 10240,

minRatio: 0.8

})

)

压缩前:最大的文件vendor.js 589kb

a88c98ddcf8e?utm_campaign=maleskine&utm_content=note&utm_medium=seo_notes&utm_source=recommendation

image6.png

压缩后:vendor.js 154kb

a88c98ddcf8e?utm_campaign=maleskine&utm_content=note&utm_medium=seo_notes&utm_source=recommendation

image7.png

至此,大功告成!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值