自建开发工具系列 -Webkit 内存动量监控 UI(七)
发布于: 3 小时前

本次修改集中在调整原来的编译结构,将新建 demo 目录,把 create-react-app 的配置重新调整。然后把工具直接编译成单个 js 文件,便于在一些特殊场合下使用。
执行 npm run eject 命令,让配置回到 webpack.config
tim@Tim tools-webkit-memory % npm run eject
> tools-webkit-memory@0.1.1 eject /Users/tim/Documents/platform/tools-webkit-memory> react-scripts eject
NOTE: Create React App 2+ supports TypeScript, Sass, CSS Modules and more without ejecting: https://reactjs.org/blog/2018/10/01/create-react-app-v2.html
✔ Are you sure you want to eject? This action is permanent. … yesEjecting...
Copying files into /Users/tim/Documents/platform/tools-webkit-memory Adding /config/env.js to the project Adding /config/getHttpsConfig.js to the project Adding /config/modules.js to the project Adding /config/paths.js to the project Adding /config/pnpTs.js to the project Adding /config/webpack.config.js to the project Adding /config/webpackDevServer.config.js to the project Adding /config/jest/babelTransform.js to the project Adding /config/jest/cssTransform.js to the project Adding /config/jest/fileTransform.js to the project Adding /scripts/build.js to the project Adding /scripts/start.js to the project Adding /scripts/test.js to the project
Updating the dependencies Removing react-scripts from dependencies Adding @babel/core to dependencies Adding @pmmmwh/react-refresh-webpack-plugin to dependencies Adding @svgr/webpack to dependencies Adding @typescript-eslint/eslint-plugin to dependencies Adding @typescript-eslint/parser to dependencies Adding babel-eslint to dependencies Adding babel-jest to dependencies Adding babel-loader to dependencies Adding babel-plugin-named-asset-import to dependencies Adding babel-preset-react-app to dependencies Adding bfj to dependencies Adding camelcase to dependencies Adding case-sensitive-paths-webpack-plugin to dependencies Adding css-loader to dependencies Adding dotenv to dependencies Adding dotenv-expand to dependencies Adding eslint to dependencies Adding eslint-config-react-app to dependencies Adding eslint-plugin-flowtype to dependencies Adding eslint-plugin-import to dependencies Adding eslint-plugin-jest to dependencies Adding eslint-plugin-jsx-a11y to dependencies Adding eslint-plugin-react to dependencies Adding eslint-plugin-react-hooks to dependencies Adding eslint-plugin-testing-library to dependencies Adding eslint-webpack-plugin to dependencies Adding file-loader to dependencies Adding fs-extra to dependencies Adding html-webpack-plugin to dependencies Adding identity-obj-proxy to dependencies Adding jest to dependencies Adding jest-circus to dependencies Adding jest-resolve to dependencies Adding jest-watch-typeahead to dependencies Adding mini-css-extract-plugin to dependencies Adding optimize-css-assets-webpack-plugin to dependencies Adding pnp-webpack-plugin to dependencies Adding postcss-flexbugs-fixes to dependencies Adding postcss-loader to dependencies Adding postcss-normalize to dependencies Adding postcss-preset-env to dependencies Adding postcss-safe-parser to dependencies Adding prompts to dependencies Adding react-app-polyfill to dependencies Adding react-dev-utils to dependencies Adding react-refresh to dependencies Adding resolve to dependencies Adding resolve-url-loader to dependencies Adding sass-loader to dependencies Adding semver to dependencies Adding style-loader to dependencies Adding terser-webpack-plugin to dependencies Adding ts-pnp to dependencies Adding url-loader to dependencies Adding webpack to dependencies Adding webpack-dev-server to dependencies Adding webpack-manifest-plugin to dependencies Adding workbox-webpack-plugin to dependencies
Updating the scripts Replacing "react-scripts start" with "node scripts/start.js" Replacing "react-scripts build" with "node scripts/build.js" Replacing "react-scripts test" with "node scripts/test.js"
Configuring package.json Adding Jest configuration Adding Babel preset
Running yarn...yarn install v1.22.4[1/4] 🔍 Resolving packages...[2/4] 🚚 Fetching packages...[3/4] 🔗 Linking dependencies...warning " > @testing-library/user-event@12.8.3" has unmet peer dependency "@testing-library/dom@>=7.21.4".[4/4] 🔨 Building fresh packages...success Saved lockfile.✨ Done in 18.99s.Ejected successfully!
Staged ejected files for commit.
Please consider sharing why you ejected in this survey: http://goo.gl/forms/Bi6CZjk1EqsdelXk1
tim@Tim tools-webkit-memory %
复制代码
然后把原来 src 下的 index.js 和 index.css 转移到和 src 平级的 demo 目录中,用来运行查看工具库的引用情况。
这个时候因为入口文件改变到了 src 以外的位置,需要调整 webpack 的设置,create-react-app 的路径设置在./config/paths.js 中,这里做了入口位置的调整:
diff --git a/config/paths.js b/config/paths.jsindex 4e3d30e..1b9b360 100644--- a/config/paths.js+++ b/config/paths.js@@ -57,9 +57,9 @@ module.exports = { appBuild: resolveApp(buildPath), appPublic: resolveApp('public'), appHtml: resolveApp('public/index.html'),- appIndexJs: resolveModule(resolveApp, 'src/index'),+ appIndexJs: resolveModule(resolveApp, 'demo/index'), appPackageJson: resolveApp('package.json'),- appSrc: resolveApp('src'),+ appSrc: resolveApp('/'), appTsConfig: resolveApp('tsconfig.json'), appJsConfig: resolveApp('jsconfig.json'), yarnLockFile: resolveApp('yarn.lock'),
复制代码
这个时候发现其实让 webpack 跑起 devServer 来看工具就引用了好多库
然候调整一下 tsconfig 的编译配置,让 tsc 打出单个 js 文件供便捷加载
diff --git a/config/paths.js b/config/paths.jsindex 4e3d30e..1b9b360 100644--- a/config/paths.js+++ b/config/paths.js@@ -57,9 +57,9 @@ module.exports = { appBuild: resolveApp(buildPath), appPublic: resolveApp('public'), appHtml: resolveApp('public/index.html'),- appIndexJs: resolveModule(resolveApp, 'src/index'),+ appIndexJs: resolveModule(resolveApp, 'demo/index'), appPackageJson: resolveApp('package.json'),- appSrc: resolveApp('src'),+ appSrc: resolveApp('/'), appTsConfig: resolveApp('tsconfig.json'), appJsConfig: resolveApp('jsconfig.json'), yarnLockFile: resolveApp('yarn.lock'),diff --git a/tsconfig.json b/tsconfig.jsonindex 24cbf02..fef3d99 100644--- a/tsconfig.json+++ b/tsconfig.json@@ -1,7 +1,7 @@ { "compilerOptions": { "target": "es5", - "module": "AMD", + "module": "CommonJS", "lib": ["DOM", "ES2015"], "allowJs": true, "declaration": true, @@ -9,11 +9,10 @@ "outFile": "./script/TWM.js", "rootDir": "./src", "strict": true, - // "esModuleInterop": true,+ "esModuleInterop": true, "jsx": "react-jsx" },- "include": [- "src/**/*.tsx",- "src/**/*.ts"+ "files": [ // 指定待编译文件+ "./src/App.tsx" ] }
复制代码
现在就可以看到输出了 TWM.js 文件,包含代码的内容:
var __extends = (this && this.__extends) || (function () { var extendStatics = function (d, b) { extendStatics = Object.setPrototypeOf || ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; }; return extendStatics(d, b); }; return function (d, b) { if (typeof b !== "function" && b !== null) throw new TypeError("Class extends value " + String(b) + " is not a constructor or null"); extendStatics(d, b); function __() { this.constructor = d; } d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); };})();define("config/api", ["require", "exports"], function (require, exports) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true });});define("utils", ["require", "exports"], function (require, exports) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); var displayPanel = function () { var memoryBottom = 100; var memoryTop = 0; var TOOLS_HEIGHT = 30; var MemoryLimitValue = TOOLS_HEIGHT; var toolsDom = document.createElement('div'); toolsDom.id = 'twm'; toolsDom.className = 'tools'; toolsDom.style.cssText = 'width:130;height:48px;opacity:0.9;cursor:pointer;overflow:hidden;z-index:10000;will-change:transform;'; var panel = document.createElement('div'); panel.id = 'ms'; panel.style.cssText = 'padding:0 0 3px 3px;text-align:left;background-color:black;'; toolsDom.appendChild(panel); var noticeLabel = document.createElement('div'); noticeLabel.id = 'noticeLabel'; noticeLabel.style.cssText = 'color:white;font-family:Arial;font-size:9px;font-weight:bold;line-height:15px'; noticeLabel.innerHTML = ''; panel.appendChild(noticeLabel); var nodeUI = document.createElement('div'); nodeUI.id = 'nodeUI'; nodeUI.style.cssText = "position:relative;width:120px;height:" + TOOLS_HEIGHT + "px;background-color:lightyellow"; panel.appendChild(nodeUI); // 刷新后增加新的内存值和GC状态 while (nodeUI.children.length < 120) { var bar = document.createElement('span'); bar.style.cssText = "width:1px;height:" + TOOLS_HEIGHT + "px;float:left;background-color:black"; nodeUI.appendChild(bar); } var updateData = function (dom, height, color) { var child = dom.appendChild(dom.firstChild); child.style.height = height + "px"; if (color) child.style.backgroundColor = color; }; var refreshGraph = function (dom, oHFactor, hFactor) { [].forEach.call(dom.children, function (c) { var cHeight = Number(c.style.height.substring(0, c.style.height.length - 2)); // 转换到 MB var newVal = TOOLS_HEIGHT - ((TOOLS_HEIGHT - cHeight) / oHFactor) * hFactor; c.style.height = newVal + "px"; }); }; // 避免没有 window.(performance as any).memory 的浏览器崩溃 if (window.performance && !performance.memory) { performance.memory = { usedJSHeapSize: 0, totalJSHeapSize: 0 }; } var precision; var i; function bytesToMB(bytes) { precision = Math.pow(10, 0); i = Math.floor(Math.log(bytes) / Math.log(1024)); return Math.round((bytes * precision) / Math.pow(1024, i)) / precision + " MB"; } var lastTime = Date.now(); var lastUsedHeap = performance.memory.usedJSHeapSize; var delta = 0; var color = 'black'; var ms = 0; var mbValue = 0; var factor = 0; var newThreshold = 0; return { domElement: toolsDom, update: function () { // 每秒刷新 if (Date.now() - lastTime < 1000 / 1) return; lastTime = Date.now(); delta = performance.memory.usedJSHeapSize - lastUsedHeap; lastUsedHeap = performance.memory.usedJSHeapSize; // GC 判定,如果是清空内存,则使用绿色标识 color = delta < 0 ? 'green' : 'black'; ms = lastUsedHeap; memoryBottom = Math.min(memoryBottom, ms); memoryTop = Math.max(memoryTop, ms); noticeLabel.textContent = window.performance.memory.jsHeapSizeLimit ? "\u5185\u5B58\u4F7F\u7528: " + bytesToMB(ms) : 'Only Webkit'; mbValue = ms / (1024 * 1024); if (mbValue > MemoryLimitValue) { factor = (mbValue - (mbValue % TOOLS_HEIGHT)) / TOOLS_HEIGHT; newThreshold = TOOLS_HEIGHT * (factor + 1); refreshGraph(nodeUI, TOOLS_HEIGHT / MemoryLimitValue, TOOLS_HEIGHT / newThreshold); MemoryLimitValue = newThreshold; } updateData(nodeUI, TOOLS_HEIGHT - mbValue * (TOOLS_HEIGHT / MemoryLimitValue), color); } }; }; exports.default = displayPanel;});define("App", ["require", "exports", "react/jsx-runtime", "react", "utils", "./App.css"], function (require, exports, jsx_runtime_1, React, utils_1) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); var TWM = /** @class */ (function (_super) { __extends(TWM, _super); function TWM(props) { var _this = _super.call(this, props) || this; _this.toolsNode = React.createRef(); _this.twm = utils_1.default(); return _this; } TWM.prototype.componentDidMount = function () { var _this = this; var updateLoop = function () { if (_this.toolsNode.current.appendChild) { _this.toolsNode.current.appendChild(_this.twm.domElement); } if (_this.twm) { _this.twm.update(); } if (window.performance.memory.jsHeapSizeLimit) { window.setTimeout(updateLoop, 1000); } }; window.setTimeout(updateLoop, 1000); }; TWM.prototype.render = function () { return (jsx_runtime_1.jsx("div", { style: { top: '0px', right: '0px', position: 'fixed' }, ref: this.toolsNode, className: "displayPanel" }, void 0)); }; return TWM; }(React.Component)); exports.default = TWM;});
复制代码
划线
评论
复制
发布于: 3 小时前阅读数: 5
版权声明: 本文为 InfoQ 作者【Tim】的原创文章。
原文链接:【http://xie.infoq.cn/article/b01b30ce60286ff01c6419d03】。文章转载请联系作者。
Tim
关注
还未添加个人签名 2018.05.01 加入
还未添加个人简介











评论