使用Node.js为其他程序编写扩展的基本方法

前端之家收集整理的这篇文章主要介绍了使用Node.js为其他程序编写扩展的基本方法前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。

准备开始

首先我们用下面的目录结构来创建一个节点通知(node-notify)文件夹.

代码如下:

这个看起来很漂亮的tree 用通用的 tree 生成.

现在让我来创建测试脚本demo.js 和决定我们扩展的API前期看起来应该像:

var notification = new notify.notification();
notification.title = "Notification title";
notification.icon = "emblem-default"; // see /usr/share/icons/gnome/16x16
notification.send("Notification message");

编写我们的Node.js扩展 Init方法

为了创建一个Node.js扩展,我们需要编写一个继承node::ObjectWrap的C++类。 ObjectWrap 实现了让我们更容易与Javascript交互的公共方法

我们先来编写类的基本框架:

// v8 is the Javascript engine used by QNode #include // We will need the following libraries for our GTK+ notification #include #include #include

using namespace v8;

class Gtknotify : node::ObjectWrap {
private:
public:
Gtknotify() {}
~Gtknotify() {}
static void Init(Handle target) {
// This is what Node will call when we load the extension through require(),see boilerplate code below.
}
};

/*

v8::Persistent Gtknotify::persistent_function_template;
extern "C" { // Cause of name mangling in C++,we use extern C here
static void init(Handle target) {
Gtknotify::Init(target);
}
// @see http://github.com/ry/node/blob/v0.2.0/src/node.h#L101
NODE_MODULE(gtknotify,init);
}

现在,我们必须把下面的代码编写到我们的Init()方法中:

声明构造函数,并将其绑定到我们的目标变量。var n = require("notification");将绑定notification() 到 n:n.notification().

local_function_template = v8::FunctionTemplate::New(New);

// Make it persistent and assign it to persistent_function_template which is a static attribute of our class.
Gtknotify::persistent_function_template = v8::Persistent::New(local_function_template);

// Each JavaScript object keeps a reference to the C++ object for which it is a wrapper with an internal field.
Gtknotify::persistent_function_template->InstanceTemplate()->SetInternalFieldCount(1); // 1 since a constructor function only references 1 object
// Set a "class" name for objects created with our constructor
Gtknotify::persistent_function_template->SetClassName(v8::String::NewSymbol("Notification"));

// Set the "notification" property of our target variable and assign it to our constructor function
target->Set(String::NewSymbol("notification"),Gtknotify::persistent_function_template->GetFunction());

声明属性:n.title 和n.icon.

InstanceTemplate()->SetAccessor(String::New("title"),GetTitle,SetTitle); Gtknotify::persistent_function_template->InstanceTemplate()->SetAccessor(String::New("icon"),GetIcon,SetIcon); // For instance,n.title = "foo" will now call SetTitle("foo"),n.title will now call GetTitle()
声明原型方法:n.send()
方法看起来应该是这样的:
sql;"> // Our constructor static v8::Persistent persistent_function_template;

static void Init(Handle target) {
v8::HandleScope scope; // used by v8 for garbage collection

// Our constructor
v8::Local local_function_template = v8::FunctionTemplate::New(New);
Gtknotify::persistent_function_template = v8::Persistent::New(local_function_template);
Gtknotify::persistent_function_template->InstanceTemplate()->SetInternalFieldCount(1); // 1 since this is a constructor function
Gtknotify::persistent_function_template->SetClassName(v8::String::NewSymbol("Notification"));

// Our getters and setters
Gtknotify::persistent_function_template->InstanceTemplate()->SetAccessor(String::New("title"),SetTitle);
Gtknotify::persistent_function_template->InstanceTemplate()->SetAccessor(String::New("icon"),SetIcon);

// Our methods
NODE_SET_PROTOTYPE_METHOD(Gtknotify::persistent_function_template,Send);

// Binding our constructor function to the target variable
target->Set(String::NewSymbol("notification"),Gtknotify::persistent_function_template->GetFunction());
}

方法中用的C++方法:New,SetTitle,SetIcon,Send

构造器方法: New()

New() 方法创建了我们自定义类的新实例(一个 Gtknotify 对象),并设置一些初始值,然后返回该对象的 JavaScript 处理。这是 JavaScript 使用 new 操作符调用构造函数的期望行为。

std::string title;
std::string icon;

// new notification()
static Handle New(const Arguments& args) {
HandleScope scope;
Gtknotify* gtknotify_instance = new Gtknotify();
// Set some default values
gtknotify_instance->title = "Node.js";
gtknotify_instance->icon = "terminal";

// Wrap our C++ object as a Javascript object
gtknotify_instance->Wrap(args.This());

return args.This();
}
getters 和 setters: GetTitle(),SetTitle(),GetIcon(),SetIcon()

下面主要是一些样板代码,可以归结为 C++ 和 JavaScript (v8) 之间的值转换。

GetTitle(v8::Local property,const v8::AccessorInfo& info) { // Extract the C++ request object from the JavaScript wrapper. Gtknotify* gtknotify_instance = node::ObjectWrap::Unwrap(info.Holder()); return v8::String::New(gtknotify_instance->title.c_str()); } // this.title= static void SetTitle(Local property,Local value,const AccessorInfo& info) { Gtknotify* gtknotify_instance = node::ObjectWrap::Unwrap(info.Holder()); v8::String::Utf8Value v8str(value); gtknotify_instance->title = *v8str; } // this.icon static v8::Handle GetIcon(v8::Local property,const v8::AccessorInfo& info) { // Extract the C++ request object from the JavaScript wrapper. Gtknotify* gtknotify_instance = node::ObjectWrap::Unwrap(info.Holder()); return v8::String::New(gtknotify_instance->icon.c_str()); } // this.icon= static void SetIcon(Local property,const AccessorInfo& info) { Gtknotify* gtknotify_instance = node::ObjectWrap::Unwrap(info.Holder()); v8::String::Utf8Value v8str(value); gtknotify_instance->icon = *v8str; }

原型方法: Send()

首先我们抽取 C++ 对象的 this 引用,然后使用对象的属性来构建通知显示

Send(const Arguments& args) { v8::HandleScope scope; // Extract C++ object reference from "this" Gtknotify* gtknotify_instance = node::ObjectWrap::Unwrap(args.This());

// Convert first argument to V8 String
v8::String::Utf8Value v8str(args[0]);

// For more info on the Notify library: http://library.gnome.org/devel/libnotify/0.7/NotifyNotification.html
Notify::init("Basic");
// Arguments: title,content,icon
Notify::Notification n(gtknotify_instance->title.c_str(),v8str,gtknotify_instance->icon.c_str()); // v8str points to the C string it wraps
// Display the notification
n.show();
// Return value
return v8::Boolean::New(true);
}

编译扩展

node-waf 是一个构建工具,用来编译 Node 的扩展,这是 waf 的基本封装。构建过程可通过名为 wscript 的文件进行配置。

def configure(conf):
conf.check_tool("compiler_cxx")
conf.check_tool("node_addon")

This will tell the compiler to link our extension with the gtkmm and libnotifymm libraries.

conf.check_cfg(package='gtkmm-2.4',args='--cflags --libs',uselib_store='LIBGTKMM')
conf.check_cfg(package='libnotifymm-1.0',uselib_store='LIBNOTIFYMM')

def build(bld):
obj = bld.new_task_gen("cxx","shlib","node_addon")
obj.cxxflags = ["-g","-D_FILE_OFFSET_BITS=64","-D_LARGEFILE_SOURCE","-Wall"]

This is the name of our extension.

obj.target = "gtknotify"
obj.source = "src/node_gtknotify.cpp"
obj.uselib = ['LIBGTKMM','LIBNOTIFYMM']

现在我们已经准备好要开始构建了,在顶级目录下运行如下命令:

node-waf configure && node-waf build

如果一切正常,我们将得到编译过的扩展,位于:./build/default/gtknotify.node ,来试试:

var notif = require('./build/default/gtknotify.node'); > n = new notif.notification(); { icon: 'terminal',title: 'Node.js' } > n.send("Hello World!"); true

上述的代码将在你的屏幕右上方显示一个通知信息。

打成npm包

这是非常酷的,但是怎样与Node社区分享你的努力的成果呢? 这才是npm主要的用途: 使它更加容易扩展和分发.

打npm的扩展包是非常简单的. 你所要做的就是在你的顶级目录中创建一个包含你的扩展信息的文件package.json :

名称 (不要在名称中包含node 或者 js,这是隐式关键字). // 这是通过require() 导入扩展的名称.

"name" : "notify",// Version should be http://semver.org/ compliant

"version" : "v0.1.0"

// 这些脚本将在调用npm安装和npm卸载的时候运行.,"scripts" : {
"preinstall" : "node-waf configure && node-waf build","preuninstall" : "rm -rf build/*"
}

// 这是构建我们扩展的相对路径.,"main" : "build/default/gtknotify.node"

// 以下是可选字段:,"description" : "Description of the extension....","homepage" : "https://github.com/olalonde/node-notify","author" : {
"name" : "Olivier Lalonde","email" : "olalonde@gmail.com","url" : "http://www.syskall.com/"
},"repository" : {
"type" : "git","url" : "https://github.com/olalonde/node-notify.git"
}
}

关于package.json 格式的更多细节,可以通过 npm help json 获取文档. 注意 大多数字段都是可选的.

你现在可以在你的顶级目录中通过运行npm install 来安装你的新的npm包了. 如果一切顺利的话,应该可以简单的加载你的扩展 var notify = require('你的包名');. 另外一个比较有用的命令式 npm link 通过这个命令你可以创建一个到你开发目录的链接,当你的代码发生变化时不必每次都去安装/卸载.

假设你写了一个很酷的扩展,你可能想要在中央npm库发布到网上. 首先你要先创建一个账户:

下一步,回到你的根目录编码并且运行:

$ npm publish

就是这样,你的包现在已经可以被任何人通过npm install 你的包名命令来安装了.

猜你在找的JavaScript相关文章