Zong
梅雨季节的杭州

6月底开始到7月都是🌧啊🌧的,好烦躁的说,况且天气又闷闷的。

React 源码阅读计划

截止 6 月底,我对 16.8.6 任然还是很远很远,暂时只读完了 React Fiber 的数据结构,并且对里面的很多字段都没有很具体和明确的理解,但是隐隐约约有了些认识,目前进度正在 ReactFiberReconciler.jsReactFiberBeginWork.js 阅读中,需要了解整个过程真是漫长之路。这里分享一些链接供各位学习:

由 Dynamic publicPath 迎刃而解的一些问题

因为我司的后台项目,在使用 React 后采用的是 Java 模板引擎 Thymeleaf 直出的页面,所以页面中会含有一些该模板引擎的语法,那么比较蛋疼的是,项目采用的是动态 URL Path ,怎么理解这句话呢,比较好理解的就是大家都有给 React 项目配置过 "homepage" 字段吧,那么问题是这里配置的信息都是写死的,依据何来呢?我们看到编译完的代码后,可以看到:

// https://github.com/webpack/webpack/blob/c36966a2c996c873b372f46d383f40b7d706fa3b/lib/MainTemplate.js#L43

// require function shortcuts:
// __webpack_require__.p = the bundle public path

// https://github.com/webpack/webpack/blob/c36966a2c996c873b372f46d383f40b7d706fa3b/lib/MainTemplate.js#L356

      const publicPath = this.getPublicPath({
        hash: hash
      });
      buf.push("");
      buf.push("// __webpack_public_path__");
      buf.push(`${this.requireFn}.p = ${JSON.stringify(publicPath)};`);
      return Template.asString(buf);
    });

看到呢, __webpack_require__.p 就是这个 "homepage" 字段,我在这里设置任何值都会被 JSON.stringify 转为 String 。说到这里以后,我们来说说为什么我们需要动态的 publicPath ,因为考虑到项目资源优化,不需要加载不必要页面的脚步或其他,所以需要进行 Code Spilting ,那么这条路发现被封锁死了,来找找其他路吧……,我们来看看 jsonpScriptSrc 函数是否可以通过某种手段进行修改:

// https://github.com/webpack/webpack/blob/acf2c2d4b19117aa6562ea6885da2dbfade369fc/lib/web/JsonpMainTemplatePlugin.js#L129

        if (needChunkOnDemandLoadingCode(chunk)) {
          extraCode.push(
            "",
            "// script path function",
            "function jsonpScriptSrc(chunkId) {",
            Template.indent([
              `return ${mainTemplate.requireFn}.p + ${getScriptSrcPath(
                hash,
                chunk,
                "chunkId"
              )}`
            ]),
            "}"
          );
        }

很遗憾的是 Webpack 官方并不支持我的想法。看到上面代码中 ${mainTemplate.requireFn}.p 后面直接跟进 getScriptSrcPath 函数,我并没有办法在他们之间插入我想要的内容,难道我需要 fork 一份代码自己改吗?可能会带来不必要的麻烦。事情到了这里,我选择先避开这个问题,那么我不采用 Code Spilting 来优化我的项目,暂时跳过,先完成我的业务开发。同时我修改了 react-echarts-map-china 项目中的 Dynamic Import 功能改为静态,带来的问题也接踵而至,使得编译打包后的代码体积很大。在将项目跑在测试环境时问题也暴露了,跟流水一样的带宽承受不了第一次的加载或者项目迭代更新……,会造成很大的麻烦。所以这个问题并不能避开,还是得硬着头皮解决,那么这时候我在想能不能在 Webpack 打包编译完成后的钩子中去检索 __webpack_require__.p 对应的 "homepage" 字段将其替换成我想要的动态功能呢?想使用 Plugin 来解决这个问题,自己造一个轮子吗?刚准备写的时候,发现强大的 NPM 社区有轮子 Dynamic Public Path Plugin ,实现的目的就是刚刚上述的内容:

// before
__webpack_require__.p = "publicPathPlaceholder";

// after
__webpack_require__.p = window.externalPublicPath;

那么这样一来, Code Spilting 就可以完全使用了,并且上述所有问题都迎刃而解了。接下来来说说关于代码分割的一些实践,先来说说 Chunk Name 的问题,默认情况下,拆分出来的文件名真的是难看的要命,以数字命名的你敢信吗?不仅看起来吃力还是看起来吃力,虽然说要查看包里面的内容还是得借助 webpack-bundle-analyzer ,但是我们还是要攻克这个难题,其实也不难。看个例子就能懂:

