stats: {
chunks: false, // 不添加chunk信息
colors: true,
modules: false, // 不添加构建模块信息
}
没有足够的数据
(゚∀゚ )
暂时没有任何数据
kiritoX 回答了问题 · 2019-11-18
stats: {
chunks: false, // 不添加chunk信息
colors: true,
modules: false, // 不添加构建模块信息
}
stats: { chunks: false, // 不添加chunk信息 colors: true, modules: false, // 不添加构建模块信息
关注 4 回答 3
kiritoX 回答了问题 · 2019-04-24
不允许浅更新,加上 --unshallow
不允许浅更新,加上 --unshallow
关注 2 回答 1
kiritoX 回答了问题 · 2019-03-15
入如果pull有这个报错:
fatal: refusing to merge unrelated histories
此项错误是由于本地仓库和远程有不同的开始点,也就是两个仓库没有共同的 commit 出现的无法提交。这里我们需要用到 --allow-unrelated-histories。也就是我们的 pull 命令改为下面这样的:
git pull origin master --allow-unrelated-histories
如果设置了默认分支,可以这样写:
git pull --allow-unrelated-histories
此项错误是由于本地仓库和远程有不同的开始点,也就是两个仓库没有共同的 commit 出现的无法提交。这里我们需要用到 --allow-unrelated-histories。也就是我们的 pull 命令改为下面这样的:
关注 7 回答 5
kiritoX 评论了文章 · 2018-06-08
还记得在我上一家公司中,某一大佬做了一个监控系统,牛逼哄哄,挺想研究他到底是怎么搞出来的。当然我们也不是拍拍脑袋干活的人,总不能人家咋干我们就咋干。下面先就介绍下,这样的平台到底有啥好处。
首先我们为什么要做前端系统呢,先看下面这张表,可以很显然的看出,前端的性能对于产品的价值提升还是蛮有帮助的,但是这些信息如果我们能实时的采集到,并且实施以监控,让整个产品在产品线上一直保持高效的运作,这才是我们的目的。
性能 | 收益 |
---|---|
Google 延迟 400ms | 搜索量下降 0.59% |
Bing 延迟 2s | 收入下降 4.3% |
Yahoo 延迟 400ms | 流量下降 5-9% |
Mozilla 页面打开减少 2.2s | 下载量提升 15.4% |
Netflix 开启 Gzip | 性能提升 13.25% 带宽减少50% |
其次,也有利于我们发布的产品,能够及时发现我们的错误。如果一个产品在新的迭代中,发生不可描述的错误。
对!就是不可描述。我们总不可能等待用户的反馈投诉,到那个时候黄花菜都凉了。
基于以上我们就开始搭建一个前端监简易控平台。(虽然现在市面上有很多这样的系统比如ELK,但是还是忍不住自己撸一个)
只能是简易了。
兄弟们原谅我,只能帮你们到这里了。
接下来请看。
以上是我们需要做的一些事情。
要做监控系统,首先我们得有一个对象。我们监控的对象!对象!对象!对象。
我在我的系统写了一个这样的页面,
<body>
<div>2</div>
<div>2</div>
<div>2</div>
<div>2</div>
<div>2</div>
<div>2</div>
</body>
没错这就是我们要监控的页面。这个.....真不是我懒。
然后接下来我一共设计了3块数据
页面加载时间
window.logInfo = {}; //统计页面加载时间
window.logInfo.openTime = performance.timing.navigationStart;
window.logInfo.whiteScreenTime = +new Date() - window.logInfo.openTime;
document.addEventListener('DOMContentLoaded',function (event) {
window.logInfo.readyTime = +new Date() - window.logInfo.openTime;
});
window.onload = function () {
window.logInfo.allloadTime = +new Date() - window.logInfo.openTime;
window.logInfo.nowTime = new Date().getTime();
var timname = {
whiteScreenTime: '白屏时间',
readyTime: '用户可操作时间',
allloadTime: '总下载时间',
mobile: '使用设备',
nowTime: '时间',
};
var logStr = '';
for (var i in timname) {
console.warn(timname[i] + ':' + window.logInfo[i] + 'ms');
if (i === 'mobile') {
logStr += '&' + i + '=' + window.logInfo[i];
} else {
logStr += '&' + i + '=' + window.logInfo[i];
}
}
(new Image()).src = '/action?' + logStr;
};
统计用户使用设备
window.logInfo.mobile = mobileType();
function mobileType() {
var u = navigator.userAgent, app = navigator.appVersion;
var type = {// 移动终端浏览器版本信息
ios: !!u.match(/\(i[^;]+;( U;)? CPU.+Mac OS X/), //ios终端
iPad: u.indexOf('iPad') > -1, //是否iPad
android: u.indexOf('Android') > -1 || u.indexOf('Linux') > -1, //android终端或者uc浏览器
iPhone: u.indexOf('iPhone') > -1 || u.indexOf('Mac') > -1, //是否为iPhone或者QQHD浏览器
trident: u.indexOf('Trident') > -1, //IE内核
presto: u.indexOf('Presto') > -1, //opera内核
webKit: u.indexOf('AppleWebKit') > -1, //苹果、谷歌内核
gecko: u.indexOf('Gecko') > -1 && u.indexOf('KHTML') == -1, //火狐内核
mobile: !!u.match(/AppleWebKit.*Mobile/i) || !!u.match(/MIDP|SymbianOS|NOKIA|SAMSUNG|LG|NEC|TCL|Alcatel|BIRD|DBTEL|Dopod|PHILIPS|HAIER|LENOVO|MOT-|Nokia|SonyEricsson|SIE-|Amoi|ZTE/), //是否为移动终端
webApp: u.indexOf('Safari') == -1 //是否web应该程序,没有头部与底部
};
var lists = Object.keys(type);
for(var i = 0; i < lists.length; i++) {
if(type[lists[i]]) {
return lists[i];
}
}
}
错误量的统计
window.onload = function () {
window.logInfo.allloadTime = +new Date() - window.logInfo.openTime;
window.logInfo.nowTime = new Date().getTime();
var timname = {
whiteScreenTime: '白屏时间',
readyTime: '用户可操作时间',
allloadTime: '总下载时间',
mobile: '使用设备',
nowTime: '时间',
};
var logStr = '';
for (var i in timname) {
console.warn(timname[i] + ':' + window.logInfo[i] + 'ms');
if (i === 'mobile') {
logStr += '&' + i + '=' + window.logInfo[i];
} else {
logStr += '&' + i + '=' + window.logInfo[i];
}
}
(new Image()).src = '/action?' + logStr;
};
var defaults = {
msg:'', // 错误的具体信息
url:'', // 错误所在的url
line:'', // 错误所在的行
col:'', // 错误所在的列
nowTime: '',// 时间
};
window.onerror = function(msg,url,line,col,error) {
col = col || (window.event && window.event.errorCharacter) || 0;
defaults.url = url;
defaults.line = line;
defaults.col = col;
defaults.nowTime = new Date().getTime();
if (error && error.stack){
// 如果浏览器有堆栈信息,直接使用
defaults.msg = error.stack.toString();
}else if (arguments.callee){
// 尝试通过callee拿堆栈信息
var ext = [];
var fn = arguments.callee.caller;
var floor = 3;
while (fn && (--floor>0)) {
ext.push(fn.toString());
if (fn === fn.caller) {
break;
}
fn = fn.caller;
}
ext = ext.join(",");
defaults.msg = error.stack.toString();
}
var str = ''
for(var i in defaults) {
// console.log(i,defaults[i]);
if(defaults[i] === null || defaults[i] === undefined) {
defaults[i] = 'null';
}
str += '&'+ i + '=' + defaults[i].toString();
}
srt = str.replace('&', '').replace('\n','').replace(/\s/g, '');
(new Image()).src = '/error?' + srt;
}
以上就是收集数据的全部,通过发送/action请求或者是/error请求,这些都是可以自定义的,我讲的只是整个过程是如何实现的。
然后通过我的的一个后台express.js把所有的请求处理并都记录下来,记录好后的数据是这样子的。
user_ip=127.0.0.1&whiteScreenTime=185&readyTime=192&allloadTime=208&mobile=webKit&nowTime=1513071388941
这里我是通过自己写的一段脚本进行解析,parse.js,这里不具体讲解,看源码即可。我展现下解析好的数据。
我以cvs的数据格式储存,因为后面图表的需要,我也支持json格式方式导出,只不过后面就需要你自己来配置可视化的界面了。
数据是这样的。
charts/csvData/2017-12-16time.csv
时间,白屏时间,用户可操作时间,总下载时间
1513427051482,137,137,153
1513427065080,470,471,507
1513427080040,127,127,143
1513428714345,274,275,323
1513428733583,267,268,317
1513428743167,268,268,317
1513428754796,276,276,328
这里我用的是highcharts.js
具体的配置我不进行讲解,可以自己到官网进行查看。
下面是可视化的图表,显示的是每天各个时间段的信息。
界面可能不是特别美观,还请见谅。
node >= 6.0.0
redis >= 2.6.0
在这里我说明下,因为如果这个部署在线上环境的时候,如果每次记录都进行记录的话,会消耗大量的内存,所以我架设了一层redis,为了防止大流量的冲击,然后可以每隔一段时间进行存储。
const express = require('express');
const performance = require('./lib/performance.js');
const app = express();
const router = express.Router();
router.get('/', function (req, res, next) {
req.url = './index.html';
next();
});
app.use(router);
app.use(performance({
time: 10, // 秒为单位
originalDir: './originalData', // 数据的目录
errorDir: './errorData' // 报错的目录
}))
app.use(express.static('./'));
const server = app.listen(3000)
这里可以设置默认的时间,我这里以10秒为单位,为了demo的效果起见。一般我采用的是一分钟进行一次存储。
github地址:https://github.com/hua1995116/mcharts
如有好的建议以及优化的方案,还请各位在Issues上提给我,喜欢的话可以点个star。
我利用这个平台对我的一个项目进行了监控。如果你只是纯粹玩的话,还请只阅读上面的原系统地址,可以忽视我这一段,毕竟我这个系统还不够完善。
项目线上地址:http://www.qiufengh.com/#/
项目监控地址:http://qiufengh.com:8080/
此项目代码地址:https://github.com/hua1995116/webchat/tree/monitoring
在这里我设置了每过1分钟记录一次日志。
// 监控引入
app.use(performance({
time: 60, // 秒为单位
originalDir: './originalData', // 数据的目录
errorDir: './errorData' // 报错的目录
}))
以及每隔10分钟进行一次解析。
function setPrase() {
setInterval(function(){
parseData();
}, 1000 * 60 * 10);
}
原文链接: http://yifenghua.win/html/2017-12-16.html (更完美的阅读体验哦)
还记得在我上一家公司中,某一大佬做了一个监控系统,牛逼哄哄,挺想研究他到底是怎么搞出来的。当然我们也不是拍拍脑袋干活的人,总不能人家咋干我们就咋干。下面先就介绍下,这样的平台到底有啥好处。
kiritoX 评论了文章 · 2018-05-31
前几天想写个小爬虫程序,准备后端就用koa2。于是翻遍github与各大网站,都没找到一个好用的、轻一点的koa2脚手架,也找不到一个清晰些的搭建介绍。github上的脚手架要么是1.x版的koa,要么一堆复杂的依赖。
当然可能还是有写的比较好的吧,只是我没找到。不管怎样吧,我只能亲自上了,就当是学习了。
现在把搭建过程介绍下,看能不能方便下入门的同学。
官方的介绍,是很简单的。
$ npm install koa
const Koa = require('koa')
const app = new Koa()
// response
app.use(ctx => {
ctx.body = 'Hello Koa'
})
app.listen(3000)
好,那我们就先从这开始。创建一个文件夹,命名koa2。(记得先装好node v7.6.0 以上版本)
cd koa2
npm init // 一路回车,根据提示输入信息。
npm install koa --save
然后在文件下根目录下创建程序入口文件:index.js,并把官网介绍那段代码贴进去。之后在命令行中执行
node index.js
打开浏览器,访问 http://localhost:3000/
,可以看到页面输出了 hello world
。
很好,第一步已经踏出去了。相信到这里大部分小白都没问题,之后就开始懵逼了。就这个玩意,我该怎么写接口?怎么连接数据库?
Koa本质上是调用一系列的中间件,来处理对应的请求,并决定是否传递到下一个中间件去处理。我们来写一个最简单的中间件试试。
// 刚才index.js 中的这段代码,我们改写一下。
app.use(ctx => {
ctx.body = 'Hello Koa'
})
// 改成如下
app.use(ctx => {
ctx.body = `您的网址路径为:${ctx.request.url}`
})
这段代码中,app.use
的 function
就是最简单的一个中间件,接受了请求,读出请求路径,并返回到客户端。重新执行下node index.js
,打开浏览器,输入http://localhost:3000/hhhhh
,页面输出了您的网址路径为:hhhhh
。
所以,接口的本质,就是判断不同的请求链接,干不同的事情,返回相应的结果。那么我们得需要一个路由中间件来处理分发请求。开源的时代,当然是拿来主义了。github搜下koa-router,成功找到。根据它的介绍,我们先在项目根目录执行
npm install koa-router --save
然后把index.js
文件再改造下。变成如下:
const Koa = require('koa')
const Router = require('koa-router')
const app = new Koa()
const router = new Router()
// 先注释了,后面再解释
// const bodyParser = require('koa-bodyparser')
// app.use(bodyParser())
router.get('/', ctx => {
ctx.body = `这是主页`
})
router.get('/user', ctx => {
ctx.body = `这是user页`
})
router.get('/post', ctx => {
ctx.body = ctx.request.body
})
router.get('/async', async ctx => {
const sleep = async (ms) => {
return new Promise(resolve => {
setTimeout(() => {
resolve(true)
}, ms)
})
}
await sleep(1000)
ctx.body = `这是异步处理页`
})
app
.use(router.routes())
.use(router.allowedMethods())
app.listen(3000)
重新执行 node index.js
。我们可以看到访问 /
, /user
,/async
,都能得到相应的结果了。
除了那个post的方法,压根得不到自己post的数据。
因为koa是很纯粹的,你提交的数据,它并不会帮你处理。所以这里我们又必须引用一个中间件来处理提交的数据--bodyparser。把上面那两行注释代码解注,就能处理请求数据了。记得要先
npm install koa-bodyparser --save
另外关于async/await
不明白的同学,可以先去看下阮老师的介绍,点击传送门。
不过我们不能把所有的接口都写在这一个文件呀,所以我们得改造下。理一下思路,路由的配置文件应该单独一份,接口的方法应该按业务模块分成一个个controller。说干就干!
先看改造后的目录结构,不想截图,大家将就看看:
-koa2
-node_modules
-controller
user.js
-index.js
-router.js
-package.json
再来看文件变成怎么样了。
// index.js
const Koa = require('koa')
const app = new Koa()
const router = require('./router')
const bodyParser = require('koa-bodyparser')
app.use(bodyParser())
app
.use(router.routes())
.use(router.allowedMethods())
app.listen(3000)
// router.js
const Router = require('koa-router')
const router = new Router()
const user = require('./controller/user')
router.post('/user/login', user.login)
router.get('/user/profile', user.profile)
module.exports = router
// controller/user.js
const sleep = async (ms) => {
return new Promise(resolve => {
setTimeout(() => {
resolve(true)
}, ms)
})
}
module.exports = {
login (ctx) {
ctx.body = {
username: ctx.request.body.username
}
},
async profile (ctx) {
await sleep(1000)
ctx.body = {
username: '相学长',
sex: 'man',
age: '999'
}
}
}
再重新执行 node index.js
。访问相应路由,应该能得到对应的结果了。
好,到此为止,我们的server已经大致完成了,但是我们发现一个很烦的问题就是,每次修改代码都得重新node index.js
,这也太烦了。我希望的是,每次更新代码都能重新执行,并且帮我执行ESlint。其他前端项目webpack那一套,不是webpack配置工程师的话,自己挪过来又改不来。
这里我介绍个简单的方案,nodemon + gulp
。具体呢就不一步步来了,这种东西,不用太了解,能run起来满足自己需求就好。如果不需要eslint的话,只要安装nodemon就好。
package.json scripts部分 修改为:
"scripts": {
"nodemon": "nodemon index.js"
}
然后命令行执行:
npm install nodemon --save-dev
npm run nodemon
如果有eslint的需求的话,就稍微麻烦些了,eslint的init我就不贴教程了,我贴上我的gulp配置文件:
// gulpfile.js
const gulp = require('gulp')
const lint = require('gulp-eslint')
const nodemon = require('gulp-nodemon')
function lintFiles (files) {
return gulp.src(files)
.pipe(lint())
.pipe(lint.format())
// .pipe(lint.failAfterError())
}
gulp.task('eslint', () => lintFiles(['**/*.js', '!node_modules/**']))
gulp.task('eslint_nodemon', ['eslint'], () => {
return nodemon({
script: './app/server.js', // 项目入口文件
tasks (changedFiles) {
lintFiles(changedFiles)
return []
},
ignore: ['build/**', 'dist/**', '.git', 'node_modules/**']
})
})
gulp.task('default', ['eslint_nodemon'])
// package.json scripts
"scripts": {
"start": "pm2 start index.js --watch", // 这里用pm2 作为线上run,有兴趣的同学可以自己去看看
"dev": "gulp",
"lint": "eslint .",
"fix": "eslint --fix ."
},
到这里,我想应该能让一部分同学上手了。
但这只是初步的搭建了下koa。真的想投入使用,根据业务需求,可能还需要安装数据库驱动等中间件。对于复杂业务场景的server,还需要更加合理的设计controller,service,在这里就不多阐述了。
如果这篇文章,能够帮助到一些同学,下次有空再写写这方面相关的。
ps: 文章介绍的所有代码都传了一份到github,有需要的同学请自行去看。
地址:https://github.com/wuomzfx/koa2
查看原文前几天想写个小爬虫程序,准备后端就用koa2。于是翻遍github与各大网站,都没找到一个好用的、轻一点的koa2脚手架,也找不到一个清晰些的搭建介绍。github上的脚手架要么是1.x版的koa,要么一堆复杂的依赖。
kiritoX 回答了问题 · 2018-04-17
改lib包里面的的东西,也就是楼上老哥说的mian入口文件里的东西,不过这里大多都是webpack打包过的,不建议修改,很容易出锅
改lib包里面的的东西,也就是楼上老哥说的mian入口文件里的东西,不过这里大多都是webpack打包过的,不建议修改,很容易出锅
关注 7 回答 3
kiritoX 关注了用户 · 2018-02-02
从事软件开发 20 年,在软件分析、设计、架构、开发及软件开发技术研究和培训等方面有着非常丰富的经验,近年主要在研究 Web 前端技术、基于 .NET 的后端开发技术和相关软件架构。
从事软件开发 20 年,在软件分析、设计、架构、开发及软件开发技术研究和培训等方面有着非常丰富的经验,近年主要在研究 Web 前端技术、基于 .NET 的后端开发技术和相关软件架构。有新课:TypeScript从入门到实践【2020版】 来关注下!欢迎搜索并关注公众号“边城客栈...
关注 11015
kiritoX 关注了用户 · 2018-02-02
[链接]我以为我摸到的是象腿,实际上是🐘的屁股,不要问我咋知道的欢迎用微信联系我: yujiabuao
关注 3695
查看全部 个人动态 →
(゚∀゚ )
暂时没有
(゚∀゚ )
暂时没有
注册于 2017-09-05
个人主页被 288 人浏览
推荐关注