nodejs / node-addon-api

Module for using Node-API from C++

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

With the `node-addon` I don't get any errors but the React Page doesn't show up

raphael10-collab opened this issue · comments

Following the indications found here: https://medium.com/jspoint/a-simple-guide-to-load-c-c-code-into-node-js-javascript-applications-3fcccf54fd32 and here https://github.com/nodejs/node-addon-examples/tree/main/1_hello_world/node-addon-api
I'm trying to understand how to effectively use node-addon-api for later include within electron C++ module.

In a simple react-typescript-webpack app I've put this:

package.json :

{
  "name": "greet",
  "version": "0.0.1",
  "license": "UNLICENSED",
  "scripts": {
    "start": "webpack serve --open",
    "build": "webpack --mode production"
  },
  "dependencies": {
    "node-addon-api": "^6.0.0",
    "node-gyp": "^9.3.1",
    "react": "^18.2.0",
    "react-dom": "^18.2.0"
  },
  "devDependencies": {
    "@babel/core": "^7.20.12",
    "@babel/plugin-transform-runtime": "^7.19.6",
    "@babel/preset-env": "^7.20.2",
    "@babel/preset-react": "^7.18.6",
    "@babel/preset-typescript": "^7.18.6",
    "@babel/runtime": "^7.20.13",
    "@types/fork-ts-checker-webpack-plugin": "^0.4.5",
    "@types/react": "^18.0.28",
    "@types/react-dom": "^18.0.10",
    "@types/webpack": "^5.28.0",
    "@types/webpack-dev-server": "^4.7.2",
    "@typescript-eslint/eslint-plugin": "^5.51.0",
    "@typescript-eslint/parser": "^5.51.0",
    "babel-loader": "^9.1.2",
    "eslint": "^8.34.0",
    "eslint-plugin-react": "^7.32.2",
    "eslint-plugin-react-hooks": "^4.6.0",
    "fork-ts-checker-webpack-plugin": "^7.3.0",
    "node-loader": "^2.0.0",
    "ts-node": "^10.9.1",
    "typescript": "^4.9.5",
    "webpack": "^5.75.0",
    "webpack-cli": "^5.0.1",
    "webpack-dev-server": "^4.11.1"
  },
  "resolutions": {
    "@types/webpack": "^4.4.11"
  }
}

webpack.config.js :

const webpack = require("webpack")
const webpackDevServer = require("webpack-dev-server")
const path = require("path")
const Configuration = require("webpack")
const ForkTsCheckerWebpackPlugin = require("fork-ts-checker-webpack-plugin")

// https://webpack.js.org/loaders/node-loader/


const config: typeof Configuration = {
  entry: "./src/index.tsx",
  target: "node",
  node: {
    __dirname: false,
  },
  module: {
    rules: [
      {
        test: /\.node$/,
        use: 'node-loader',
      },
      {
        test: /\.(ts|js)x?$/,
        exclude: /node_modules/,
        use: {
          loader: "babel-loader",
          options: {
            presets: [
              "@babel/preset-env",
              "@babel/preset-react",
              "@babel/preset-typescript",
            ],
          },
        },
      },
    ],
  },
  resolve: {
    extensions: [".tsx", ".ts", ".js"],
  },
  mode: 'development',
  output: {
    path: path.resolve(__dirname, "build"),
    filename: "bundle.js",
  },
  devServer: {
    static: path.join(__dirname, "build"),
    compress: true,
    port: 4000,
  },
  plugins: [
    new ForkTsCheckerWebpackPlugin({
      async: false,
    }),
  ],
};

export default config;

tsconfig.json:

    {
      "compilerOptions": {
        "lib": ["dom", "dom.iterable", "esnext"],
        "allowJs": true,
        "allowSyntheticDefaultImports": true,
        "skipLibCheck": true,
        "esModuleInterop": true,
        "strict": true,
        "forceConsistentCasingInFileNames": true,
        "moduleResolution": "node",
        "resolveJsonModule": true,
        "isolatedModules": true,
        "noEmit": true,
        "jsx": "react"
      },
      "include": ["src"]
    }

