在项目中采用nodejs作中间层,作页面的首屏渲染,同时采用express做为主web框架,其中express的router页面路由我采用ts语言来编写。以下:javascript
//page.ts 文件 import request = require('request'); module.exports = function(router) { router.get('/', function(req, resp) { resp.render('xxx/page'); }); };
编写完ts后运行tsc命令将相应的ts文件编译为对应的js文件,以下:html
//page.js 文件 var request = require('request'); module.exports = function(router) { router.get('/', function(req, resp) { resp.render('xxx/page'); }); };
其实这里只是import
变成了var
而已,但其意义在于在ts代码中采用import
载入的模块能够享用强类型检查,以及代码自动补全,预编译检查等。java
可是在启动node服务时却报错,错误信息以下:node
Debugger listening on port 45864 /Users/WebSite/routes/xxx/page.ts:8 import request = require('request'); ^^^^^^ SyntaxError: Unexpected reserved word at exports.runInThisContext (vm.js:53:16) at Module._compile (module.js:373:25) at Object.Module._extensions..js (module.js:416:10) at Module.load (module.js:343:32) at Function.Module._load (module.js:300:12) at Module.require (module.js:353:17) at require (internal/module.js:12:17) ...
提示import
关键字非法,是保留字不能使用,在搜了Google以及Stackflow以后发现虽然提问的人不少,但几乎没人回答正确的解决方案,搜索无果后只能本身查为何会出现这个问题。web
在受到stackoverflow上某一个回答(http://stackoverflow.com/a/23113558/6001468) 的启发后,发现个人路由代码的code.ts和编译后的code.js文件都在express下的router文件夹下,而经过在这两个文件分别输出log发现均会输出,而实际上我但愿只有.js文件被识别,ts文件在编译完成后就再也不参与node的执行。
因此问题的缘由就在于本不该该被node载入的.ts也被拉去进行执行。express
经过断点后发现,问题的缘由在于核心模块的module.js
文件里面的343行:json
// Given a file name, pass it to the proper extension handler. Module.prototype.load = function(filename) { debug('load %j for module %j', filename, this.id); assert(!this.loaded); this.filename = filename; this.paths = Module._nodeModulePaths(path.dirname(filename)); var extension = path.extname(filename) || '.js'; if (!Module._extensions[extension]) extension = '.js'; Module._extensions[extension](this, filename); this.loaded = true; };
在倒数第4行,若是某个文件的扩展名没有在Module._extensions
字典内的文件,均被强制识别为.js文件,而后按照js代码去执行。而_extensions
字典内只有js,json和node文件,以下图:
api
因此问题找到了,可是由于module.js是核心模块,不能修改其代码,因此只能去更上层的Express的代码去改。框架
在node_modules/express-enrouten/lib/directory.js
中,有一个isFileModule
的函数,用来判断当前文件是否一个模块,从而来决定是否要用node去加载它,能够经过修改这个函数来达到目的。ide
/** * Returns true if `require` is able to load the provided file * or false if not. * http://nodejs.org/api/modules.html#modules_file_modules * @param file the file for which to determine module-ness. * @returns {boolean} */ function isFileModule(file) { var ext = path.extname(file); // 新增:若是文件扩展名是.ts则不进行加载 --xxcanghai@博客园 if(ext === ".ts") { return false; } // Omit dotfiles // NOTE: Temporary fix in lieu of more complete (cross platform) // fix using file flags/attributes. if (path.basename(file, ext)[0] === '.') { return false; } try { // remove the file extension and use require.resolve to resolve known // file types eg. CoffeeScript. Will throw if not found/loadable by node. file = ext ? file.slice(0, -ext.length) : file; require.resolve(file); return true; } catch (err) { return false; } }
若是当前文件的扩展名是.ts则判断为非模块,而不去加载。
修改后问题解决了。
虽然问题解决了,可是修改框架代码这种事实际上是有很是多的坑的,并且我本人也极力反感这种行为。
好比之后如何面临框架升级,还有由于修改了源码而带来的其余bug怎么办,等等。
可是目前现阶段而言有没有什么其余更好的办法,因此只能先这样了,若是有哪位博客园友知道能好的解决方案,还望不吝赐教。
完