借助 Webpack 静态分析能力实现代码动态加载
栏目: JavaScript · 发布时间: 6年前
内容简介: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 复制代码
// config.ts "enable_test_mode": false 复制代码
可以看到,搜索 register_test_blocks
模块里面的相关代码已经搜索不到了。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Designing Data-Intensive Applications
Martin Kleppmann / O'Reilly Media / 2017-4-2 / USD 44.99
Data is at the center of many challenges in system design today. Difficult issues need to be figured out, such as scalability, consistency, reliability, efficiency, and maintainability. In addition, w......一起来看看 《Designing Data-Intensive Applications》 这本书的介绍吧!
HTML 编码/解码
HTML 编码/解码
正则表达式在线测试
正则表达式在线测试