binding.gyp :

{
  "targets": [
    {
      "target_name": "greet",
      "cflags!": [ "-fno-exceptions" ],
      "cflags_cc!": [ "-fno-exceptions" ],
      "sources": [
        "./src/greeting.cpp",
        "./src/index.cpp"
      ],
      "include_dirs": [
        "<!@(node -p \"require('node-addon-api').include\")"
      ],
      'defines': [ 'NAPI_DISABLE_CPP_EXCEPTIONS' ],
    }
  ],

  'cflags!': [ '-fno-exceptions' ],
  'cflags_cc!': [ '-fno-exceptions' ],
  'conditions': [
    ["OS=='win'", {
      "defines": [
        "_HAS_EXCEPTIONS=1"
      ],
      "msvs_settings": {
        "VCCLCompilerTool": {
          "ExceptionHandling": 1
        },
      },
    }],
    ["OS=='mac'", {
      'xcode_settings': {
        'GCC_ENABLE_CPP_EXCEPTIONS': 'YES',
        'CLANG_CXX_LIBRARY': 'libc++',
        'MACOSX_DEPLOYMENT_TARGET': '10.7',
      },
    }],
  ]

}

In ./src/ folder:

greeting.h :

#include <string>

std::string helloUser( std::string name );

greeting.cpp :

#include
#include
#include "greeting.h"

std::string helloUser( std::string name) {
    return "Hello " + name + " !";
}

int main() {

    std::string HelloUserString = helloUser("Bob");

    std::cout << HelloUserString << std::endl;

    return 0;
}

Compiling and testing the .cpp file:

raphy@raohy:~/native-greet-module/src$ g++ -std=c++20 greeting.cpp -o greeting
raphy@raohy:~/native-greet-module/src$ ./greeting 
Hello Bob !

index.cpp :

#include <napi.h>
#include <string>

// https://github.com/nodejs/node-addon-examples/blob/main/1_hello_world/node-addon-api/hello.cc

// native C++ function that is assigned to "greetHello" property on "exports" object

Napi::String greetHello(const Napi::CallbackInfo& info) {
    Napi::Env env = info.Env();

    // call "helloUser" function from "greeting.cpp" file
    // WARNING: We are passing hardcoded "MIKE" value for now
    std::string result = helloUser( "MIKE" );

    // return new "Nap::String" value
    return Napi::String::New(env, result);
}

// callback method when module is registered with Node.js
Napi::Object Init(Napi::Env env, Napi::Object exports) {

    // set a key on "exports" object
    exports.Set(
        Napi::String::New(env, "greetHello"), // property name => "greetHello"
        Napi::Function::New(env, greetHello) // property value => "greetHello" function
    );

    // return "exports" object (always)
    return exports;
}

// register "greet" module which calls "Init" method
NODE_API_MODULE(greet, Init)

I executed node-gyp configure :

