Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Webpack failing to package balena-sdk in React/Next.js #1412

Open
Nevter opened this issue Apr 18, 2024 · 11 comments
Open

Webpack failing to package balena-sdk in React/Next.js #1412

Nevter opened this issue Apr 18, 2024 · 11 comments

Comments

@Nevter
Copy link

Nevter commented Apr 18, 2024

Expected Behavior

npm install balena-sdk
use balena getSdk()

Actual Behavior

On compilation, webpack cannot package the balena sdk. See following error:

./node_modules/balena-sdk/LICENSE
Module parse failed: Unexpected token (2:37)
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
| 
>                               Apache License
|                         Version 2.0, January 2004
|                      http://www.apache.org/licenses/

It seems like webpack is failing to parse the LICENSE file. I'm unsure, but it might be beacuse of the tabs in the LICENSE file. Inspect other packages' LICENSE files, they don't have any tabs/ formatting. The error is with the " Apache License" line

One solution would be to override the webpack loader to deal with LICENSE files specifically, but this not an option in React.
Alterantively, the pre-packaged sdk can be used (balena-browser.min.js) but this is not an elegant solution, and means the sdk can only be used on the client side.

Steps to Reproduce the Problem

  1. npx create-next-app@latest
  2. npm i balena-sdk
  3. Create balena instance: const balena = getSdk({apiUrl: ...}_
  4. npm run build/ npm run dev

Specifications

References

@thgreasi
Copy link
Member

thgreasi commented Apr 18, 2024

Hi,
Can you provide your import statement as well please?
Our balena dashboard is also using webpack 5 and we are not facing any such issue.
Moreover since the package.json already defines the entrypoints, none of which points to the LICENSE file, I don't really see why webpack would try to import it.

balena-sdk/package.json

Lines 5 to 12 in e62c741

"main": "index.js",
"types": "index.d.ts",
"browser": {
"index.js": "./es2015/index.js",
"es2015/util/settings-client.js": "./es2015/util/settings-client.browser.js",
"es2018/util/settings-client.js": "./es2018/util/settings-client.browser.js",
"handlebars": "handlebars/dist/cjs/handlebars.js"
},

Can you try adding the following to your webpack.config.js and check whether helps?

{
	resolve: {
		alias: {
			'balena-sdk': path.resolve('./node_modules/pinejs-client-core/es2015'),
		}
	}
}

@Nevter
Copy link
Author

Nevter commented Apr 18, 2024

Here is a fresh project with the issue: https://github.com/Nevter/BalenaSdkIssue/tree/main
And the page.tsx file where I am trying to import and use the sdk: https://github.com/Nevter/BalenaSdkIssue/blob/main/src/app/page.tsx

Will try make the webpack adjustments now.

@Nevter
Copy link
Author

Nevter commented Apr 18, 2024

Modifying the webpack config (through next.config.mjs) seems to resolve the webpack issue, but the getSdk package export is now broken (although, this might be a typescript issue?)

src\app\page.tsx (11:25) @ Home
 ⨯ TypeError: (0 , balena_sdk__WEBPACK_IMPORTED_MODULE_1__.getSdk) is not a function
    at Home (./src/app/page.tsx:16:70)
    at stringify (<anonymous>)
digest: "1104208706"
   9 |   }
  10 |
> 11 |   const balena = getSdk({ apiUrl: "https://api.balena-cloud.com" });
     |                         ^
  12 |   await balena.auth.loginWithToken(balenaToken);
  13 |
  14 |   const device = await balena.models.device.get("17fabed");
 GET / 500 in 77ms

@Nevter
Copy link
Author

Nevter commented Apr 18, 2024

Changing the files to .jsx files doesn't resolve this issue. Still seems to be webpack related:
⨯ TypeError: (0 , balena_sdk__WEBPACK_IMPORTED_MODULE_1__.getSdk) is not a function

@thgreasi
Copy link
Member

Can you provide us your import/require statement please?
You might need to do:

