Skip to content

Commit 8d82b7f

Browse files
committed
feat(pages): add N-API pages
1 parent 345bd7f commit 8d82b7f

20 files changed

Lines changed: 1584 additions & 1 deletion

components/Sidebar/index.jsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ const PrefetchLink = props => <a {...props} rel="prefetch" />;
1111
*/
1212
export default ({ metadata }) => (
1313
<SideBar
14-
pathname={`/learn${metadata.path}`}
14+
pathname={`/learn${metadata.path.replace('/index', '')}`}
1515
groups={sidebar}
1616
onSelect={redirect}
1717
as={PrefetchLink}

pages/napi/build-tools/cmake-js.md

Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
---
2+
authors: gabrielschulhof, NickNaso, jschlight, mhdawson, KevinEady, avivkeller
3+
---
4+
5+
# CMake.js
6+
7+
[CMake.js](https://github.com/cmake-js/cmake-js) is good build tool alternative to [node-gyp](/learn/napi/build-tools/node-gyp.md). CMake.js is based on the [CMake](https://cmake.org) tool which must be installed.
8+
9+
### Pros
10+
11+
- Uses the CMake tool which is widely-adopted in the open source community.
12+
- Ideal for existing C/C++ libraries already based on CMake.
13+
14+
### Cons
15+
16+
- Not widely adopted in the Node community.
17+
18+
## Installation
19+
20+
CMake.js requires that CMake is already installed. Installers are available on the [CMake website](https://cmake.org).
21+
22+
> macOS developers may find it more convenient to install CMake using [Homebrew](https://brew.sh). With Homebrew installed, CMake can be installed using a `brew install cmake` command.
23+
24+
You can verify your CMake installation with the command:
25+
26+
```bash
27+
cmake --version
28+
```
29+
30+
As a Node native module developer, you may find it convenient to install CMake.js as a global command line tool:
31+
32+
```bash
33+
npm install cmake-js -g
34+
```
35+
36+
You can verify your CMake.js installation with the command:
37+
38+
```bash
39+
cmake-js --version
40+
```
41+
42+
## package.json
43+
44+
Your `package.json` file needs to have a couple of entries for your native module to work with CMake.js.
45+
46+
Since your native module needs to be compiled using CMake.js on installation, the `scripts` property of your `package.json` file needs an `install` entry to make this happen:
47+
48+
```json
49+
"scripts": {
50+
"install": "cmake-js compile",
51+
}
52+
```
53+
54+
It is unlikely that the users of your native module will have CMake.js installed as a global command line tool. Therefore, your project needs to declare a development dependency on CMake.js. This can be accomplished by entering this command:
55+
56+
```bash
57+
npm install cmake-js --save-dev
58+
```
59+
60+
An alternative is to manually add the development dependency to your `package.json` file:
61+
62+
```json
63+
"devDependencies": {
64+
"cmake-js": "^6.0.0"
65+
}
66+
```
67+
68+
An example of this approach is [available here](https://github.com/nodejs/node-addon-examples/blob/main/src/8-tooling/build_with_cmake/node-addon-api/package.json).
69+
70+
## CMakeLists.txt
71+
72+
Native modules built on CMake.js have a `CMakeLists.txt` that describes how the module is to be built. The file serves the same purpose as the `binding.gyp` for projects that use `node-gyp`.
73+
74+
In addition to the entries required for any CMake build, additional entries are required when building native modules.
75+
76+
### CMake.js
77+
78+
Here are the lines required for all native modules built using CMake.js:
79+
80+
```cpp
81+
project(napi-cmake-build-example)
82+
include_directories(${CMAKE_JS_INC})
83+
file(GLOB SOURCE_FILES "hello.cc")
84+
add_library(${PROJECT_NAME} SHARED ${SOURCE_FILES} ${CMAKE_JS_SRC})
85+
set_target_properties(${PROJECT_NAME} PROPERTIES PREFIX "" SUFFIX ".node")
86+
target_link_libraries(${PROJECT_NAME} ${CMAKE_JS_LIB})
87+
```
88+
89+
### NAPI_VERSION
90+
91+
When building a native module based on Node-API, it is important to declare the minimum Node-API version against which your module is designed to work. For CMake.js, this is accomplished by adding a line like this to the `CMakeLists.txt` file:
92+
93+
```cpp
94+
# define NAPI_VERSION
95+
add_definitions(-DNAPI_VERSION=3)
96+
```
97+
98+
> In the absence of other requirements, Node-API version 3 is a good choice as this is the Node-API version active when Node-API left experimental status.
99+
100+
### node-addon-api
101+
102+
Additional configuration values are required for Node-API modules based on `node-addon-api`.
103+
104+
`node-addon-api` requires C++11. These configuration lines at the top of the `CMakeLists.txt` file specify this requirement:
105+
106+
```cpp
107+
cmake_minimum_required(VERSION 3.9)
108+
cmake_policy(SET CMP0042 NEW)
109+
set (CMAKE_CXX_STANDARD 11)
110+
```
111+
112+
Modules based on `node-addon-api` include additional header files that are not part of Node itself. These lines instruct CMake.js where to find these files:
113+
114+
```cpp
115+
# Include Node-API wrappers
116+
execute_process(COMMAND node -p "require('node-addon-api').include"
117+
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
118+
OUTPUT_VARIABLE NODE_ADDON_API_DIR
119+
)
120+
string(REPLACE "\n" "" NODE_ADDON_API_DIR ${NODE_ADDON_API_DIR})
121+
string(REPLACE "\"" "" NODE_ADDON_API_DIR ${NODE_ADDON_API_DIR})
122+
target_include_directories(${PROJECT_NAME} PRIVATE ${NODE_ADDON_API_DIR})
123+
```
124+
125+
An example of this approach is [available here](https://github.com/nodejs/node-addon-examples/blob/main/src/8-tooling/build_with_cmake/node-addon-api/CMakeLists.txt).

pages/napi/build-tools/index.md

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
---
2+
authors: avivkeller
3+
---
4+
5+
# Build Tools
6+
7+
Building a native Node.js addon requires compiling C/C++ source code into a binary `.node` file that Node.js can load at runtime. This section covers the build tools available to you and the trade-offs between them.
8+
9+
## Compiling on installation vs. distributing pre-built binaries
10+
11+
There are two broad strategies for shipping a native addon:
12+
13+
**Compile on the user's machine** - When a user runs `npm install`, the build tool compiles your C/C++ source on their system. This is simple to set up but requires every user to have a working C/C++ toolchain installed.
14+
15+
**Distribute pre-built binaries** - You compile binaries for each supported platform and architecture ahead of time and upload them somewhere users can download. Users who download a matching binary skip the compilation step entirely; others fall back to compiling locally.
16+
17+
## Build tools covered in this section
18+
19+
- [node-gyp](/learn/napi/build-tools/node-gyp.md) - the default build tool bundled with npm; uses Google's GYP format and is nearly universally supported in the Node ecosystem
20+
- [CMake.js](/learn/napi/build-tools/cmake-js.md) - a CMake-based alternative, well-suited for projects that already use CMake
21+
- [node-pre-gyp](/learn/napi/build-tools/node-pre-gyp.md) - a layer on top of node-gyp for distributing pre-built binaries via Amazon S3
22+
- [prebuild](/learn/napi/build-tools/prebuild.md) - an alternative pre-build tool that publishes binaries as GitHub Releases

pages/napi/build-tools/node-gyp.md

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
---
2+
authors: gabrielschulhof, NickNaso, jschlight, mhdawson, KevinEady, avivkeller
3+
---
4+
5+
# node-gyp
6+
7+
[node-gyp](https://github.com/nodejs/node-gyp) is the standard build tool for native Node.js addons and is used by the vast majority of packages in the npm ecosystem. It is actively maintained by the Node.js team. Most of the examples on this site use node-gyp to build binaries.
8+
9+
node-gyp is based on Google's [GYP](https://gyp.gsrc.io/) build tool. GYP provides a single cross-platform configuration format for C/C++ builds. Although Google archived the upstream GYP repository, node-gyp continues to receive active development and maintenance independently.
10+
11+
> node-gyp requires **Python 3.6 or later**. Python 2 is not supported. The full list of requirements for each platform can be found in the [node-gyp installation docs](https://github.com/nodejs/node-gyp#installation).
12+
13+
node-gyp is included with npm; when npm sees `"gypfile": true` in `package.json`, it invokes node-gyp automatically during `npm install`. You can also install and use it directly:
14+
15+
```bash
16+
npm install -g node-gyp
17+
```
18+
19+
For developers who find node-gyp too constraining, [CMake.js](/learn/napi/build-tools/cmake-js.md) is a good alternative.
20+
21+
### Pros
22+
23+
- Included with npm - no separate global install required for consumers.
24+
- Nearly universally used in the Node.js ecosystem, with broad documentation and community knowledge.
25+
- Supports Windows, macOS, and Linux from a single `binding.gyp` configuration file.
26+
27+
### Cons
28+
29+
- The underlying GYP format is no longer actively developed by Google.
30+
- Some developers find GYP's configuration syntax verbose or difficult to debug.
Lines changed: 157 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,157 @@
1+
---
2+
authors: gabrielschulhof, NickNaso, jschlight, mhdawson, KevinEady, avivkeller
3+
---
4+
5+
# node-pre-gyp
6+
7+
One of the limitations of native addons is that they must be compiled for each target platform and architecture. Without pre-built binaries, every user who installs your package must have a working C/C++ toolchain on their machine.
8+
9+
[node-pre-gyp](https://github.com/mapbox/node-pre-gyp) solves this by letting you build binaries ahead of time, upload them to a remote location, and have users download the right binary at install time - falling back to compiling from source only if a matching binary is not available.
10+
11+
> Note that Node-API support was added to node-pre-gyp in version 0.8.0.
12+
13+
> [prebuild](/learn/napi/build-tools/prebuild.md) is an alternative tool that addresses the same problem.
14+
15+
This page describes the changes required to a Node-API addon to support node-pre-gyp.
16+
17+
## Amazon S3
18+
19+
By default, node-pre-gyp uploads binaries to [Amazon S3](https://aws.amazon.com/s3/).
20+
21+
> The [node-pre-gyp-github](https://github.com/bchr02/node-pre-gyp-github) module adds support for publishing to GitHub Releases instead.
22+
23+
### Amazon S3 Requirements
24+
25+
Before uploading you need:
26+
27+
1. An Amazon Web Services account.
28+
2. An IAM user or role with permission to upload to S3.
29+
3. An [S3 bucket](https://docs.aws.amazon.com/AmazonS3/latest/userguide/UsingBucket.html) to host the binaries.
30+
31+
### AWS Credentials
32+
33+
Never store credentials in your repository. node-pre-gyp supports two common approaches for providing credentials during development:
34+
35+
1. A `~/.node_pre_gyprc` file:
36+
37+
```json
38+
{
39+
"accessKeyId": "xxx",
40+
"secretAccessKey": "xxx"
41+
}
42+
```
43+
44+
2. Environment variables:
45+
46+
```bash
47+
export node_pre_gyp_accessKeyId=xxx
48+
export node_pre_gyp_secretAccessKey=xxx
49+
```
50+
51+
For CI environments, prefer IAM roles or short-lived credentials rather than long-lived access keys. See the [node-pre-gyp credentials documentation](https://github.com/mapbox/node-pre-gyp#3-configure-aws-credentials) for additional options.
52+
53+
## package.json
54+
55+
### The `dependencies` and `devDependencies` properties
56+
57+
The package is now published under the `@mapbox` scope. Use `aws-sdk` as a dev dependency for the upload step.
58+
59+
```json
60+
"dependencies": {
61+
"@mapbox/node-pre-gyp": "^1.0.0"
62+
},
63+
"devDependencies": {
64+
"aws-sdk": "^2.0.0"
65+
}
66+
```
67+
68+
### The `scripts` property
69+
70+
The `install` script should invoke node-pre-gyp with `--fallback-to-build` so that users who don't have a pre-built binary available can still compile locally:
71+
72+
```json
73+
"scripts": {
74+
"install": "node-pre-gyp install --fallback-to-build"
75+
}
76+
```
77+
78+
### The `binary` property
79+
80+
The `binary` property tells node-pre-gyp which Node-API versions your addon supports and where to find/upload binaries:
81+
82+
```json
83+
"binary": {
84+
"module_name": "your_module",
85+
"module_path": "./lib/binding/napi-v{napi_build_version}",
86+
"remote_path": "./{module_name}/v{version}/{configuration}/",
87+
"package_name": "{platform}-{arch}-napi-v{napi_build_version}.tar.gz",
88+
"host": "https://your_bucket.s3.us-west-1.amazonaws.com",
89+
"napi_versions": [3]
90+
}
91+
```
92+
93+
Set `module_name` to a valid C identifier. The `napi_versions` array lists which Node-API versions to build for; `3` is a reasonable minimum for most addons.
94+
95+
See the [node-pre-gyp docs](https://github.com/mapbox/node-pre-gyp#1-add-new-entries-to-your-packagejson) for a complete reference, including [Node-API considerations](https://github.com/mapbox/node-pre-gyp#n-api-considerations).
96+
97+
## binding.gyp
98+
99+
### New target
100+
101+
Add a post-build target to copy the compiled binary to the path specified by `module_path`:
102+
103+
```json
104+
{
105+
"target_name": "action_after_build",
106+
"type": "none",
107+
"dependencies": ["<(module_name)"],
108+
"copies": [
109+
{
110+
"files": ["<(PRODUCT_DIR)/<(module_name).node"],
111+
"destination": "<(module_path)"
112+
}
113+
]
114+
}
115+
```
116+
117+
### NAPI_VERSION
118+
119+
Include the Node-API version in the first target's `defines` so the header files configure themselves correctly:
120+
121+
```json
122+
"defines": [
123+
"NAPI_VERSION=<(napi_build_version)"
124+
]
125+
```
126+
127+
## JavaScript updates
128+
129+
JavaScript code that loads the native binary must dynamically resolve the path to the correct `.node` file:
130+
131+
```cjs
132+
const binary = require('@mapbox/node-pre-gyp');
133+
const path = require('path');
134+
const bindingPath = binary.find(
135+
path.resolve(path.join(__dirname, './package.json'))
136+
);
137+
const binding = require(bindingPath);
138+
```
139+
140+
## Build
141+
142+
Once everything is in place, build from source:
143+
144+
```bash
145+
npm install --build-from-source
146+
```
147+
148+
## Package and publish
149+
150+
```bash
151+
./node_modules/.bin/node-pre-gyp package
152+
./node_modules/.bin/node-pre-gyp publish
153+
```
154+
155+
## CI and automated builds
156+
157+
Use [GitHub Actions](https://docs.github.com/en/actions) to build, test, and publish binaries for multiple platforms and architectures. A typical workflow matrix covers `ubuntu-latest`, `macos-latest`, and `windows-latest`, plus any architecture variants you need (e.g. `x64`, `arm64`). See the node-pre-gyp repository for [example workflow configurations](https://github.com/mapbox/node-pre-gyp).

0 commit comments

Comments
 (0)