abbshr.github.io icon indicating copy to clipboard operation
abbshr.github.io copied to clipboard

动手实现一个Custom-Node.js

Open abbshr opened this issue 9 years ago • 0 comments

了解Node.js的运行机理之后就有能力对其进行custom了,我们可以尝试着DIY一个node-v0.10.31.(1)

涉及源码

  • node.gyp: Node.js构建编译所用配置文件
  • lib/

我要custom那些东西呢? 我尚未拜读v8的API,况且C++水平略渣,因此暂且不理会depssrc/*.cc这两个目录,从最贴近现实处入手: lib/src/node.js.

修改src/node.js最合适不过了,因为这是官方推荐的自定义Node核心功能的方法.其实还可以扩充Node的JavaScript核心模块组,我这次玩的就是这个.

我向lib目录里添加了read.iwebsocket,这两个是我之前写的Node扩展模块,这次把他们跟Node核心模块整合,哈哈.

read.i用于增强Node.js的接受用户输入的能力, websocket用于扩展Node.js的应用层协议,提供websocket协议支持.

添加核心模块

准备read.i的源码read.i.js,拷贝到lib目录下. 既然read是提供读取,我们不妨让他使用的便捷一些:

  // 这里我修改了src/node.js中初始化全局变量的函数
  // 将read.i模块添加到gloabl变量中
  startup.globalVariables = function() {
    global.process = process;
    global.global = global;
    global.GLOBAL = global;
    global.root = global;
    global.Buffer = NativeModule.require('buffer').Buffer;
    process.binding('buffer').setFastBufferConstructor(global.Buffer);
    process.domain = null;
    process._exiting = false;
    // 添加read变量
    global.read = NativeModule.require('read');
  };

ok,编译一下

./configure
sudo make && ./node

然后你惊讶的发现报错了是吧,Node根本没找到你的模块! 原因是你并没有在node.gyp中添加新的模块,下面修改以下node.gyp:

{
  'variables': {
    'v8_use_snapshot%': 'true',
    'node_use_dtrace%': 'false',
    'node_use_etw%': 'false',
    'node_use_perfctr%': 'false',
    'node_has_winsdk%': 'false',
    'node_shared_v8%': 'false',
    'node_shared_zlib%': 'false',
    'node_shared_http_parser%': 'false',
    'node_shared_cares%': 'false',
    'node_shared_libuv%': 'false',
    'node_use_openssl%': 'true',
    'node_use_systemtap%': 'false',
    'node_shared_openssl%': 'false',
    'library_files': [
      'src/node.js',
      'lib/_debugger.js',
      'lib/_linklist.js',
      'lib/assert.js',
      'lib/buffer.js',
      'lib/child_process.js',
      'lib/console.js',
      'lib/constants.js',
      'lib/crypto.js',
      'lib/cluster.js',
      'lib/dgram.js',
      'lib/dns.js',
      'lib/domain.js',
      'lib/events.js',
      'lib/freelist.js',
      'lib/fs.js',
      'lib/http.js',
      'lib/https.js',
      'lib/module.js',
      'lib/net.js',
      'lib/os.js',
      'lib/path.js',
      'lib/punycode.js',
      'lib/querystring.js',
      'lib/readline.js',
      'lib/repl.js',
      'lib/stream.js',
      'lib/_stream_readable.js',
      'lib/_stream_writable.js',
      'lib/_stream_duplex.js',
      'lib/_stream_transform.js',
      'lib/_stream_passthrough.js',
      'lib/string_decoder.js',
      'lib/sys.js',
      'lib/timers.js',
      'lib/tls.js',
      'lib/tty.js',
      'lib/url.js',
      'lib/util.js',
      'lib/vm.js',
      'lib/zlib.js',
      # 这里添加新的模块路径
      'lib/read.js',
    ],
  },
  ....
  ....
}

再次编译,执行./node,就能调用我们的read模块了,同时也可以直接使用,当然这个模块在REPL环境中是无效的,仅作用于普通模式.

下面添加websocket模块.过程类似,只不过我的这个模块是由多个相互依赖的文件组成.

注: 每个通过require或NativeModule.require的模块,其文件必须首先添加进node.gyp的library_files子节点下.并且在Node编译时,会将这个节点数组中所有文件均编译成独立的核心模块!

因此,如果有多个依赖的话,就一个不剩的添加到node.gyp里,经过编译之后,这些模块的名称就是它的文件名.所以不能有两个index.js,在添加时一定要注意.

然后修改依赖文件和主文件中的require,把所有require的文件路径统统改成模块的文件名(不包含扩展名). like this:

var utils = require('index');
var Client = require('client');
var datarecv_handler = require('datarecv_handler');

经过编译,我们的node-v10.31.1私人定制版就新鲜出炉了.

当然,除了添加模块之外还有好多事可以做,比如修改模块加载方式,Node的运行模式等等.

abbshr avatar Aug 29 '14 06:08 abbshr