import(/* webpackChunkName: 'about' */'../about')

打包出来的文件就不再是 1.[chunkhash:8].js 而是 about.[chunkhash:8].js 了。有关 webpackChunkName 的可以参考文章:

再来说说这次我代码分割的一些库的抽离,使用了 splitChunks 来操作:

const vendors = {
  antd: [['antd', '@ant-design']],
  echarts: [['echarts', 'zrender']],
  mapchina: [['react-echarts-map-china']],
  publicData: [['publicData'], 'src'],
};

const generateVendorsCacheGroups = () => {
  const vendorsCacheGroups = {};
  for (const [key, [val, folder = 'node_modules']] of Object.entries(vendors)) {
    vendorsCacheGroups[key] = {
      test: new RegExp(`[\\/]${folder}[\\/](${val.join('|')})[\\/]`),
      name: val.join('~'),
      chunks: 'all',
    }
  }
  return vendorsCacheGroups;
};

const cacheGroups = {
  ...generateVendorsCacheGroups(),
};

module.exports = {
  cacheGroups,
};

来尽最大的可能来进行前端资源的优化。

Ant Design Cascader 级联选择之奇淫技巧

在使用级联的时候,因为涉及到数据回填,比较特殊的是这个级联还是异步的,采用的不是直接遍历级联深度去请求接口并拼装树,而是把最底层的级联数据提升至顶层并设置禁止选择同时将其隐藏 DOM ,这样可以实现数据回填,并且不需要遍历请求接口,是一个不错的技巧。

git 特殊 host 端口调整

vim ~/.ssh/config
## IP
host 127.0.0.1
## 域名
hostname www.zongzi531.com
## 端口
port 1234

进行特定配置即可

推啊前端技术开放日

参加推啊前端开放日是一种怎样的体验?

【自问自答系列】在今天参加了推啊的开放日,很喜悦的是今天学习到的各位老师分享的干货,同时还获得了兑吧的文化衫,哈哈。那么趁热打铁,我来快速的总结下今天的收获吧!

前端错误和性能的监控,服务端的性能监控

当然啦,其实我一开始就知道 window.onerror 这个 API ,在里面放个接口用于自动收集错误报告,但是听了闪电分享的老师说的内容,使我想到对于前端页面仔来说,这只不过是挂一个接口的事情,更多的事情其实是在服务端,在收集数据后进行聚合分析的结果,以及服务端需要承受的数据压力才是真正的考量。当然错误监控平台在一款需要不停迭代的产品中,存在着不可缺少的地位,他的存在能让你的产品自我进步,升华,就吹这么多。那么围绕着这个主题,我们来直接讲到性能监控,性能优化一直是前端的一个命题,分享老师提到 PerformanceTiming API ,收集信息的操作类似错误监控,但是不像错误监控那样是有很明确的定义,性能监控的标准?什么是流畅,什么是卡顿,都是相对的。从网络情况吗?从机器性能吗?针对不同的网络情况,不同的机型,后端直出不同的针对性的资源吗?一个难题,看公司考虑这样做是否有必要了,都是结合自身业务的事情。慢慢的一步一步做才会让产品更好才不是呢,性能的提升会使他与客户更好的互动,同样也能留住客户,提升转化率,增加收入等等。

再来说说服务端的性能监控,在今天有被老师提到,关于服务器内存、CPU、流量、服务状态等信息的监控,以及监控预警。老师推荐了一本书《Node.js 调试指南》。

微页面,高效测试

我司组长有和我传授过微页面的有意思之处,在之前商城项目中就有,可以把页面的展示全权交给运营去配置,不需要开发介入。老师提到关于组件旋转的数学细节很有意思,点个赞。

测试老师真的好给力,自己实现业界的云测试平台,记录了三个库:

One to More

在之前的 Vue conf 基于一端产多端的解决方案就有提到很多,但是这次的货很干,提到了这个转换过程的实现,在此记录学习。

在对编写完的代码进行 AST 解析AST Explorer(HTML、CSS、JS)后,进行对应目标端的转换,可以想到这里会针对目标端进行打补丁,类似差异化、FallBack这样的事情,在完成转换后再将转换后的 AST 生成为目标端的代码即完成这样的事情。当然,有些由转换无法自己完成的事情是需要由人工干预的,比如老师说的各端不同的登录模式,真的是奇淫技巧,利用 example.(wx|zfb|...).js 这样的技巧,真的非常 NICE 。


追加计划