Skip to content

ESM with Webpack not running #88

@nzedler

Description

@nzedler

Hi together,

we're having trouble getting ziti-sdk-nodejs working without modifying the ziti-sdk-nodejs library code under Nextjs (React). We built and call the following test function using the ESM-client-side example code server-side:

'use server';

import ziti from '@openziti/ziti-sdk-nodejs';

export async function TestZiti() {
    // Somehow provide path to identity file, e.g. via env var
    const zitiIdentityFile = process.env.ZITI_IDENTITY_FILE ?? './test_identity.json';
    // Authenticate ourselves onto the Ziti network
    await ziti.init(zitiIdentityFile).catch((err) => { /* probably exit */ });
    
    const on_resp_data = (obj) => {
        console.log(`response is: ${obj.body.toString('utf8')}`);
    };
    
    // Perform an HTTP GET request to a dark OpenZiti web service
    ziti.httpRequest(
        'myDarkWebService',            // OpenZiti Service name or HTTP origin part of the URL
        undefined,                     // schemeHostPort parm is mutually-exclusive with serviceName parm
        'GET',
        '/',                           // path part of the URL including query params
        ['Accept: application/json'], // headers
        undefined,                     // optional on_req cb 
        undefined,                     // optional on_req_data cb
        on_resp_data                   // optional on_resp_data cb
    );
}

In order to get it working, we needed to add the dependency node-loader and the following Webpack config in the next.config.js. What we did is copying the ziti_sdk_nodejs.node-file to the build directory to make it available (since Nextjs performs build optimization). Additionally we hat to define the node-loader, that is able to load the binary:

webpack: (config, { isServer, nextRuntime }) => {
    if (isServer && nextRuntime === "nodejs") {
      const __filename = fileURLToPath(import.meta.url);
      const __dirname = path.dirname(__filename);
      config.plugins.push(
        new CopyPlugin({
          patterns: [
            {
              from: path.resolve(__dirname, 'node_modules/@openziti/ziti-sdk-nodejs/build/Release/ziti_sdk_nodejs.node'),
              to: path.resolve(__dirname, '.next/server/vendor-chunks//_next/ziti_sdk_nodejs.node'),
            },
          ],
        })
      );
      config.externals = [
        ...config.externals,
        "_http_server"
      ];
      config.module.rules.push({
        test: /\.node$/,
        loader: "node-loader",
        options: {
          name: "ziti_sdk_nodejs.node",
        },
      });
    }
    return config;
  }

Running this example, we get the following error message:

⨯ ./node_modules/.pnpm/@mapbox+node-pre-gyp@1.0.11/node_modules/@mapbox/node-pre-gyp/lib/util/nw-pre-gyp/index.html
Module parse failed: Unexpected token (1:0)
You may need an appropriate loader to handle this file type, currently no loaders are configured to process this file. See https://webpack.js.org/concepts#loaders
> <!doctype html>
| <html>
| <head>

Import trace for requested module:
./node_modules/.pnpm/@mapbox+node-pre-gyp@1.0.11/node_modules/@mapbox/node-pre-gyp/lib/util/nw-pre-gyp/index.html
./node_modules/.pnpm/@mapbox+node-pre-gyp@1.0.11/node_modules/@mapbox/node-pre-gyp/lib/ sync ^\.\/.*$
./node_modules/.pnpm/@mapbox+node-pre-gyp@1.0.11/node_modules/@mapbox/node-pre-gyp/lib/node-pre-gyp.js
./node_modules/.pnpm/@openziti+ziti-sdk-nodejs@0.17.0/node_modules/@openziti/ziti-sdk-nodejs/lib/ziti.js
./src/app/test.tsx
./src/app/page.tsx

This is because in @openziti/ziti-sdk-nodejs/lib/ziti.js line 32 to 44, always the else-statement is used. typeof require.context == 'function' is never true, because require is undefined:

if (typeof require.context == 'function') {

  importAll( require.context("../build/", true, /\.node$/) );

} else {

    const binary = require('@mapbox/node-pre-gyp');
    const path = require('path')
    const binding_path = binary.find(path.resolve(path.join(__dirname,'../package.json')), {debug: false});

    binding = require(binding_path);
    
}

However, if we modify the if-statement to always true, require.context("../build/", true, /\.node$/) works and loads the binary despite typeof require.context == 'function' being false. This works flawlessly. 🎉

// if (typeof require.context == 'function') {
if (true) {

  importAll( require.context("../build/", true, /\.node$/) );

} else {

    const binary = require('@mapbox/node-pre-gyp');
    const path = require('path')
    const binding_path = binary.find(path.resolve(path.join(__dirname,'../package.json')), {debug: false});

    binding = require(binding_path);
    
}

We don't want to modify the package source in production. Are there any possibilities to get it running without modifying the package source?

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions