node-cube
Advanced tools
Comparing version 0.2.1 to 0.2.2
59
index.js
@@ -47,7 +47,12 @@ /*! | ||
* - resBase {String} [optional] the http base for resource | ||
* - scope {String} [optional] set the module scope, like '@ali' | ||
* - scope {String} [optional] set the module scope, like '@ali' [X] | ||
* - devCache {Boolean} default true | ||
* | ||
*/ | ||
function Cube(config) { | ||
// remove the last slash(\|/) in config.root | ||
config.root = config.root.replace(/[\\\/]$/, ''); | ||
if (config.devCache === undefined) { | ||
config.devCache = true; | ||
} | ||
this.config = config; | ||
@@ -116,3 +121,3 @@ /** | ||
* - middleware boolean, default false | ||
* - processors {type, ext, processor, forceOverride} | ||
* - processors {Array} extenal processors | ||
*/ | ||
@@ -144,2 +149,7 @@ Cube.init = function (config) { | ||
* @param {String|Object} mod mod can be a string(module path) or an mod object | ||
* a module shoud contain { | ||
* ext: {String|Array} | ||
* type: {String} | ||
* process: {Function} | ||
* } | ||
* @param {Boolean} force set force will override the origin register | ||
@@ -161,25 +171,34 @@ */ | ||
} | ||
info = Processor.info; | ||
if (typeof info !== 'object') { | ||
return console.error('[CUBE_ERRROR] processor formatter error, no info found', mod); | ||
if (Processor.info) { | ||
type = Processor.info.type; | ||
ext = Processor.info.ext; | ||
} else { | ||
type = Processor.type; | ||
ext = Processor.ext; | ||
} | ||
type = info.type; | ||
ext = info.ext; | ||
if (!type || !ext) { | ||
return console.error('[CUBE_ERRROR] formatter error, no info found', mod); | ||
if (!type || !ext || !Processor.prototype.process) { | ||
return console.error('[CUBE_ERRROR] processor error, en processor should contain properties `name`, `type`, `ext`, `process`'); | ||
} | ||
var types = processors.types[type]; | ||
if (!types) { | ||
// register new type | ||
types = processors.types[type] = {}; | ||
} | ||
if (!processors.map[ext]) { | ||
processors.map[ext] = type; | ||
if (!Array.isArray(ext)) { | ||
ext = [ext]; | ||
} | ||
var origin = types[ext]; | ||
if (origin && !force) { | ||
var err = new Error('the ext `' + ext + '` is already binded, you should pass `force` param to override it!'); | ||
err.code = 'CUBE_BIND_TRANSFER_ERROR'; | ||
throw err; | ||
} | ||
types[ext] = new Processor(this); | ||
var self = this; | ||
ext.forEach(function (extName) { | ||
if (!processors.map[extName]) { | ||
processors.map[extName] = type; | ||
} | ||
var origin = types[extName]; | ||
if (origin && !force) { | ||
var err = new Error('the ext `' + extName + '` is already binded, you should pass `force` param to override it!'); | ||
err.code = 'CUBE_BIND_TRANSFER_ERROR'; | ||
throw err; | ||
} | ||
types[extName] = new Processor(self); | ||
}); | ||
}; | ||
@@ -201,3 +220,3 @@ | ||
/** 修订css文件中的资源文件中的路径 **/ | ||
Cube.prototype.fixupResPath= function (dir, code) { | ||
Cube.prototype.fixupResPath = function (dir, code) { | ||
var base = this.config.resBase || ''; | ||
@@ -227,3 +246,3 @@ return code.replace(/url\( *([\'\"]*)([^\'\"\)]+)\1 *\)/ig, function (m0, m1, m2) { | ||
return 'Cube("' + utils.moduleName(qpath, 'template', options.release) + | ||
'",' + JSON.stringify(require) + ',function(module,exports,require){' + code +'; return module.exports});'; | ||
'",' + JSON.stringify(require) + ',function(module,exports,require){' + code + '; return module.exports});'; | ||
}; | ||
@@ -230,0 +249,0 @@ |
@@ -12,7 +12,6 @@ var path = require('path'); | ||
} | ||
CoffeeProcessor.info = { | ||
type: 'script', | ||
ext: '.coffee' | ||
}; | ||
CoffeeProcessor.type = 'script'; | ||
CoffeeProcessor.ext = '.coffee'; | ||
CoffeeProcessor.prototype = { | ||
@@ -23,3 +22,3 @@ /** | ||
* @param {Object} options {root: path, compress:boolean, sourceMap:boolean, moduleWrap} | ||
* @param {Function} callback({err, data:{source, code, sourceMap}}) | ||
* @param {Function} callback({err, data:{source, code, sourceMap}}) | ||
*/ | ||
@@ -26,0 +25,0 @@ process: function (file, options, callback) { |
var fs = require('fs'); | ||
var path = require('path'); | ||
var css = require('clean-css'); | ||
var Css = require('clean-css'); | ||
@@ -9,6 +9,4 @@ function CssProcessor(cube) { | ||
CssProcessor.info = { | ||
type: 'style', | ||
ext: '.css' | ||
}; | ||
CssProcessor.type = 'style'; | ||
CssProcessor.ext = '.css'; | ||
@@ -27,3 +25,3 @@ CssProcessor.prototype = { | ||
try { | ||
result.code = new css({ | ||
result.code = new Css({ | ||
compatibility: true, | ||
@@ -46,2 +44,2 @@ noAdvanced: true, | ||
module.exports = CssProcessor; | ||
module.exports = CssProcessor; |
@@ -14,6 +14,4 @@ /*! | ||
HtmlProcessor.info = { | ||
type: 'template', | ||
ext: '.html' | ||
}; | ||
HtmlProcessor.type = 'template'; | ||
HtmlProcessor.ext = '.html'; | ||
@@ -20,0 +18,0 @@ HtmlProcessor.prototype = { |
@@ -112,7 +112,7 @@ /*! | ||
function tryNodeModules(cube, root, dir, module) { | ||
var node_modules_path = path.join(dir, '/node_modules/'); | ||
var nodeModulesPath = path.join(dir, '/node_modules/'); | ||
var modp; | ||
// search node_modules, if match return | ||
try { | ||
modp = testModPath(cube, root, path.join(root, node_modules_path, module)); | ||
modp = testModPath(cube, root, path.join(root, nodeModulesPath, module)); | ||
return modp; | ||
@@ -124,3 +124,3 @@ } catch (e) { | ||
// search node_modules with namespace | ||
var flist = fs.readdirSync(path.join(root, node_modules_path)); | ||
var flist = fs.readdirSync(path.join(root, nodeModulesPath)); | ||
var parr = []; | ||
@@ -130,3 +130,3 @@ | ||
if (v.indexOf('@') === 0) { | ||
parr.push(path.join(root, node_modules_path, v, module)); | ||
parr.push(path.join(root, nodeModulesPath, v, module)); | ||
} | ||
@@ -163,3 +163,3 @@ }); | ||
while (dir) { | ||
count ++; | ||
count++; | ||
try { | ||
@@ -184,5 +184,3 @@ p = tryNodeModules(cube, root, dir, module); | ||
} | ||
} | ||
// if abs path: like "/jquery" | ||
else if (/^\//.test(module)) { | ||
} else if (/^\//.test(module)) { // if abs path: like "/jquery" | ||
debug('module type: abs_module', module); | ||
@@ -363,2 +361,4 @@ //abs path | ||
JsProcessor.type = 'script'; | ||
JsProcessor.ext = '.js'; | ||
JsProcessor.requires = {}; | ||
@@ -570,7 +570,2 @@ | ||
JsProcessor.info = { | ||
type: 'script', | ||
ext: '.js' | ||
}; | ||
module.exports = JsProcessor; |
@@ -8,3 +8,3 @@ var debug = require('debug')('cube'); | ||
var matchedExts = []; | ||
for(var i = 0, len = arr.length; i < len; i++) { | ||
for (var i = 0, len = arr.length; i < len; i++) { | ||
tmp = arr[i]; | ||
@@ -11,0 +11,0 @@ if (tmp.indexOf(fName + '.') !== 0) { |
@@ -5,3 +5,3 @@ { | ||
"description": "a new way to write js in browser", | ||
"version": "0.2.1", | ||
"version": "0.2.2", | ||
"homepage": "https://github.com/fishbar/cube", | ||
@@ -8,0 +8,0 @@ "repository": { |
@@ -135,2 +135,4 @@ Cube | ||
maxAge: // 浏览器端文件缓存时间,最终会应用到http头:Cache-Control: public, maxAge=xxx | ||
processors: ['cube-ejs', 'cube-jade'] // load extra processors, 确保你的依赖中有这些模块 | ||
devCache: // boolean 开发模式下是否开启缓存, 默认开启 | ||
} | ||
@@ -157,3 +159,3 @@ ``` | ||
--with-source create source file 指定是否输出源文件 | ||
-r, --resbase [value] the http base for resouce 指定css中的资源文件 http路径的base | ||
-r, --resbase [value] the http base for resouce 指定css中的资源文件 http路径的base | ||
--merge if merged dependences into on file 是否合并 | ||
@@ -180,27 +182,3 @@ ``` | ||
... | ||
在上面 | ||
## why cube | ||
每一个web应用都有一包静态资源 | ||
每一个web应用的静态资源,都应该被设计成可自由部署 (static.server/path, 虽然很多时候静态资源都在同域下) | ||
每一个web应用都会包含这么一个目录叫静态资源, 比如: | ||
```sh | ||
webapp -| | ||
| - wwwroot | << 静态资源目录 | ||
| - js | ||
| - css | ||
| - imgs | ||
``` | ||
在设计前端框架的时候,通常都会考虑到这点:前端资源需要可以被方便的部署到CDN等资源(动静态资源分离) | ||
cube的运行模式就是遵循这一设计思路的 | ||
cube的初始化就从这个wwwroot开始,进入wwwroot目录,cube内建静态资源服务,启动服务: | ||
根据命令行提示的地址访问, ok,你的前端资源可以像node.js一样编写了。 | ||
cube让前端开发模块化,更好的代码组织方式,让代码轻松复用。 | ||
cube集成各种工具,让coffee,styl,jade,ejs,less等等默认支持,选择你所熟悉的工具。 | ||
cube支持扩展,你可以动手集成插件进入其中。 | ||
138
service.js
@@ -12,3 +12,15 @@ /*! | ||
var utils = require('./lib/utils'); | ||
var Event = require('events').EventEmitter; | ||
/** | ||
* CACHE { | ||
* realPath: { | ||
* mtime: | ||
* mime: | ||
* code: | ||
* } | ||
* } | ||
* @type {Object} | ||
*/ | ||
var CACHE = {}; | ||
/** | ||
* init cube | ||
@@ -23,3 +35,3 @@ * | ||
*/ | ||
exports.init = function(cube, config) { | ||
exports.init = function (cube, config) { | ||
if (config.middleware === undefined) { | ||
@@ -35,3 +47,3 @@ config.middleware = false; | ||
if (!xfs.existsSync(config.cached)) { | ||
config.cached = false; | ||
config.cached = false; | ||
} | ||
@@ -42,3 +54,3 @@ | ||
serveStatic = connectStatic(config.cached ? config.cached : config.root, { | ||
maxAge: config.maxAge | ||
maxAge: config.maxAge | ||
}); | ||
@@ -50,2 +62,3 @@ | ||
var ext = path.extname(qpath); | ||
var cachePath; | ||
if (qpath === '/') { | ||
@@ -60,4 +73,4 @@ req.url = '/index.html'; | ||
req.query = qs.parse(queryString); | ||
debug('parse request query object', req.query); | ||
} | ||
debug('query file', qpath); | ||
@@ -70,2 +83,3 @@ | ||
} | ||
var mime = cube.getMIMEType(type); | ||
var ps = cube.processors.types[type]; | ||
@@ -77,19 +91,37 @@ var options = { | ||
compress: req.query.c === undefined ? false : true, | ||
qpath: qpath | ||
}; | ||
cachePath = qpath + ':' + options.moduleWrap + ':' + options.compress; | ||
debug('recognize file type: %s', type); | ||
// seek for realpath | ||
utils.seekFile(cube, root, qpath, ps, function (err, realPath, ext, processor) { | ||
if (err) { | ||
debug('seek file error', err, options); | ||
if (type === 'script' && options.moduleWrap) { | ||
res.statusCode = 200; | ||
res.end('console.error("[CUBE]",' + JSON.stringify(err.stack) + ');'); | ||
return ; | ||
var evt = new Event(); | ||
var origEtag = req.headers.etag; | ||
var realPath; | ||
evt.on('error', function (code, msg) { | ||
res.statusCode = code || 500; | ||
res.end(msg || 'server error'); | ||
}); | ||
evt.on('seekfile', function (rpath, processor) { | ||
var tmp = CACHE[cachePath]; | ||
realPath = rpath; | ||
xfs.lstat(path.join(options.root, rpath), function (err, stats) { | ||
if (err) { | ||
return evt.emit('error', 500, 'read file stats error:' + err.message); | ||
} | ||
res.statusCode = 404; | ||
return res.end('file not found:' + qpath); | ||
} | ||
debug('query: %s target: %s type: %s %s', qpath, realPath, type, cube.mimeType[type]); | ||
options.qpath = qpath; | ||
var mtime = new Date(stats.mtime).getTime(); | ||
if (tmp) { // if cached, check cache | ||
if (tmp.mtime === mtime) { // target the cache, just return | ||
debug('hint cache', realPath); | ||
evt.emit('end', tmp.mime, tmp.code); | ||
} else { | ||
evt.emit('process', rpath, processor, mtime); | ||
} | ||
} else { | ||
evt.emit('process', rpath, processor, mtime); | ||
} | ||
}); | ||
}); | ||
evt.on('process', function (realPath, processor, mtime) { | ||
processor.process(realPath, options, function (err, result) { | ||
@@ -99,31 +131,55 @@ if (err) { | ||
if (options.moduleWrap) { | ||
res.statusCode = 200; | ||
res.end('console.error("[CUBE]",' + JSON.stringify(err.message) + ');'); | ||
evt.emit('error', 200, 'console.error("[CUBE]",' + JSON.stringify(err.message) + ');'); | ||
} else { | ||
res.statusCode = 500; | ||
res.end(err.message); | ||
evt.emit('error', 500, err.message); | ||
} | ||
return; | ||
} | ||
// resule {source, code, wraped} | ||
var code; | ||
var mime; | ||
if (options.moduleWrap) { | ||
code = result.wraped !== undefined ? result.wraped : result.code; | ||
mime = cube.getMIMEType('script'); | ||
evt.emit('processEnd', result, mtime); | ||
}); | ||
}); | ||
evt.on('processEnd', function (result, mtime) { | ||
var code; | ||
if (options.moduleWrap) { | ||
code = result.wraped !== undefined ? result.wraped : result.code; | ||
mime = cube.getMIMEType('script'); | ||
} else { | ||
if (options.compress) { | ||
code = result.code; | ||
} else if (realPath === qpath) { | ||
code = result.source; | ||
} else { | ||
if (options.compress) { | ||
code = result.code; | ||
} else if (realPath === qpath) { | ||
code = result.source; | ||
} else { | ||
code = result.code; | ||
} | ||
mime = cube.getMIMEType(type); | ||
code = result.code; | ||
} | ||
res.statusCode = 200; | ||
res.setHeader('content-type', mime); // fix #10 | ||
res.end(code); | ||
}); | ||
} | ||
if (cube.config.devCache) { | ||
debug('cache processed file: %s, %s' + realPath, mtime); | ||
CACHE[cachePath] = { | ||
mtime: mtime, | ||
mime: mime, | ||
code: code | ||
}; | ||
} | ||
evt.emit('end', mime, code); | ||
}); | ||
evt.on('end', function (mime, code) { | ||
res.statusCode = 200; | ||
res.setHeader('content-type', mime); // fix #10 | ||
res.end(code); | ||
}); | ||
// seek for realpath | ||
utils.seekFile(cube, root, qpath, ps, function (err, realPath, ext, processor) { | ||
if (err) { | ||
debug('seek file error', err, options); | ||
if (type === 'script' && options.moduleWrap) { | ||
res.setHeader('content-type', mime); | ||
evt.emit('error', 200, 'console.error("[CUBE]",' + JSON.stringify(err.stack) + ');'); | ||
} else { | ||
evt.emit('error', 404, 'file not found:' + qpath); | ||
} | ||
return ; | ||
} | ||
debug('query: %s target: %s type: %s %s', qpath, realPath, type, cube.mimeType[type]); | ||
evt.emit('seekfile', realPath, processor); | ||
}); | ||
} | ||
@@ -141,5 +197,3 @@ // return middleware | ||
} | ||
// other static files | ||
if (!config.middleware && config.port) { | ||
@@ -146,0 +200,0 @@ app.listen(config.port, function (err) { |
14
tools.js
@@ -19,3 +19,3 @@ var xfs = require('xfs'); | ||
} | ||
var _ignore = []; | ||
var ignore = []; | ||
ignoreRules.forEach(function (v, i, a) { | ||
@@ -28,5 +28,5 @@ if (!v) { | ||
} | ||
_ignore.push(new RegExp(v.replace(/\./g, '\\.').replace(/\*/g, '.*'))); | ||
ignore.push(new RegExp(v.replace(/\./g, '\\.').replace(/\*/g, '.*'))); | ||
}); | ||
return _ignore; | ||
return ignore; | ||
} | ||
@@ -37,3 +37,3 @@ | ||
var rule; | ||
for (var i = 0; i < ignores.length; i++){ | ||
for (var i = 0; i < ignores.length; i++) { | ||
rule = ignores[i]; | ||
@@ -68,3 +68,3 @@ if (rule.test(file)) { | ||
} | ||
fileCount ++; | ||
fileCount++; | ||
@@ -137,3 +137,3 @@ var relFile = sourceFile.substr(root.length); | ||
root: cube.config.root, | ||
qpath: relFile, | ||
qpath: relFile | ||
}; | ||
@@ -175,2 +175,2 @@ var st = new Date().getTime(); | ||
exports.processFile = processFile; | ||
exports.processDir = processDir; | ||
exports.processDir = processDir; |
Sorry, the diff of this file is not supported yet
266840
2845
182