raphy@raohy:~/native-greet-module$ node-gyp configure
gyp info it worked if it ends with ok
gyp info using node-gyp@9.3.0
gyp info using node@18.12.1 | linux | x64
gyp info find Python using Python version 3.10.6 found at "/usr/bin/python3"
gyp info spawn /usr/bin/python3
gyp info spawn args [
gyp info spawn args   '/home/raphy/.nvm/versions/node/v18.12.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/raphy/native-greet-module/build/config.gypi',
gyp info spawn args   '-I',
gyp info spawn args   '/home/raphy/.nvm/versions/node/v18.12.1/lib/node_modules/node-gyp/addon.gypi',
gyp info spawn args   '-I',
gyp info spawn args   '/home/raphy/.cache/node-gyp/18.12.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/raphy/.cache/node-gyp/18.12.1',
gyp info spawn args   '-Dnode_gyp_dir=/home/raphy/.nvm/versions/node/v18.12.1/lib/node_modules/node-gyp',
gyp info spawn args   '-Dnode_lib_file=/home/raphy/.cache/node-gyp/18.12.1/<(target_arch)/node.lib',
gyp info spawn args   '-Dmodule_root_dir=/home/raphy/native-greet-module',
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 ok 
raphy@raohy:~/native-greet-module$ 

And then node-gyp build :

raphy@raohy:~/native-greet-module$ node-gyp build
gyp info it worked if it ends with ok
gyp info using node-gyp@9.3.0
gyp info using node@18.12.1 | linux | x64
gyp info spawn make
gyp info spawn args [ 'BUILDTYPE=Release', '-C', 'build' ]
make: Entering directory '/home/raphy/native-greet-module/build'
  CXX(target) Release/obj.target/greet/src/greeting.o
  CXX(target) Release/obj.target/greet/src/index.o
  SOLINK_MODULE(target) Release/obj.target/greet.node
  COPY Release/greet.node
make: Leaving directory '/home/raphy/native-greet-module/build'
gyp info ok 
raphy@raohy:~/native-greet-module$ 

In ./src/ folder` :

index.tsx :

import React from "react";
import ReactDOM from "react-dom";

const greetModule = require('../build/Release/greet.node')

const App = () => (
  <h1>My React and TypeScript App!</h1>
);

ReactDOM.render(
  <App />,
  document.getElementById("root")
);

Starting the react app I get no errors:

raphy@raohy:~/native-greet-module$ yarn start
yarn run v1.22.19
$ webpack serve --open
<i> [webpack-dev-server] Project is running at:
<i> [webpack-dev-server] Loopback: http://localhost:4000/
<i> [webpack-dev-server] On Your Network (IPv4): http://192.168.1.7:4000/
<i> [webpack-dev-server] On Your Network (IPv6): http://[fe80::f2e3:be71:cd02:bb1d]:4000/
<i> [webpack-dev-server] Content not from webpack is served from '/home/raphy/native-greet-module/build' directory
<i> [webpack-dev-middleware] wait until bundle finished: /
asset bundle.js 1.16 MiB [emitted] (name: main)
asset 5951ea98b41e9eadb7f0d975f38f4ae6.node 60.8 KiB [emitted] (auxiliary name: main)
runtime modules 23.7 KiB 11 modules
built modules 1.09 MiB [built]
  modules by path ./node_modules/ 1.09 MiB
    modules by path ./node_modules/webpack/hot/*.js 4.59 KiB 4 modules
    modules by path ./node_modules/react/ 85.7 KiB 2 modules
    modules by path ./node_modules/react-dom/ 1000 KiB 2 modules
    modules by path ./node_modules/scheduler/ 17.3 KiB
      ./node_modules/scheduler/index.js 198 bytes [built] [code generated]
      ./node_modules/scheduler/cjs/scheduler.development.js 17.1 KiB [built] [code generated]
  ./src/index.tsx 331 bytes [built] [code generated]
  ./build/Release/greet.node 199 bytes [built] [code generated]
  external "events" 42 bytes [built] [code generated]
  external "path" 42 bytes [optional] [built] [code generated]
webpack 5.75.0 compiled successfully in 1766 ms

But I get this output, instead of the expected header message My React and TypeScript App! :

image

You can find the code in this Repo : https://github.com/raphael10-collab/native-greet-module

What's wrong with my settings? And how to make this simple React-Typescript-Webpack with node-addon showing the react page ?

This issue is stale because it has been open many days with no activity. It will be closed soon unless the stale label is removed or a comment is made.

Hi @raphael10-collab ,

From the looks of it though, you don't have an index.html file to be served to use your transpiled index.js. However, this is an issue with webpack and/or react, not node-addon-api. I would reach out there if you are having issues.