自建开发工具系列 -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. … yes
Ejecting...
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.js
index 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.js
index 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.json
index 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 加入
还未添加个人简介
评论