第六期:前端九条启发分享
本期
这个系列是本来叫'九条bug', 然而始终感觉名字不是很贴切, 想了很久决定从这次起改成九条启发(尽管名字还是很烂), 这次要分享的内容大部分是我的项目构造相干的, 让咱们一起看看吧。
一: soucemap反解析打包后的文件
咱们正式环境安排的都是压缩后的文件, 如果正式环境报错那么咱们要如何精确晓得谬误产生在代码的什么地位? 兴许某些状况下你须要对代码进行 soucemap反解析
, 这就须要mozila 官网 sourcemap 反解库
, 让咱们新建一个文件尝试一下:
npx create-react-app my_inspire
咱们成心做一个error进去, 比方在App.js
里增加如下的代码:
function cc(str) { str.replace("-", ","); } cc();
进入到 node_module/react-scripts/config/webpack.config.js
做如下替换:
// const shouldUseSourceMap = process.env.GENERATE_SOURCEMAP !== 'false';const shouldUseSourceMap = true;
运行yarn build
(重点)咱们把.map
文件都独自拿进去放在一个map文件夹里, 如果这个文件在build
文件夹内会主动帮咱们做了soucemap的解析
性能。
咱们能够看到报出的error
正式咱们的'replace'谬误, 点击下放的main
压缩文件。
记住这两个参数line = 1;
和 column = 241;
。
当初咱们要新建一个我的项目:
mikdir my_mapcd ./my_mapnpm init -yyarn add source-mapmikdir srccd srctouch index.js
在index.js
外面增加解析代码:
const sourceMap = require("source-map");const fs = require("fs");let data = fs .readFileSync(process.cwd() + "/map/static/js/main.761f3095.chunk.js.map") .toString();const consumer = new sourceMap.SourceMapConsumer(data);consumer.then((code) => { const line = 1; const column = 241; const res = code.originalPositionFor({ line, column }); console.log( code .sourceContentFor(res.source) .split("\n") .slice(Math.max(res.line - 5, 0), res.line + 5) .join("\n") );});
一起看看这个代码.slice(Math.max(res.line - 5, 0), res.line + 5)
, 这里是同时打印出错代码的高低5行代码。
用node命令执行这个文件就能够失去如下后果:
二: sendBeacon 发送数据
比方咱们要上报用户的敞开页面操作, 间接应用axios
上报就会呈现申请没有收回去或被浏览器cancel掉, 比方上面这种形式会使卸载变慢:
window.addEventListener('unload', logData, false);function logData() { var client = new XMLHttpRequest(); client.open("POST", "/log", false); client.setRequestHeader("Content-Type", "text/plain;charset=UTF-8"); client.send(analyticsData);}
看了以后应用的埋点和监控库的代码, 发现他们会应用sendBeacon api
进行数据的上报, 它能够保证数据无效送达,且不会阻塞页面的卸载或加载, 值得注意的是这个办法最好只传递大量数据不应设计的简单, 用法如下:
window.addEventListener('unload', logData, false);function logData() { navigator.sendBeacon("你的上报地址", "上报的数据");}
应用 sendBeacon() 办法会使用户代理在有机会时异步地向服务器发送数据,同时不会提早页面的卸载或影响下一导航的载入性能。这就解决了提交剖析数据时的所有的问题:数据牢靠,传输异步并且不会影响下一页面的加载。
三: 如何监测到页面卡死无响应
该如何监控到用户的页面解体了? 因为js
属于单线程执行, 如果页面里有一个死循环
, 那么咱们前面的代码都无奈被执行, 当然谬误的监控代码也就无奈被执行。
思路就是要跳出单线程
, Worker 线程
降下来了正义之光, Worker 线程是能够独立于 JS 主线程执行的子线程,不受 JS 主线程
影响, 而咱们能够通过Worker 线程
每3秒给JS 主线程
发送一个音讯, 如果超过6秒没有收到主线程的回复, 那就能够认定是主线程卡死了。
上面是一个简易版的监控:
index.html
:
<!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title></head><body> <script> var worker = new Worker('./worker.js'); worker.onmessage = function (event) { console.log(`收到了子线程的问候: ${event.data}`) worker.postMessage('我很好!'); } </script></body></html>
worker.js
:
let come = 0;const timer = setInterval(() => { waiting = true; come -= 1; self.postMessage("主线程你还好么?"); if (come < -2) { navigator.sendBeacon("你的上报地址", "上报页面解体"); }}, 3000);self.addEventListener( "message", function (e) { waiting = false; console.log(`收到了主线程的回答: ${e.data}`); come += 1; }, false);
四: 深层依赖无奈更新
比方咱们的主我的项目
依赖a包
&b包
, a包
也依赖b包
, 当a包
降级了须要依赖b包
最新的版本时, 间接执行yarn
命令可能会导致咱们咱们主我的项目
外面的b包
更新了, 然而a包
的package.json
文件尽管写了"b":"*"
然而可能也无奈更新到最新版的b
, 删掉node_modules
文件夹也无用, 因为这个bug是yarn.lock
文件导致的, 须要咱们yarn remove a
而后从新yarn add a
就能够解决问题。
五: yarn why
yarn why
命令次要是用于显示须要包的起因, 比方我的我的项目里yarn add antd
, 然而我没有装置dayjs
库, 这时我执行命令:
yarn why dayjs
"antd#rc-picker" depends on it
antd
外面这个日期组件用到了它, 并且还会列出这个包的大小。
六: vscode工作空间设置
就是图里的这两个设置项:
工作空间是指应用VS Code关上的某个文件夹,在该文件夹下会创立一个名为.vscode的暗藏文件夹,外面蕴含着仅实用于当前目录的VS Code的设置,工作空间的设置会笼罩用户的设置, 咱们来把字体调大。
变得好大:
咱们改回 12
利用这个性能能够做格式化的对立
以及某个插件针对特定我的项目的针对性配置。
七: react异步引入组件 @loadable/component
如果咱们引入文件的地址是动静的, 他的引入门路是/home/home1
或者是/home/home2
, 如下的写法会报错:
const Home = () => import(`./home/home1`);function App() { return ( <div className="App"> <p>app 页面</p> <Home></Home> </div> );}export default App;
借助插件实现动静批改引入门路:
yarn add import @loadable/component
import "./App.css";import loadable from "@loadable/component";const n = 1;const Home = loadable(() => import(`./home/home${n}`));function App() { return ( <div className="App"> <p>app 页面</p> <Home></Home> </div> );}export default App;
这样至多不必引入两个组件。
八: package.json
引入本地包作为依赖
一提到引入本地包第一工夫想到的就是npm link
& npm unlink
这对兄弟命令, 然而当你要引入的本地包
变多的时候就会很麻烦, 比方公布代码的时候还要npm unlink
, 所以当初好多我的项目都采纳lerna
来做我的项目的包治理, 当前有机会具体聊聊lerna
。
在这里我想介绍另一种形式, 如下图:
咱们有个包名为@lulu/bao
, 新建bao
文件夹, 放在我的项目里并且须要npm init
一下把信息填残缺:
包文件index.js
内容为
export default () => { console.log("我是本地的包");};
在package.json
中增加配置, file:
指向本地
要留神, 以后须要npm install
一次才能够失效, 就能够如下的形式应用了。
import bao from "@lulu/bao";bao();
九: ts在替换ui库时的重要性
ts
某些时候真的太重要了, 最近我参加了一个老工程整体替换ui
组件库的我的项目, 本认为都是款式上的不同, 后果踩坑满满。
比如说旧版的日期组件
的onchange
事件第二个参数返回的是dayjs
对象格局的, 然而新版组件返回的是string
, 导致之后的所有解决办法全不对了, 这种谬误ts就能够很明确的报进去。
属性的更替也是同理, 比方新版的某个组件身上不接管style
属性了, 那么之前传入style
属性的中央都飘红, 我就须要想别的方法把一堆style
以其余形式作用在组件上。
还有属性值的范畴, button
组件的size之前有4个属性可选, 然而新版的只有两个, 真是很让人头秃。
end
第九条说了替换ui组件的问题, 下一篇我会专门聊一聊我为一个大我的项目替换ui组件遇到的20几种问题类型, 真的是十分开眼界, 这次就是这样, 心愿与你一起提高。