不知道雪球在用Node.js?你。。。你。。。你是社区新人吧
不知道雪球在用Node.js?你。。。你。。。你是社区新人吧
为什么这么说?
@undoZen at NodeParty 2012.06
全球化的投资交流平台,给投资者提供跨市场、跨品种的数据查询、新闻订阅和互动交流服务,目前已覆盖A股、港股、美股市场。
“价值投资通往财务自由”
雪球 xueqiu.com 是国内少有的将 Node.js 用作生产环境的公司之一
我们会保持技术探索和实践
并将实战经验回馈开源社区
Evented I/O for JavaScript.
Proved server-side JavaScript could do great.
Question:你们用 node 写后端?
Answer:No. node 只有前端团队在用。后端用 Java。
“大前端”:面向用户的工程师
目标:看得舒服 用的方便 访问快速
//server.js
fs.writeFileSync(pidsDir+'/master.pid', process.pid)
var master = new cluster.Master()
master.register(1234, './current/app.js', { cnum: forkNum })
master.dispatch()
//app.js
if (process.hasOwnProperty('send')) {
require('node-cluster').ready(function(socket) {
app.emit('connection', socket)
})
}
//seamless restart
kill -s USR1 `cat $PIDSDIR/master.pid` #sh
kill -s SIGUSR1 `cat $PIDSDIR/master.pid` #bash
r = snowball(req)
r.Request(CONFIG.Domain.base + path, data, ...
req.api()?
req.api('base', path, data, ... ?
req.api.base(path, data, ...
function Api (req) {
this.req = req
}
Api.prototype.request = function(url/*, ...*/) { /*...*/ }
Object.keys(CONFIG.Domain).forEach(function(domain) {
Api.prototype[domain] = function(path/*, ...*/) {
this.request(CONFIG.Domain[domain] + path/*, ...*/)
}
})
//req.api().base(path, ...)
http.IncomingMessage.prototype.api = function() {
return this._api || (this._api = new Api(this))
}
function Api (req) {
this.req = req
}
Api.prototype.request = function(url/*, ...*/) { /*...*/ }
Object.keys(CONFIG.Domain).forEach(function(domain) {
Api.prototype[domain] = function(path/*, ...*/) {
this.request(CONFIG.Domain[domain] + path/*, ...*/)
}
})
//req.api.base(path, ...)
http.IncomingMessage.prototype.__defineGetter__('api', function() {
return this._api || (this._api = new Api(this))
})
http.createServer(function(req, res) {
http.request({
hostname: CONFIG.proxyHost
, path: req.url
, method: req.method
, port: CONFIG.proxyPort
, headers: req.headers
}, function(_res) {
res.statusCode = _res.statusCode
Object.keys(_res.headers).forEach(function(name){
res.setHeader(name, _res.headers[name])
}
_res.pipe(res)
})
}).listen(8080)
res.on('data', function(data) {
buffers.push(data)
len += data.length
})
res.on('end', function() {
var body = new Buffer(len)
, i = 0
buffers.forEach(function (buffer) {
buffer.copy(body, i, 0, buffer.length)
i += buffer.length
})
callback(null, body.toString('utf8'))
})
if (needApiProxy) { // 通过比如 req.url 以 'json' 结尾来判断
// ...
needHostAdjust = headers.host != 'xueqiu.com'
if (needHostAdjust) {
if (isApiRequest) {
headers.host = 'api.xueqiu.com'
} else {
headers.host = 'xueqiu.com'
}
}
// http.request(...
Object.keys(_res.headers).forEach(function(name) {
if ('set-cookie' === name && needHostAdjust) {
var _headers = _res.headers[name].map(function(cookie) {
return cookie.replace(/\sdomain=[^\s$]*/gi, '')
})
res.setHeader(name, _headers)
} else {
res.setHeader(name, _res.headers[name])
}
})
1a. add bootstrap as a dependency in package.json
"bootstrap":
"https://github.com/xueqiu/bootstrap/tarball/master"
1b. add bootstrap as a submodule
git submodule add \
https://github.com/xueqiu/bootstrap.git \
submodules/bootstrap
2. cp node_modules/bootstrap/less/bootstrap.less \
static/style
3. modify @import path, for example:
@import "../../node_modules/bootstrap/less/reset.less";
4.lessc command or connect-assets
1. install using npm, in package.json:
dependencies: { "connect-assets": "latest" }
2. var assets = require('connect-assets')
3. app.use(assets({ src: 'static' })
// 默认 src: 'assets'
4. css.root = 'style'
// 默认 css.root = 'style'
5. in x.jade:
html
head
!= css('bootstrap.css')
// 寻找 static/style/bootstrap.{css,less,styl}
!= js('bootstrap.js')
1. static/js/bootstrap.js
//= require bootstrap/bootstrap-modal.js
2. in x.jade:
!= js('bootstrap.js')
//connect-assets
//a.js
window.a = 2
//b.js
window.a = 1
//= require a.js
console.log(window.a)
//actual execution
window.a = 2 //a.js
window.a = 1 //b.js
console.log(window.a)
//seajs
//a.js
define(function(){
window.a = 2
})
//b.js
define(function(require){
window.a = 1
require('a')
console.log(window.a)
})
//html
//<script>seajs.use('b')</script>
npm install spm -g
spm build srcdir --combine --app_url './'
// use spm as a node module
new require('spm').Build([srcdir], {
combine: true
, app_url: './'
, out_path: destdir
, compiler_options: { ascii_only: true }
}).run()
console.log(jade.compile('p#hello hello, world!', {
client: true
, compileDebug: false }).toString())
function anonymous(locals, attrs, escape, rethrow) {
var attrs = jade.attrs, escape = jade.escape,
rethrow = jade.rethrow;
var buf = [];
with (locals || {}) {
var interp;
buf.push('<p');
buf.push(attrs({ 'id':('hello') }));
buf.push('>hello, world!</p>');
}
return buf.join("");
}
var t = 'window.Templates = {}'
fs.readdirSync(cjdir).forEach(function(filename) {
var p = path.join(cjdir, filename)
var j = fs.readFileSync(p, 'utf8')
t += 'window.Templates.'+filename+'='+jade.compile(j, {
client: true
, compileDebug: false }).toString()
})
fs.writeFileSync(templatesjspath, t, 'utf8')
//provided as /js/client/test.jade.js
'define(function(require, exports, module) {\n'
+ jade.compile(content, { client: true, ...
+ '\nmodule.exports = anonymous\n})'
//test.js
define(function (require) {
var tmpl = require('./client/test.jade')
console.log(tmpl({ name: 'World' })
})
//in html
<script>seajs.use('test.js')</script>
//部署到生产环境 ./client/test.jade.js 会并入 test.js