Gowhich

Durban's Blog

使用插件google的prettify和jquery的format 完成了一套很完美的代码高亮显示,还能自动格式化。

先说jquery.format的接入【我这里开发是用的webpack】

在引入文件中使用reqiure方法,把jquery.format加入到js代码中。

1
require('./jquery.format.js');

jquery.format.js 这个文件我放在了与引入文件同级的目录下

就可以样就可以了。

在说引入prettify到react中,这个当然是在html页面中进行的了,所以在html中引入

1
2
<script src="https://cdn.bootcss.com/prettify/r298/prettify.min.js?skin=sunburst"></script>
<script src="https://cdn.bootcss.com/prettify/r298/lang-sql.min.js?skin=sunburst"></script>

就这样就可以了。

然后把我们需要的高亮代码的css也加入进来吧

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
pre .str, code .str { color: #65B042; } /* string  - green */
pre .kwd, code .kwd { color: #E28964; } /* keyword - dark pink */
pre .com, code .com { color: #AEAEAE; font-style: italic; } /* comment - gray */
pre .typ, code .typ { color: #89bdff; } /* type - light blue */
pre .lit, code .lit { color: #3387CC; } /* literal - blue */
pre .pun, code .pun { color: #fff; } /* punctuation - white */
pre .pln, code .pln { color: #fff; } /* plaintext - white */
pre .tag, code .tag { color: #89bdff; } /* html/xml tag - light blue */
pre .atn, code .atn { color: #bdb76b; } /* html/xml attribute name - khaki */
pre .atv, code .atv { color: #65B042; } /* html/xml attribute value - green */
pre .dec, code .dec { color: #3387CC; } /* decimal - blue */
pre.prettyprint, code.prettyprint {
background-color: #000;
-moz-border-radius: 8px;
-webkit-border-radius: 8px;
-o-border-radius: 8px;
-ms-border-radius: 8px;
-khtml-border-radius: 8px;
border-radius: 8px;
}
pre.prettyprint {
width: 95%;
margin: 0.2em auto;
padding: 1em;
white-space: pre-wrap;
}
/* Specify class=linenums on a pre to get line numbering */
ol.linenums { margin-top: 0; margin-bottom: 0; color: #AEAEAE; } /* IE indents via margin-left */
li.L0,li.L1,li.L2,li.L3,li.L5,li.L6,li.L7,li.L8 { list-style-type: none }
/* Alternate shading for lines */
li.L1,li.L3,li.L5,li.L7,li.L9 { }
@media print {
pre .str, code .str { color: #060; }
pre .kwd, code .kwd { color: #006; font-weight: bold; }
pre .com, code .com { color: #600; font-style: italic; }
pre .typ, code .typ { color: #404; font-weight: bold; }
pre .lit, code .lit { color: #044; }
pre .pun, code .pun { color: #440; }
pre .pln, code .pln { color: #000; }
pre .tag, code .tag { color: #006; font-weight: bold; }
pre .atn, code .atn { color: #404; }
pre .atv, code .atv { color: #060; }
}

最后看下react里面是如何操作的

在render方法里面操作,稍微有点基础知识的肯定都知道的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
render:function(){
if(this.props.data.length > 0){
return (
<table className="table table-striped table-bordered table-hover table-responsive">
<thead>
<colgroup>
<col width="5%"></col>
<col></col>
<col width="20%"></col>
<col width="20%"></col>
<col width="10%"></col>
</colgroup>
<tr>
<th>ID号</th>
<th>SQL Template</th>
<th>参数</th>
<th>备注</th>
<th>创建日期</th>
</tr>
</thead>
<tbody id="itemContainer">
{this.props.data.map(function(i){
let ctime = moment.unix(i.ctime).format('YYYY-MM-DD');
let template = $.format(i.template, {'method':'sql'});
let config = $.format(i.config, {'method':'json'});
return (
<tr key={i.autokid}>
<td>{i.autokid}</td>
<td style={{'wordWrap':'break-word','wordBreak':'break-all','verticalAlign':'top'}} >
<pre className="prettyprint">
<code className="language-sql">{template}</code>
</pre>
</td>
<td style={{'verticalAlign':'top'}}>
<pre className="prettyprint">
<code className="language-js">{config}</code>
</pre>
</td>
<td style={{'verticalAlign':'top'}}>{i.comment} bezhu de qing</td>
<td style={{'verticalAlign':'top'}}>{ctime}</td>
</tr>
);
})}
</tbody>
</table>
);
}else{
return <Loading type='spinning-bubbles' color='#e3e3e3'/>;
}
}

最后为了是的pretty的效果产生我们还要进行一个启动的操作

1
2
3
4
5
6
componentDidMount(){
prettyPrint();
},
componentDidUpdate(){
prettyPrint();
},

可以了,就是这样的。

以下支持的Nodejs版本是 >=4.2.1

在express中我们都知道,我们可以在文件中定义一个方法,如下,然后可以在router中调用这个方法进行相应的处理。但是我们不想一直去写一些回调的方法,

希望对于异步的处理能像写顺序编程那样一直按照逻辑顺序去执行,co就帮了我们一个大忙,试试如下这种方式吧。【前提是要安装下co】

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
module.exports.addBackground = function (req, res, next) {
let title = req.body.title || '';
let theme = req.body.theme || '';
let theorder = req.body.theorder || 0;
let big_url = req.body.big_url || '';
let thumb_url = req.body.thumb_url || '';
let mtime = parseInt(new Date().valueOf() / 1000);
if (!title || !theme || !big_url || !thumb_url) {
throw new Error('Arguments is Error.');
}
co(function *() {
let _isAdmin = yield User.isAdmin(req.user.id);
if (!_isAdmin) {
throw new Error('Admin only.');
}
let e_sql = 'SELECT * FROM xxxxx.app_dft_background where title = ' + mysql.escape(title);
let e_res = yield mysql.thunkQuery(e_sql);
if (e_res.length > 0) {
return false;
}
let sql = sqlBuilder.makeInsertSql('xxxxx.app_dft_background', {
title: title,
theme: theme,
theorder: theorder,
big_url: big_url,
thumb_url: thumb_url,
mtime: mtime
});
let res = yield mysql.thunkQuery(sql);
return res;
}).then((data) => {
if (!data) {
res.json({'success': false, 'message': '名称已存在'});
} else {
res.json({'success': true, 'data': data});
}
}).catch((err) => {
next(err);
});
};

如果还是没有理解清楚可以去看下co和Promise。很容易理解的

做web网站开发一般都会分为三个环节:开发阶段【开发模式】、调试阶段【调试模式】、部署阶段【部署模式】

在Node的环境中:


开发阶段我们希望能够即使响应我们的开发速度,node启动的方式大家都知道 node app.js ,如果中间有修改的话,就不能即使响应了,需要我们自己再去重新启动。

所以我们的开发阶段最好是安装一下supervisor

安装

1
npm install --save-dev supervisor

启动

1
supervisor app.js or supervisor www/bin

【此种方法启动,需要作为一个全局去安装supervisor】

我的实践是把package.json里的start

1
2
3
4
"scripts": {
"d": "node-debug app.js",
"start": "./node_modules/.bin/supervisor app.js"
}

然后

1
npm start

调试阶段,我们肯定是希望监测每个请求的响应结果,一旦出现问题可以直接更加友好的展示给我们:

推荐node-inspector

安装

1
npm install --save node-inspector

启动

1
node-inspector app.js or node-debug www/bin

【此种方法启动,需要作为一个全局去安装supervisor】

我的实践是把package.json里的d里

1
2
3
4
"scripts": {
"d": "./node_modules/.bin/node-debug app.js",
"start": "./node_modules/.bin/supervisor app.js"
}

然后执行

1
npm run d

部署阶段就是我们通常所说的生产环境或者是产品上线

推荐使用pm2

pm2是非常优秀工具,它提供对基于node.js的项目运行托管服务。它基于命令行界面,提供很多特性:

内置的负载均衡器(使用nodecluster module)

以守护进程运行

0s(不间断)重启

为ubuntu/ CentOS 提供启动脚本

关闭不稳定的进程(避免无限死循环)

基于控制台监控

HTTP API

远程控制以及实时监控接口

pm2使用nodecluster构建一个内置的负载均衡器。部署多个app的实例来达到分流的目的以减轻单app处理的压力。

安装pm2

1
npm install -g pm2

查看基本帮助文档

Basic Examples:

Start an app using all CPUs available + set a name :

$ pm2 start app.js -i 0 --name "api"

Restart the previous app launched, by name :

$ pm2 restart api

Stop the app :

$ pm2 stop api

Restart the app that is stopped :

$ pm2 restart api

Remove the app from the process list :

$ pm2 delete api

Kill daemon pm2 :

$ pm2 kill

Update pm2 :

$ npm install pm2@latest -g ; pm2 updatePM2

More examples in https://github.com/Unitech/pm2#usagefeatures

Deployment help:

$ pm2 deploy help

上面基本是我们比较常用的

我们也可以把启动信息写入到json配置文件中->ecosystem.json

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
{
"apps": [
{
"name": "web.0",
"max_memory_restart": "1024M",
"log_date_format": "YYYY-MM-DD HH:mm:ss SSS",
"script": "/var/www/web/bundle/main.js",
"out_file": "/var/log/web/app.0.log",
"error_file": "/var/log/web/err.0.log",
"port": "8080",
"env": {
"CDN_PREFIX": "//dbde4sd21oahf.cloudfront.net",
"MONGO_URL": "mongodb://localhost:27017/web",
"MONGO_OPLOG_URL": "mongodb://localhost:27017/local",
"ROOT_URL": "http://web.com",
"PORT": "8080"
}
},
{
"name": "web.1",
"max_memory_restart": "1024M",
"log_date_format": "YYYY-MM-DD HH:mm:ss SSS",
"script": "/var/www/web/bundle/main.js",
"out_file": "/var/log/web/app.1.log",
"error_file": "/var/log/web/err.1.log",
"port": "8081",
"env": {
"CDN_PREFIX": "//dbde4sd21oahf.cloudfront.net",
"MONGO_URL": "mongodb://localhost:27017/web",
"MONGO_OPLOG_URL": "mongodb://localhost:27017/local",
"ROOT_URL": "http://web.com",
"PORT": "8081"
}
},
{
"name": "web.2",
"max_memory_restart": "1024M",
"log_date_format": "YYYY-MM-DD HH:mm:ss SSS",
"script": "/var/www/web/bundle/main.js",
"out_file": "/var/log/web/app.2.log",
"error_file": "/var/log/web/err.2.log",
"port": "8082",
"env": {
"CDN_PREFIX": "//dbde4sd21oahf.cloudfront.net",
"MONGO_URL": "mongodb://localhost:27017/web",
"MONGO_OPLOG_URL": "mongodb://localhost:27017/local",
"ROOT_URL": "http://web.com",
"PORT": "8082"
}
},
{
"name": "web.3",
"max_memory_restart": "1024M",
"log_date_format": "YYYY-MM-DD HH:mm:ss SSS",
"script": "/var/www/web/bundle/main.js",
"out_file": "/var/log/web/app.3.log",
"error_file": "/var/log/web/err.3.log",
"port": "8083",
"env": {
"CDN_PREFIX": "//dbde4sd21oahf.cloudfront.net",
"MONGO_URL": "mongodb://localhost:27017/web",
"MONGO_OPLOG_URL": "mongodb://localhost:27017/local",
"ROOT_URL": "http://web.com",
"PORT": "8083"
}
}
]
}

pm2的当然还有一些其他的用法:

1、pm2远程部署

1
pm2 deploy ecosystem.json production setup

2、pm2 cluster启动

1
pm2 start app.js -i 0 --name "apps"

3、pm2 重启实例

1
pm2 reload <name>

4、pm2 命令行监测

1
pm2 monit

5、pm2 查看实例日志

1
pm2 logs 或 pm2 logs <name> 或 pm2 flush

6、pm2 开机启动

1
pm2 startup <ubuntu|centos|gentoo|systemd>

7、pm2 web方式监测

1
pm2 web

之后要考虑的就是服务器的监测以及如果给node做反向代理

比如:

nginx或haproxy的部署,也可以使用nginx+passenger进行部署

mongodb的部署

mysql的部署

redis的部署

还要对服务器进行压测

apache ab

wrk

以及性能调优和监控

本文主要是引入官方的使用,如果此时间较晚,可到官方查看较新使用说明:

React.PropTypes 提供很多验证器 (validator) 来验证传入数据的有效性。当向 props 传入无效数据时,JavaScript 控制台会抛出警告。注意为了性能考虑,只在开发环境验证 propTypes。下面用例子来说明不同验证器的区别:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
React.createClass({
propTypes: {
// 可以声明 prop 为指定的 JS 基本类型。默认
// 情况下,这些 prop 都是可传可不传的。
optionalArray: React.PropTypes.array,
optionalBool: React.PropTypes.bool,
optionalFunc: React.PropTypes.func,
optionalNumber: React.PropTypes.number,
optionalObject: React.PropTypes.object,
optionalString: React.PropTypes.string,

// 所有可以被渲染的对象:数字,
// 字符串,DOM 元素或包含这些类型的数组。
optionalNode: React.PropTypes.node,

// React 元素
optionalElement: React.PropTypes.element,

// 用 JS 的 instanceof 操作符声明 prop 为类的实例。
optionalMessage: React.PropTypes.instanceOf(Message),

// 用 enum 来限制 prop 只接受指定的值。
optionalEnum: React.PropTypes.oneOf(['News', 'Photos']),

// 指定的多个对象类型中的一个
optionalUnion: React.PropTypes.oneOfType([
React.PropTypes.string,
React.PropTypes.number,
React.PropTypes.instanceOf(Message)
]),

// 指定类型组成的数组
optionalArrayOf: React.PropTypes.arrayOf(React.PropTypes.number),

// 指定类型的属性构成的对象
optionalObjectOf: React.PropTypes.objectOf(React.PropTypes.number),

// 特定形状参数的对象
optionalObjectWithShape: React.PropTypes.shape({
color: React.PropTypes.string,
fontSize: React.PropTypes.number
}),

// 以后任意类型加上 `isRequired` 来使 prop 不可空。
requiredFunc: React.PropTypes.func.isRequired,

// 不可空的任意类型
requiredAny: React.PropTypes.any.isRequired,

// 自定义验证器。如果验证失败需要返回一个 Error 对象。不要直接
// 使用 `console.warn` 或抛异常,因为这样 `oneOfType` 会失效。
customProp: function(props, propName, componentName) {
if (!/matchme/.test(props[propName])) {
return new Error('Validation failed!');
}
}
},
/* ... */});

来个示例,网上找了很久了,没发现同时添加多个字段的例子,我英文比较差,只能靠猜了,结果还真成了。

1
2
3
ALTER TABLE `record` 
ADD COLUMN `rate_name` varchar(16) NOT NULL COMMENT '货币k值' AFTER `money`,
ADD COLUMN `rate_money` decimal(16,4) NOT NULL COMMENT '货币汇率' AFTER `rate_name`,LOCK=SHARED;
1
2
3
4
5
ALTER TABLE `record_list` 
ADD COLUMN `rate_name` varchar(16) NOT NULL COMMENT '货币K值' AFTER `mtime`,
ADD COLUMN `rate_list` varchar(32) NOT NULL COMMENT '货币ID组合' AFTER `rate_name`,
ADD COLUMN `list_rate_budget` decimal(16,4) NOT NULL COMMENT '预算汇率金额' AFTER `rate_list`,
ADD COLUMN `date_start` bigint(20) NOT NULL COMMENT '起始日' AFTER `list_rate_budget`,LOCK=SHARED;

如下摘自原文档:https://dev.mysql.com/doc/refman/5.7/en/alter-table.html

LOCK = DEFAULT

Maximum level of concurrency for the given ALGORITHM clause (if any) and ALTER TABLE operation: Permit concurrent reads and writes if supported. If not, permit concurrent reads if supported. If not, enforce exclusive access.

LOCK = NONE

如果MYSQL支持, 则同时发生度读操作和写操作. Otherwise, return an error message.

LOCK = SHARED

如果MYSQL支持, 则允许并发读取但是阻塞写入。 Note that writes will be blocked even if concurrent writes are supported by the storage engine for the given ALGORITHM clause (if any) and ALTER TABLE operation. If concurrent reads are not supported, return an error message.

LOCK = EXCLUSIVE

实施独占访问. This will be done even if concurrent reads/writes are supported by the storage engine for the given ALGORITHM clause (if any) and ALTER TABLE operation

估计会翻译有误,不过大概意思是这样的

IntelliJ IDEA开源社区 提供了如下通用激活方法:

注册时选择License server

然后输入框填写:http://idea.lanyus.com/

然后点击 OK,就搞定了。

JetBrains注册码计算: idea.lanyus.com/

===================截至目前为止,上面的方式已经无效了===========

可以进入http://idea.lanyus.com/ 自己去找方案

我这里把我使用的过程需要注意的点说下

IntelliJIDEALicenseServer 使用方法

首先下载指定版本的IntelliJIDEALicenseServer,解压文件夹,进入文件夹,跟自己的系统的情况指定指定的文件,对于linux或者unix系统,最好到终端去执行。如果是win的话就请随意吧。

可以指定端口 指定用户的哟。

1
2
3
4
5
6
7
8
9
10
╰─➤  ./IntelliJIDEALicenseServer_darwin_amd64 -p 41015 -u durban                                                                                                                                                                          1 ↵
2016/07/21 13:21:39 *************************************************************
2016/07/21 13:21:39 ** IntelliJ IDEA License Server **
2016/07/21 13:21:39 ** by: ilanyu **
2016/07/21 13:21:39 ** http://www.lanyus.com/ **
2016/07/21 13:21:39 ** Alipay donation: xx@xx **
2016/07/21 13:21:39 ** Please support genuine!!! **
2016/07/21 13:21:39 ** listen on 0.0.0.0:41015... **
2016/07/21 13:21:39 ** You can use http://127.0.0.1:41015 as license server **
2016/07/21 13:21:39 *************************************************************

经过几天的努力终于实现了一个完美的作品,webpack可以与gulp完美结合的进行打包静态文件,并将静态文件上传到七牛云存储,当然也可以传到你想传的云存储了,这里只分享一个七牛的云存储方案。

关于如何使用webpack打包静态代码,这个可以参考我之前的一些文章和方案,不行的话可以进群交流。

这里只分享一下gulp这边的操作,然后给一个例子实现如何一条命令打包静态文件并更新cdn文件的方法。

先展示一下gulpfile.js文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
const gulp = require('gulp');
const uglify = require('gulp-uglify');
const concat = require('gulp-concat');
const shrink = require('gulp-cssshrink');
const webpack = require('gulp-webpack');
const qn = require('gulp-qn');
// MD5戳
const rev = require('gulp-rev-qn');
const revCollector = require('gulp-rev-collector');
const runSequence = require('run-sequence');
const config = require('./webpack.config');
const qiniu_options = {
accessKey: 'xxx',
secretKey: 'xxx',
bucket: 'xxx',
domain: 'http://xxx.com'
};
gulp.task('publish-js', function () {
return gulp.src(['./build/js/*.js'])
.pipe(uglify())
.pipe(rev())
.pipe(gulp.dest('./build/js'))
.pipe(qn({
qiniu: qiniu_options,
prefix: 'js'
}))
.pipe(rev.manifest())
.pipe(gulp.dest('./build/rev/js'));
});
gulp.task('publish-font-img', function () {
return gulp.src(['./build/js/*.svg','./build/js/*.gif','./build/js/*.woff2','./build/js/*.ttf','./build/js/*.eot','./build/js/*.woff'])
.pipe(qn({
qiniu: qiniu_options,
prefix: 'js'
}));
});
gulp.task('publish-css', function () {
return gulp.src(['./build/js/*.css'])
.pipe(rev())
.pipe(gulp.dest('./build/js'))
.pipe(qn({
qiniu: qiniu_options,
prefix: 'css'
}))
.pipe(rev.manifest())
.pipe(gulp.dest('./build/rev/css'));
});
gulp.task('publish-html', function () {
return gulp.src(['./build/rev/**/*.json', './build/views/*.html'])
.pipe(revCollector({
dirReplacements: {
'/js/': ''
}
}))
.pipe(gulp.dest('./build/views'));
});
gulp.task('default',function(callback){
runSequence(
['publish-css','publish-js','publish-font-img'],
'publish-html',
callback);
});

publish-js部分是将我的js文件进行版本更新并上传到七牛。

publish-font-img部分是将我的字体文件、图片文件上传到七牛

publish-css部分是将我的css文件进行版本更新并上传到七牛

publish-html将我html文件中对应的js路径进行替换,好了,可以直接发布这个build文件夹下的文件了。

激活后可免费使用200M流量VPN:

点击如下链接可免费获取:免费VPN


以上已不再免费,稳定的VPN可点击这里进行购买

前提是远程仓库已经存在某个分支,本地并没有对应的分支【这是情景描述前提】

对应的标题操作很简单,方法如下:

1
git fetch origin remote_branch:local_branch

koa2.0.0 的路由和视图渲染完之后的一个问题就是,如何高效的开发前端代码。

因为我之前的前端代码是用webpack进行打包,然后打包过程中,使用babel实现了,ES6语法的转换,这行我就不能太干脆的丢弃webpack,然后里面使用了react+react-router+reflux,整个开发体系还是比较可以的。为了整合之前的代码,需要将之前的connect框架改为koa2.0.0,毕竟koa的实现方式还有与express,connect等这样的框架,实现方式不太一样,所以,稍微还有有点小困难,不过我这里记录下,也就不困难了。

从webpack-dev-server说起,我们使用webpack-dev-server是为了能够时时监控我们的代码改变,然后用它自己的socket-io去刷新我们的页面,实现了代码修改即页面重载,当然只是在开发环境。

webpack-dev-server并没有多大的改变,只是将原来的一个proxy的操作去掉了,然后整合到koa的启动文件里面了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
const webpack = require('webpack');
const WebpackDevServer = require('webpack-dev-server');
const config = require('./webpack.config.development');
const debug = require('debug');
new WebpackDevServer(webpack(config), {
publicPath: config.output.publicPath,
hot: true,
noInfo: false,
historyApiFallback: true,
stats: { colors: true },
headers: { 'Access-Control-Allow-Origin': '*' }
}).listen(8080, '127.0.0.1', function(err,result) {
if (err) {
console.log(err);
}
console.log('Webpack Listening at 127.0.0.1:8080');
});

关于webpack的config文件的代码是不需要改变的,继续使用。

下面就是在koa的启动文件里面加入启动需要的proxy处理。

1
2
3
4
5
//解析 开发环境 development
app.use(convert(proxy({
host:'http://127.0.0.1:8080/js',
match: /^\/js\//
})));

就这么简单,这里使用了两个中间件:

koa-proxy,koa-convert。

解释一下好了,就是将访问的path中有带/js/部分的路径,进行重新proxy一下就好,这样就将文件转向到了webpack-dev-server这边的对应的文件了。相关的其他的问题可以参考我之前的几篇文章.

0%