webpack-contrib / node-loader

node loader for native modules
MIT License
119 stars 43 forks source link

webpack build does not copy .node modules into the build folder and links via absolute path #12

Closed appdev44 closed 4 years ago

appdev44 commented 7 years ago

I have a webpack(3.5.6) project using node-loader(0.6.0), which I use to build a package for a nw.js application. I am trying to include a custom node package (Created with nw-gyp) in my build. But for some reason all files apart from the ".node" files are copied into my build folder, and in the generated java script file, it has an absolute path reference eg function(module) {try {global.process.dlopen(module, "c:\src\locale_modules\helloworld.node")

thanks, alex

atrauzzi commented 7 years ago

Curious about this as well. Any advice on how to get the built output a copy of the binary?

smt116 commented 7 years ago

@appdev44 @atrauzzi I'd the same issue. First, you need to copy the file into the output directory and then build a relative path in the runtime instead of hardcoding an absolute one during a build process. I've extracted this to the npm package since non of the existing solutions had that feature. You can use that code: https://github.com/smt116/node-native-ext-loader, create your own implementation using it as the starting point or create a pull request to some existing solutions. You might be also interested in the https://github.com/ushu/node-addon-loader as it was used as the inspiration for node-native-ext-loader.

aurelhann commented 6 years ago

I have the same pb when i'm building this native addon in an other directory. It is the same with native-ext-loader and node-addon-loader

PerfectionVR commented 6 years ago

My situation:

Webpack builds to

./dist

And we create an asar package with webpack. Then in our application we have

./electron.exe ./application/package.asar/dist

A reference to what was once ./node_module/somemodule/module.node can not be found in the packaged app because ./dist will not exist and it should have been ./application/package.asar/dist/

Any idea how to fix this?

Cellule commented 6 years ago

I had a similar problem, I have a build machine that build my addon then webpack packs everything. However, since the .node file wasn't actually bundled I couldn't run the packed script anywhere else.

I ended up writing my own loader, I don't know if it can be made generic, but it does solves my problem at least and I hope it can help others.

const fs = require("fs");
const path = require("path");

module.exports = function nodeLoader() {
  const filename = path.basename(this.resourcePath);
  const src = fs.readFileSync(this.resourcePath, {encoding: "binary"});
  return `
const nodeFilename = ${JSON.stringify(filename)};
const src = ${JSON.stringify(src)};
require("fs").writeFileSync(nodeFilename, src, "binary");
try {
  global.process.dlopen(
    module,
    nodeFilename
  );
} catch(e) {
  throw new Error('node-loader: Cannot open ' + nodeFilename + ': ' + e);
}
`;
};

It will bundle the .node file as a string in the packed script and then can be used to load it. Since global.process.dlopen expects a filename, I had to write the data to a file in cwd before loading it

jablko commented 5 years ago

The following solution worked for me:

const CopyPlugin = require('copy-webpack-plugin')

module.exports = {
  plugins: [
    new CopyPlugin([{
      from: 'node_modules/scrypt/build/Release/scrypt.node',
      to: 'build/Release'
    }])
  ],
  externals: './build/Release/scrypt'
}
alexander-akait commented 5 years ago

Somebody can create minimum reproducible test repo?

joshuan commented 5 years ago

This demo: https://github.com/joshuan/test-node-loader node-loader generate absolute path to keytar.node (as example) native module.

imndx commented 5 years ago

I had a similar problem, I have a build machine that build my addon then webpack packs everything. However, since the .node file wasn't actually bundled I couldn't run the packed script anywhere else.

I ended up writing my own loader, I don't know if it can be made generic, but it does solves my problem at least and I hope it can help others.

const fs = require("fs");
const path = require("path");

module.exports = function nodeLoader() {
  const filename = path.basename(this.resourcePath);
  const src = fs.readFileSync(this.resourcePath, {encoding: "binary"});
  return `
const nodeFilename = ${JSON.stringify(filename)};
const src = ${JSON.stringify(src)};
require("fs").writeFileSync(nodeFilename, src, "binary");
try {
  global.process.dlopen(
    module,
    nodeFilename
  );
} catch(e) {
  throw new Error('node-loader: Cannot open ' + nodeFilename + ': ' + e);
}
`;
};

It will bundle the .node file as a string in the packed script and then can be used to load it. Since global.process.dlopen expects a filename, I had to write the data to a file in cwd before loading it

thanks, this solution partially works for me. On windows 10, if I install for the current user, it works. If I install for all users, it not works.

conorgriffin commented 4 years ago

Is this still an open bug? I'm having a similar issue with keytar where absolute paths are packaged into the application and then the app fails when distributed to other machines

a7ul commented 4 years ago

I used https://github.com/toyobayashi/native-addon-loader and it solved all my issues.

Livven commented 4 years ago

Just for the record, I've been trying to get nodegit to work with Electron and create-react-app and native-addon-loader was the only one that worked, having also tried the options from this comment.

gabrielvincent commented 4 years ago

@Livven I'm having a problem with this library. Webpack bundles my application into the following structure:

- .webpack
    - service
        - src
            handler.js
        addon.node

But in handler.js I have module.exports = require("./addon.node");. But this path is not valid. If I manually move addon.node to src, it works.

Do you know how can I make handler.js reference the correct path?

LYLC commented 4 years ago

If anyone encounters this "node-loader" issue while working with Electron, target: 'electron-renderer' and the following syntax can resolve it.

const addon = require('electron').remote.require('./addon/dist/addon.node');

The link below contains more detail. https://stackoverflow.com/questions/50547649/using-node-js-addons-in-electrons-renderer-with-webpack

If an error message, "Require is not defined", is found, nodeIntegration: true needs to put in the main js file. This link has more detail. https://stackoverflow.com/questions/55233839/require-is-not-defined-when-adding-electron-renderer-to-webpack

alexander-akait commented 4 years ago

Fixed in the next branch, ETA is today, anyway you faced with this problem again, please open a new issue with minimum reproducible test repo and we will fix it :+1: