GithubHelp home page GithubHelp logo

andi23rosca / napi-nim Goto Github PK

View Code? Open in Web Editor NEW
32.0 3.0 0.0 51 KB

Write NodeJS native extensions in Nim

License: MIT License

JavaScript 13.26% Nim 86.74%
nim-lang node-js n-api node-addon nim nim-language

napi-nim's Introduction

Write NodeJS native extensions in Nim

If you don't like the verbosity of C code and feel that C++ is too complex, then try to improve the performance of your NodeJS apps with napi-nim.

The new n-api which is now part of NodeJS lets you interface with JavaScript code from any language that supports the C ABI. Nim is a language that values efficiency above all else, but provides a lot of high level constructs and niceties for developer productivity, making it a very suitable choice for writing performant add-ons to your NodeJS code.

Prerequisites

Since we're building a NodeJS extension in Nim you should install both from:

Make sure you have node-gyp installed globally by doing

npm i -g node-gyp

Installation

Install napi-nim globally

npm i -g napi-nim

Basic usage

To get started run the following command:

napi-nim init hello-world

If it didn't work one of the following things might be the cause:

  • The location in which you ran the command should not contain a folder named hello-world.
  • You need an internet connection when running the command since it does an npm install of the dependencies of the project for you.

If everything went fine the output of the command should say:

DONE Project ready.

Test that it works by building and running:
  cd hello-world
  napi-nim main.nim
  node --napi-modules index.js

napi-nim has now created a new folder in the directory in which you ran the command called hello-world. The folder contains all of the necessary dependencies to start working on your Nim add-on.

Next up, follow the next steps outlined in the output:

  1. cd hello-world to navigate to the project directory.
  2. napi-nim main.nim will compile the Nim file to a C file, and then use node-gyp to build the final NodeJS add-on.
  3. node --napi-modules index.js will run the JS file. the --napi-modules flag ensures that node knows to look for a n-api add-on.

Running the last command should output Hello world in the command line.

API

napi-nim provides a high level API over the classic n-api. This readme might be incomplete, to see all available high level APIs see napi/napibindings.nim.

Defining a module

The init macro will help you define a module initialization proc. The proc definition following it should accept an argument of the type Module.

init proc(module: Module) =

Registering module exports

For exporting properties and functions there are 2 separate templates to use.

init proc(module: Module) =
  # equivalent to module.exports.hello = function () ....
  module.registerFn(0, "hello"):
    echo "hello world"

  # equivalent to module.exports.num = 23
  module.register("num", 23)

Converting between napi_value and Nim types

The node api defines the type napi_value which can take the value of the JS types such as number, string, object, etc. For you to be able to translate between JS types and Nim types and vice-versa, napi-nim exposes a few helpers.

napi_value -> Nim

jsString.getStr # to get the string equivalent
jsNumber.getInt # to convert a js number to int, getInt32/64 and getFloat32/64 are also available

See the rest in napi/napibindings.nim.

Nim -> napi_value

Use the %* operator to convert Nim types to JS. Make sure there's an empty space between the operator and the definition.

let obj = %* {"someProp": 23}

Function with arguments

When registering a function, the first argument should be the number of arguments you expect for it.

You can get the arguments from the args array that is made available by registerFn. Keep in mind the arguments you receive will be JS types so you have to convert to Nim types if you want to use them.

module.registerFn(1, "hello"):
  let toGreet = args[0].getStr; # Getting the first and only argument as a string
  echo "Hello " & toGreet

Low level API

For the things that the high level API might not support yet there's the option to use the lower level functions and types provided by the node_api header. You can see in the rest of the files in napi like napi/jsNativeApi.nim the wrappers which are just Nim type definitions equivalent to the header files from the n-api.

Check the original docs here: https://nodejs.org/api/n-api.html#n_api_basic_n_api_data_types

One function to mention is assessStatus. It checks that a low level api function returns a success, and if not throws an error. You could also use discard instead to ignore the returned status, but it's not recommended.

var
  obj: napi_value
  value: napi_value
assessStatus module.env.napi_create_string_utf8("level", 5, addr value) # create a js string and put it in value
assessStatus module.env.napi_create_object(addr lowObj); # create a js object and put it in obj
assessStatus module.env.napi_set_named_property(obj, "low", value) # Set the property low to be the value string

Roadmap

The project is still new and unfinished. It can already be used to create add-ons but it is missing the following features/nice-to-haves:

  • Examples folder to show how to use.
  • In-depth explanation of the code-base.
  • Collaboration guide.
  • napi-nim init should include bundling and publishing an add-on out of the box. (Right now you have to figure it out yourself ๐Ÿ˜•)

Credit to https://github.com/AjBreidenbach/napibindings which this project is heavily based on. I opted for a new repository instead of PR since it seems that the project is completely abandoned.

napi-nim's People

Contributors

andi23rosca avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

napi-nim's Issues

fatal error: nimbase.h: No such file or directory

I followed the instructions to install on a Linux/Ubuntu, with Nim 1.6.6, but I get the error in title. (I just changed helloworld by chatbot)

I'm using choosenim v.0.7.4. The nimbase.h file is in /home/pcarbonn/.choosenim/toolchains/nim-1.6.6/lib. How can I set it up so that the compiler can find it ?

> napi-nim main.nim
Hint: used config file '/home/pcarbonn/.choosenim/toolchains/nim-1.6.6/config/nim.cfg' [Conf]
Hint: used config file '/home/pcarbonn/.choosenim/toolchains/nim-1.6.6/config/config.nims' [Conf]
.................................................................
/home/pcarbonn/Documents/repos/chatbot/napi/napibindings.nim(63, 55) Warning: implicit conversion to 'cstring' from a non-const location: name; this will become a compile time error in the future [CStringConv]
Hint: gc: refc; opt: none (DEBUG BUILD, `-d:release` generates faster code)
29404 lines; 0.217s; 39.254MiB peakmem; proj: /home/pcarbonn/Documents/repos/chatbot/main.nim; out: /home/pcarbonn/Documents/repos/chatbot/nimcache/main.json [SuccessX]
gyp info it worked if it ends with ok
gyp info using [email protected]
gyp info using [email protected] | linux | x64
gyp info chdir .
gyp info find Python using Python version 3.7.7 found at "/home/linuxbrew/.linuxbrew/opt/python/bin/python3.7"
gyp http GET https://nodejs.org/download/release/v16.13.1/node-v16.13.1-headers.tar.gz
gyp http 200 https://nodejs.org/download/release/v16.13.1/node-v16.13.1-headers.tar.gz
gyp http GET https://nodejs.org/download/release/v16.13.1/SHASUMS256.txt
gyp http 200 https://nodejs.org/download/release/v16.13.1/SHASUMS256.txt
gyp info spawn /home/linuxbrew/.linuxbrew/opt/python/bin/python3.7
gyp info spawn args [
gyp info spawn args   '/home/pcarbonn/.nvm/versions/node/v16.13.1/lib/node_modules/node-gyp/gyp/gyp_main.py',
gyp info spawn args   'binding.gyp',
gyp info spawn args   '-f',
gyp info spawn args   'make',
gyp info spawn args   '-I',
gyp info spawn args   '/home/pcarbonn/Documents/repos/chatbot/build/config.gypi',
gyp info spawn args   '-I',
gyp info spawn args   '/home/pcarbonn/.nvm/versions/node/v16.13.1/lib/node_modules/node-gyp/addon.gypi',
gyp info spawn args   '-I',
gyp info spawn args   '/home/pcarbonn/.cache/node-gyp/16.13.1/include/node/common.gypi',
gyp info spawn args   '-Dlibrary=shared_library',
gyp info spawn args   '-Dvisibility=default',
gyp info spawn args   '-Dnode_root_dir=/home/pcarbonn/.cache/node-gyp/16.13.1',
gyp info spawn args   '-Dnode_gyp_dir=/home/pcarbonn/.nvm/versions/node/v16.13.1/lib/node_modules/node-gyp',
gyp info spawn args   '-Dnode_lib_file=/home/pcarbonn/.cache/node-gyp/16.13.1/<(target_arch)/node.lib',
gyp info spawn args   '-Dmodule_root_dir=/home/pcarbonn/Documents/repos/chatbot',
gyp info spawn args   '-Dnode_engine=v8',
gyp info spawn args   '--depth=.',
gyp info spawn args   '--no-parallel',
gyp info spawn args   '--generator-output',
gyp info spawn args   'build',
gyp info spawn args   '-Goutput_dir=.'
gyp info spawn args ]
gyp info spawn make
gyp info spawn args [ 'BUILDTYPE=Debug', '-C', 'build' ]
make: Entering directory '/home/pcarbonn/Documents/repos/chatbot/build'
  CC(target) Debug/obj.target/main/nimcache/stdlib_digitsutils.nim.o
../nimcache/stdlib_digitsutils.nim.c:4:10: fatal error: nimbase.h: No such file or directory
    4 | #include "nimbase.h"
      |          ^~~~~~~~~~~
compilation terminated.
make: *** [main.target.mk:122: Debug/obj.target/main/nimcache/stdlib_digitsutils.nim.o] Error 1
make: Leaving directory '/home/pcarbonn/Documents/repos/chatbot/build'
gyp ERR! build error 
gyp ERR! stack Error: `make` failed with exit code: 2
gyp ERR! stack     at ChildProcess.onExit (/home/pcarbonn/.nvm/versions/node/v16.13.1/lib/node_modules/node-gyp/lib/build.js:201:23)
gyp ERR! stack     at ChildProcess.emit (node:events:390:28)
gyp ERR! stack     at Process.ChildProcess._handle.onexit (node:internal/child_process:290:12)
gyp ERR! System Linux 5.4.0-122-generic
gyp ERR! command "/home/pcarbonn/.nvm/versions/node/v16.13.1/bin/node" "/home/pcarbonn/.nvm/versions/node/v16.13.1/bin/node-gyp" "rebuild" "--directory=." "--debug"
gyp ERR! cwd /home/pcarbonn/Documents/repos/chatbot
gyp ERR! node -v v16.13.1
gyp ERR! node-gyp -v v9.1.0
gyp ERR! not ok 

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.