多页面应用

传统多页面应用

  • 浏览器的地址栏发生变化指向新的URL,于是浏览器发起一个HTTP请求到服务器获取页面的完整HTML;

  • 浏览器获取到HTML内容后,解析HTML内容

  • 浏览器根据解析的HTML内容确定还需要下载哪些其他资源,包括JS和CSS资源

  • 浏览器会根据HTML和其他资源渲染页面内容,然后等待用户的其他操作

  • 当用户点击网页内某个链接引起URL的改变,又会重复上面的步骤

单页面应用

  • 不同页面之间切换的时候,URL会对应改变,这通过浏览器的History API 可以实现在不刷新网页的情况下修改URL。

  • 用户在地址栏直接输入某个正确的URL时,网页上要显示对应的正确内容。

  • 服务器返回的HTML实际上没有任何可视的内容,作用只是引入JS代码。对于任何一个URL,只需要返回一个同样的HTML页面就可以,一切应用的逻辑都在浏览器执行的JS代码中。

路由:每个URL都包含域名部分和路径部分,因为应用可能被部署到任何一个域名上,所以决定一个URL显示什么内容的只有路径部分,和域名和端口没有关系,根据路径找到对应应用内容的过程就叫路由。

React Router

使用React Router,即使结合了Redux,当前路由的信息是存储在浏览器的URL上的,而不是像其他数据一样存储在Redux的Store上,获取路由信息的唯一数据源就是当前的URL。但是,如果不是所有应用状态都存在Store上,就会有一个很大的缺点,因为当利用Redux Devtools 做调试时,无法重现网页之间的切换,因为当前路由作为应用状态根本没有在Store状态上体现。为了克服这个缺点,可以利用react-router-redux库来同步浏览器URL和Redux的状态,显然,这违背了“唯一数据源”的规则,但是只要两者绝对保持同步,就不会带来问题。react-router-redux库的工作原理是在Redux Store的状态树上routing字段中保存当前路由信息,其提供syncHistoryWithStore方法将React-Router提供的browser-History 和 store 关联起来,当浏览器的URL变化时,会向store派发action对象,同时监听store的状态变化,当状态树下routing字段发生变化时,反过来会更新浏览器的URL。

代码分片

  • 注册登录页面访问量较少

  • 网站应用有持续的新功能更新上新时,如果因为一个微小的局部修改导致整个bundele.js需要被更新,用户浏览器为了获取那一个微小的修改也只有下载整个bundle.js

对JS分片打包,按需加载,代码分片原则:

  • 一个应用本身的bundle.js

  • 一个包含页面间共同内容的common.js

  • 一个特定于当前页面内容的JS文件

  • 一个外部依赖模块的vendor.js

提高网页性能的另一个重要原则是减少HTTP请求数,虽然代码分片减少了每个页面的代码下载量,却也增加了引用JS资源数。但由于浏览器的缓存作用,只影响用户访问的第一个页面,当应用中页面越多,这种优化效果越明显。

代码分片需要两步:

  • 配置webpack告诉webpack分片打包

    • 配置output字段

    • 配置plugins字段:CommonsChunkPlugin插件

  • 让webpack产生分片打包文件:

    • require.ensure

      • 因为webpack的打包过程是对代码静态扫描的过程,require的参数如果不是字符串而是一个需要运算的表达式,webpack就无从知道表达式的运算结果是什么,反之,如果是字符串,那么webpack就可以明确知道对应的文件模块位置
    • import函数:类似import(‘./pages/Home.js’)

  • 使用React-Router的getComponent异步加载页面分片文件