借助 Webpack 静态分析能力实现代码动态加载

栏目: JavaScript · 发布时间: 5年前

内容简介:Debugger 一个动态配置代码异步加载引发的状态错误问题,想起以前在某厂学习的一个解决问题的方法论:最后从 Webpack 的角度利用静态代码分析的能力来解决问题。父组件 kitten.tsx

Debugger 一个动态配置代码异步加载引发的状态错误问题,想起以前在某厂学习的一个解决问题的方法论:

  • 现象背后真实问题是啥?
  • 真实问题背后原因是啥?
  • 对策是要基于原因的,不是基于现象的。

最后从 Webpack 的角度利用静态代码分析的能力来解决问题。

现象

父组件 kitten.tsx

componentDidMount() {
  console.log('cc kitten didMount');
  setTimeout(
    () => {
      console.log('cc kitten render_content before');
      this.render_content();
      console.log('cc kitten render_content after');
    },
    0,
  );
}
render_content() {
  console.log('cc action_fetch_bcm_by_url before');
  // 一个异步操作,拉取到在线资源后会调用 workspace 上的方法
  this.props.action_fetch_bcm_by_url();
  console.log('cc action_fetch_bcm_by_url after');
}
复制代码

子组件 BKWorkspaceContainer.tsx

async componentDidMount() {
  console.log('cc BKWorkspaceContainer didMount');

  console.log('cc BKBridge.init before');
  // 初始化 workspace,初始化完成前为 null
  await BKBridge.init();
  console.log('cc BKBridge.init after');
}
复制代码

执行顺序

cc BKWorkspaceContainer didMount
cc BKBridge.init before
cc kitten didMount
cc kitten render_content before
cc kitten render_content after
cc action_fetch_bcm_by_url before
cc action_fetch_bcm_by_url after

cc BKBridge.init after
复制代码

上面顺序可能一个个看会看得眼花,而且这只是最外层的函数,里面还很深很杂,描述一下现象:

  • 方法调用workspace.xxx 报错了,因为 workspace 还是 null
  • 子组件先 render 没毛病,但是子组件里面的 init 方法似乎没有执行完就把控制权交回给父组件了
  • 父组件 componentDidMount 中使用 setTimeout 0 企图将 render 任务推到 task 中,甚至这是个 ajax 请求操作,但是在 ajax 请求完成后还是比 BKBridge.init() 完成得要早,ajax 后面的操作用到了 workspace,但是它是 null
  • 最后 cc BKBridge.init after 打印出来了,workspace 初始化完成了

init 阻塞

// 简化后的调用过程
if (config().enable_test_mode) {
  await register_test_block();
}
const workspace_panel = new WorkspacePanel(block_xml);

// register_test_block 代码
async function register_test_block(registry:Registry) {
  return new Promise((resolve) => {
    require.ensure([], function(require){
      const { register_test_blocks } = require('../acceptance_test');
      register_test_blocks(registry);
      registry.load_all_block_definitions_into_bk(BK);
      resolve();
    });
  });
}
复制代码

用了 require.ensure 这种方式来异步加载代码,代码执行到这一段的时候才去拉 JS,所以会出现比 ajax 还慢的情况,它是异步的。直接阻塞了后面 new WorkspacePanel(block_xml) 的执行。

更长的延时

componentDidMount() {
  setTimeout(
    () => {
      this.render_content();
    },
    100,
  );
}
复制代码

通过父组件设置 100ms 的延时,问题就不存在了,但是如果 require('../acceptance_test') 的时间超过了 100ms,怎么办呢?

现象背后的问题

代码写成这样子,最初是为了解决动态加载代码的问题,如果 config().enable_test_mode 设置成 true 才接入 acceptance_test 相关的代码,否则就连代码都不要进入到打出来的包中。

问题背后的原因

所以我们的初衷是为了让某段代码可以通过配置决定是否打包进 boundle。这就好办了,可以不用把精力放在如何沟通父子组件上面,不用想类似代码暂停这种复杂化操作,只要利用 Webpack 打包时候的静态分析即可。

对策:Webpack 静态分析

webpack 读 config 文件

const runtime_cfg = require('../config')();

module.exports = {
  // ...
  plugins: [
    new webpack.DefinePlugin({
      '__TEST_MODE__': runtime_cfg.client.enable_test_mode
    }),
  ],
  // ...
}
复制代码

为全局定义一个 __TEST_MODE__ 变量,在代码的任何地方都可以使用,当然如果是 ts 代码的话需要配置:

// global.d.ts
declare var __TEST_MODE__:boolean;
复制代码

代码中直接写 require

if (__TEST_MODE__) {
  const { register_test_blocks } = require('../acceptance_test');
  register_test_blocks(registry);
  registry.load_all_block_definitions_into_bk(BK);
}
复制代码

结果

// config.ts
"enable_test_mode": true
复制代码
借助 Webpack 静态分析能力实现代码动态加载
// config.ts
"enable_test_mode": false
复制代码
借助 Webpack 静态分析能力实现代码动态加载

可以看到,搜索 register_test_blocks 模块里面的相关代码已经搜索不到了。


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

影响力

影响力

[美] 罗伯特·西奥迪尼 / 陈叙 / 中国人民大学出版社 / 2006-5 / 45.00元

政治家运用影响力来赢得选举,商人运用影响力来兜售商品,推销员运用影响力诱惑你乖乖地把金钱捧上。即使你的朋友和家人,不知不觉之间,也会把影响力用到你的身上。但到底是为什么,当一个要求用不同的方式提出来时,你的反应就会从负面抵抗变成积极合作呢? 在这本书中,心理学家罗伯特·B·西奥迪尼博士为我们解释了为什么有些人极具说服力,而我们总是容易上当受骗。隐藏在冲动地顺从他人行为背后的6大心理秘笈,正是......一起来看看 《影响力》 这本书的介绍吧!

HTML 编码/解码
HTML 编码/解码

HTML 编码/解码

Markdown 在线编辑器
Markdown 在线编辑器

Markdown 在线编辑器

RGB HSV 转换
RGB HSV 转换

RGB HSV 互转工具