近日的工作集中于一个单页面应用(Single-page application),在项目中尝试了闻名已久的Code splitting,收获极大,特此分享。

Why we need code splitting

SPA的客户端路由极大的减少了Server 与 Client端之间的Round trip,在此基础上,我们还可以借助Server Side Rendering 砍掉客户端的初次页面渲染时间(这里是SSR实现的参考链接:ReactAngular2).

仍然有一个问题普遍存在着:随着应用复杂度/规模的增加,应用初始所加载的文件大小也随之增加。我们可以通过将文件分割成按需加载的chunks来解决这一问题,对于初始页面,只请求他所用到的模块的相关文件,等我们进入新的路由,或者使用到一些复杂的功能模块时,才加载与之相关的chunk。

借助于webpackreact-router(目前我的应用是基于React开发的),我们可以快速实现这些按需加载的chunks。

webpack

Webpack是非常火的一个module bundler,这里是一个很好的入门参考链接。

我们可以借助代码中定义split point以创建按需加载的chunk。

使用require.ensure(dependencies, callback)可以加载 CommonJs modules, 使用require(dependencies, callback)加载 AMD modules。webpack会在build过程中检测到这些split points,创建chunks。

React router

React router 是一个基于React且非常流行的客户端路由库。

我们能以plain JavaScript object或者declaratively的形式定义客户端路由。

Plain JavaScript way:

let myRoute = {
path: `${some path}`,
childRoutes: [
RouteA,
RouteB,
RouteC,
]
}

declaratively way:

const routes = (
<Route component={Component}>
<Route path="pathA" component={ComponentA}/>
<Route path="pathB" component={ComponentB}/>
</Route>
)

React router 可以实现代码的lazy load, 而我们正好可以把split points 定义在这些lazy load code中(参考链接)。

Code Splitting implement

below is a demo of create two on demand loaded chunks, chunk A will load once when enter rootUrl/A, chunk B will load once when enter rootUrl/B.

接下来的代码就是创建按需加载的chunks的例子,chunk A 只有当进入rootUrl/A才会加载,chunk B 只有当进入rootUrl/B才会加载。

routes

/* ---            RootRoute            --- */
...
import RouteA from './RouteA'
import RouteB from './RouteB' export default {
path: '/',
component: App,
childRoutes: [
RouteA,
RouteB,
],
indexRoute: {
component: Index
}
} /* --- RouteA --- */
...
export default {
path: 'A',
getComponent(location, cb) {
require.ensure([], (require) => {
cb(null, require(`${PathOfRelatedComponent}`))
}, 'chunkA')
}
} /* --- RouteB --- */
...
export default {
path: 'B',
getComponent(location, cb) {
require.ensure([], (require) => {
cb(null, require(`${PathOfRelatedComponent}`))
}, 'chunkB')
}
}

client side code for client side render

...
import { match, Router } from 'react-router' const { pathname, search, hash } = window.location
const location = `${pathname}${search}${hash}` //use match to trigger the split code to load before rendering.
match({ routes, location }, () => {
render(
<Router routes={routes} history={createHistory()} />,
document.getElementById('app')
)
})

server code for server side rendering

...
app.createServer((req, res) => {
match({ routes, location: req.url }, (error, redirectLocation, renderProps) => {
if (error)
writeError('ERROR!', res)
else if (redirectLocation)
redirect(redirectLocation, res)
else if (renderProps)
renderApp(renderProps, res)
else
writeNotFound(res)
}).listen(PORT) function renderApp(props, res) {
const markup = renderToString(<RoutingContext {...props}/>)
const html = createPage(markup)
write(html, 'text/html', res)
} export function createPage(html) {
return `
<!doctype html>
<html>
<head>
<meta charset="utf-8"/>
<title>My Universal App</title>
</head>
<body>
<div id="app">${html}</div>
<script src="/__build__/main.js"></script>
</body>
</html>
`
}

实现中可能会遇到的坑

取决于你是如何写自己的模块的,你可能会遇到这个错误:React.createElement: type should not be null, undefined, boolean, or number. It should be a string (for DOM elements) or a ReactClass (for composite components). Check the render method of RoutingContext.require()之后加一个.default即可。

如果你收到了这样的错误提示:require.ensure is not function, 增加一个polyfill即可: if (typeof require.ensure !== 'function') require.ensure = (d, c) => c(require),在Server端使用require来代替require.ensure.

谢谢,希望能指正我的错误!

最后附一张目前项目的chunks图:

借助Code Splitting 提升单页面应用性能的更多相关文章

  1. 借助 Vue 来构建单页面应用

    原文: https://github.com/MeCKodo/vue-tutorial 主题 Vue.js (1/2)Vue构建单页应用最佳实战 前言 我们将会选择使用一些vue周边的库 1.使用no ...

  2. webpack优化之code splitting

    作为当前风头正盛的打包工具,webpack风靡前端界.确实作为引领了一个时代的打包工具,很多方面都带来了颠覆性的改进,让我们更加的感受到自动化的快感.不过最为大家诟病的一点就是用起来太难了. 要想愉快 ...

  3. webpack 和 code splitting

    Code Splitting指的是代码分割,那么什么是代码分割,webpack和code splitting又有什么样的联系呢? 使用npm run dev:"webpack-dev-ser ...

  4. Ember.js实现单页面应用程序

    1.1.1 摘要 单页应用程序 (SPA) 是加载单个HTML 页面并在用户与应用程序交互时动态更新该页面的Web应用程序. SPA使用AJAX和HTML5创建流畅且响应迅速的Web应用程序,不会经常 ...

  5. Cloud Test 单页面即时监测功能上线!

    什么是即时监测? 即时监测,顾名思义是指输入 URL 后能够立即进行监测并展示结果,无需注册. 如下图,在输入框内输入需要监测的 URL,点击免费监测,即可展示网页监测结果: 图中我们可以看到页面各个 ...

  6. 由单页面web应用引发的企业应用问题

    由于单页面web应用的流行,client与server端之间都对应的产生了一些微妙的变化,比方,client原来仅仅是用来展示页面和理清逻辑,而现在逐渐转变成了一个可以进入驱动状态的应用程序. 未来的 ...

  7. 详细解剖大型H5单页面应用的核心技术点

    项目 Xut.js 阐述下开发中一个比较核心的优化技术点,这是一套平台代码,并非某一个插件功能或者框架可以直接拿来使用,核心代码大概是6万行左右(不包含任何插件) .这也并非一个开源项目,不能商业使用 ...

  8. webpack Code Splitting浅析

    Code Splitting是webpack的一个重要特性,他允许你将代码打包生成多个bundle.对多页应用来说,它是必须的,因为必须要配置多个入口生成多个bundle:对于单页应用来说,如果只打包 ...

  9. [转] react-router4 + webpack Code Splitting

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

随机推荐

  1. codeforces 702B B. Powers of Two(水题)

    题目链接: B. Powers of Two time limit per test 3 seconds memory limit per test 256 megabytes input stand ...

  2. luogu 3389 【模板】高斯消元

    大概就是对每一行先找到最大的减小误差,然后代入消元 #include<iostream> #include<cstdio> #include<cstring> #i ...

  3. java虚拟机内存溢出和泄漏实例

    测试参数设置: 1.循环调用new A()实现堆溢出,java.lang.OutOfMemoryError: Java heap space, 虚拟机参数:-Xms1M -Xmx1M -XX:+Hea ...

  4. hdu 最短路模板题 java

    最短路 Problem Description 在每年的校赛里,所有进入决赛的同学都会获得一件很漂亮的t-shirt.但是每当我们的工作人员把上百件的衣服从商店运回到赛场的时候,却是非常累的!所以现在 ...

  5. 使用Rest api管理Ceph网关

    背景 开发基于Ceph RadosGW的微服务,需要实现调用方可以通过rest api就能创建用户,获取用户信息等功能. 实现 Ceph的RadosGW自身就有该功能,这些创建用户.获取用户信息.获取 ...

  6. MVC中为自动生成实体类添加验证

    将额外的基于特性的元数据(象验证特性)施加到由VS设计器自动生成/维护的类的一个方法是,采用一个我们称之为“伙伴类(buddy classes)”的技术. 基本上来说,你创建另外一个类,包含你的验证特 ...

  7. SpannableStringBuilder 用法浅析以及仿陌陌表情

    SpannableStringBuilder  官方文档解释:这个类可以使文本的内容和标记都可以改变.当我们要为TextView或者Edittext里面的文字加入加入一些效果,如下划线,颜色标 识,超 ...

  8. 微信小程序开发之三元运算符代替wx.if/wx.else

    直接上代码 实现功能为:当fbphotoFirst为空时,src路径为“pic/信息反馈1-1_14.png“,并且点击事件uploadfbphotoFirst有效,否则为路径fbphotoFirst ...

  9. [教程心得] Flash AIR 调用exe/bat且可以传参

    Flash AIR 如何调用exe/bat?并且有些情况下需要传参,如何传参呢? 看下面例子: cmd传参打开系统软键盘(参考http://bbs.9ria.com/thread-181265-1-1 ...

  10. 设置a 标签打开新窗口新姿势

    设置页面中的所有a标签都打开新窗口 1,在写的时候就加上target="_blank" 2,在页头<head></head>里加上 <base tar ...