import * as BalenaSdk from 'balena-sdk';

const sdkBase = BalenaSdk.getSdk({
	// ...
});

and/or add "esModuleInterop": true, to your tsconfig.json .

@Nevter
Copy link
Author

Nevter commented Apr 18, 2024

I was importing with import { getSdk } from 'balena-sdk'; but have tried import * as BalenaSdk from 'balena-sdk'; and get the same issue,
which is now:

TypeError: balena_sdk__WEBPACK_IMPORTED_MODULE_1__.getSdk is not a function
    at Home (./src/app/page.tsx:16:60)
    at stringify (<anonymous>)
digest: "1737674563"
   9 |   }
  10 |
> 11 |   const balena = BalenaSdk.getSdk({ apiUrl: "https://api.balena-cloud.com" });
     |                  ^
  12 |   await balena.auth.loginWithToken(balenaToken);

"esModuleInterop": true, has been set the whole time, as well.

@Nevter
Copy link
Author

Nevter commented Apr 18, 2024

So, the issue isn't related to the LICENSE file itself, because if I remove that from the downloaded package in node_modules it then fails on another file in the package.

I have also verified this isn't working on another system:
node version: 20.11.0
npm version: 10.2.4
OS: Windows 10

Do you get the same issue if you clone the repo I provided?

@Nevter
Copy link
Author

Nevter commented Apr 18, 2024

I've also rolled back to a previous version of Next.js (v13.5.6) to see if the newest version of Next was adding some conflicting configs to webpack, but that version also fails with the same error.

@thgreasi
Copy link
Member

Oh @Nevter it seems that I gave you the wrong alias 😞
I should have said this v, which should fix the "getSdk" is not a function error:

{
	resolve: {
		alias: {
			'balena-sdk': path.resolve('./node_modules/balena-sdk/es2015')
		}
	}
}

Give it a try and let us know.
The issue is that on our index.js there is a require() with string concatenation, and I think that makes webpack on next.js try to bundle all files in that folder.
If you still get the LICENSE file issue after that, then you might also need to add the following alias as well:

			'pinejs-client-core': path.resolve('./node_modules/pinejs-client-core/es2015'),

Let me note again, that on our plain webpack project we do not face such issues, so I'm wondering whether this is b/c of the next.js defaults 🤔

An alternative to the aliases might be to explicitly limit webpack resolved files with:

{
	resolve: {
		// Extensions to search for when requiring files.
		extensions: ['.js', '.ts', '.tsx'], // and so on
}

@Nevter
Copy link
Author

Nevter commented Apr 19, 2024

Hey @thgreasi

That solves it! Overriding the webpack alias for both balena-sdk and pinejs-client-core solves the problem.
If it is the string concat in a require issue, then it looks like you have that in both packages.

For completeness, this is now my next.config.mjs file:

import path from 'path';

/** @type {import('next').NextConfig} */
const nextConfig = {
  webpack: (config, options) => {
    config.resolve.alias['balena-sdk'] = path.resolve('./node_modules/balena-sdk/es2015');
    config.resolve.alias['pinejs-client-core'] = path.resolve('./node_modules/pinejs-client-core/es2015');
    return config
  },
};

export default nextConfig;

I don't have time to try it now, but it could also be React issue, over next.js configs? But it seems likely that one of those libs has some webpack configs that are causing the issue.


This solves the issue, but it might be a good idea to either add this to the README or try hunt down the root cause so that others don't fall into the same trap. Thanks again for your help!

@Nevter
Copy link
Author

Nevter commented Apr 19, 2024

That said, I just noticed that I get server-side error printed to console this during runtime:

require.extensions is not supported by webpack. Use a loader instead.

Import trace for requested module:
./node_modules/handlebars/lib/index.js
./node_modules/balena-sdk/es2015/models/device-type.js
./node_modules/balena-sdk/es2015/models/index.js
./node_modules/balena-sdk/es2015/index.js
./src/app/page.tsx

./node_modules/handlebars/lib/index.js

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants