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

Building client with rollup and typescript results in incorrect call to qrcode module #170

Closed
fredcy opened this issue Feb 9, 2021 · 15 comments
Labels
bug Something isn't working

Comments

@fredcy
Copy link

fredcy commented Feb 9, 2021

Describe the bug (current behavior)
When I build a BeaconSDK client using the Rollup bundler and Typescript, I get an warning during compilation and a blocking error when I run the client application.

To Reproduce
Steps to reproduce the behavior:

  1. Clone the repo at https://gitlab.com/fredcy/beacon-issue-1.git

  2. Build the application:

npm install
npm run build
  1. Serve the application
npm run serve
  1. Visit http://localhost:5000 and open the console.

Expected (correct) behavior
I expect the app to compile cleanly.

I expect the app to execute the Beacon permissionRequest flow, including the wallet chooser and permission-request in the wallet.

Actual behavior

The output during compilation reports a problem:

(!) Cannot call a namespace ('qrcode')
node_modules/@airgap/beacon-sdk/dist/esm/utils/qr.js: (13:15)
11:     const typeNumber = 0;
12:     const errorCorrectionLevel = 'L';
13:     const qr = qrcode(typeNumber, errorCorrectionLevel);
                   ^
14:     if (payload.length > 500) {
15:         logger.warn('getQrData', 'The size of the payload in the QR code is quite long and some devices might not be able to scan it anymore. To reduce the QR size, try using a shorter "name", "appUrl" and "iconUrl"');

And when I run the app in the browser, it hangs at the client.requestPermission() call. No wallet chooser appears, possibly because the QR code can't be created.

Environment

  • Device: MacBook Pro
  • OS: MacOS 10.15.7
  • Browser: latest Firefox and Chrome

Additional context
The rollup.config.js has a section commented out that if applied patches the Beacon code so that it works.

@fredcy fredcy added the bug Something isn't working label Feb 9, 2021
@AndreasGassmann
Copy link
Member

This is probably related to #124 and #138

I'll look into it now

@fredcy
Copy link
Author

fredcy commented Feb 9, 2021

I think it might indeed be related. Some older modules seem to export default in a way that newer code doesn't import properly unless it accesses via old_module.default rather than just old_module. I've seen this with libsodium-wrappers and now with qrcode-generator. Some packaging flows such as what beacon-vue-example uses do some kind of transformation that makes this work. Others that I have tried using Parcel.js and now Rollup.js do not, at least as far as I have worked out. Disclaimer: I am new to modern JS modules and packaging and may be missing something obvious here to work around the problem.

The patch in my rollup.config.js modifies

const qr = qrcode(typeNumber, errorCorrectionLevel)
to call qrcode.default() rather than just qrcode() per what I found at kazuhikoarase/qrcode-generator#62

@AndreasGassmann
Copy link
Member

I just released 2.2.2-beta.0 which has some changes in the build script: #171

Can you try it out and see if it works?

@AndreasGassmann
Copy link
Member

Sadly it did not work. I'll give it another try.

@souljorje
Copy link
Contributor

@fredcy could you resolve it somehow?

@AndreasGassmann any updates?

@fredcy
Copy link
Author

fredcy commented May 16, 2022

@souljorje I don't think I ever got it to work with Rollup, other than with the patch that I described. Even today when I build with Vite I see a message about "Cannot call a namespace ('qrcode')" in the build output -- but the app runs OK.

@fredcy
Copy link
Author

fredcy commented May 16, 2022

Looking at my old rollup.config.js, I would do this in the plugins section:

	// Monkey-patch Beacon code. Without this I get a rollup
	// error about "Cannot call a namespace ('qrcode')", and the call to
	// requestPermissions() hangs at app runtime.
	replace({
	    "qr = qrcode(": "qr = qrcode.default(",
	    delimiters: ["", ""],
	    include: "node_modules/@airgap/beacon-sdk/**",
	}),

@souljorje
Copy link
Contributor

souljorje commented May 16, 2022

@fredcy yep, app runs fine but without opportunity to pair wallet via qr-code.

Eventually I did something kinda you suggested, valid for beacon-sdk@3.

// vite.config.js

import replace from 'rollup-plugin-re';

export default export default (ctx) => {
    const isBuild = ctx.command === 'build';
    return {
		plugins: [
            {
                ...replace({
                    include: ['node_modules/@airgap/**'],
                    replaces: {
                        /**
                         * qr doesn't work on dev, but at least the whole wallet works
                         */
                        ...isBuild
                            ? {
                                "import * as qrcode from 'qrcode-generator';": "import qrcode from 'qrcode-generator';",
                            }
                            : {
                                'var libsodium_wrappers_1 = require("libsodium-wrappers")': 'var libsodium_wrappers_1 = require("libsodium-wrappers").default',
                            },
                    },
                }),
                enforce: 'pre',
            },
    	],
	}
};

        

@PureSpider
Copy link

@souljorje sadly, this does not work for me using version 3.1.4 of @airgap/beacon-dapp, and the QR code is shown in dev, but not prod - which is the same situation as when not using the workaround.

Do you know if there is anything I can do to remedy this?

This is my current vite.config.ts:

import { defineConfig } from "vite";
import path from "path";
import vue from "@vitejs/plugin-vue";
import replace from "rollup-plugin-re";

// https://vitejs.dev/config/
export default ({ command }) => {
    const isBuild = command === "build";

    return defineConfig({
        base: "./",
        plugins: [
            vue(),
            {
                ...replace({
                    include: ["node_modules/@airgap/**"],
                    replaces: {
                        "import * as qrcode from 'qrcode-generator';": "import qrcode from 'qrcode-generator';",
                    },
                }),
                apply: "build",
                enforce: "pre",
            },
        ],
        build: {
            target: "esnext",
            commonjsOptions: {
                transformMixedEsModules: true,
            },
        },
        resolve: {
            alias: {
                // dedupe @airgap/beacon-dapp
                // I almost have no idea why it needs `cjs` on dev and `esm` on build, but this is how it works 🤷‍♂️
                "@airgap/beacon-dapp": path.resolve(path.resolve(), `./node_modules/@airgap/beacon-dapp/dist/${isBuild ? "esm" : "cjs"}/index.js`),
                // polyfills
                "readable-stream": "vite-compatible-readable-stream",
                stream: "vite-compatible-readable-stream",
            },
        },
    });
};

@souljorje
Copy link
Contributor

souljorje commented Sep 19, 2022

@PureSpider currently this works for me:

            {
                ...replace({
                    include: ['node_modules/@airgap/**'],
                    replaces: {
                        /**
                         * damn circus with this beacon-sdk...
                         * qr doesn't work on dev, but at least the whole wallet works
                         */
                        ...isBuild
                            ? {
                                "import * as qrcode from 'qrcode-generator';": "import qrcode from 'qrcode-generator';",
                            }
                            : {
                                'var libsodium_wrappers_1 = require("libsodium-wrappers")': 'var libsodium_wrappers_1 = require("libsodium-wrappers").default',
                            },
                    },
                }),
                enforce: 'pre',
            },

updated original comment

@852Kerfunkle
Copy link

Yup, also an issue here.

Above mentioned workarounds seem to work, in production at least.

@852Kerfunkle
Copy link

@AndreasGassmann what's the argument against using allowSyntheticDefaultImports and importing the dep as:

import qrcode from 'qrcode-generator'; ?

Let me make a PR. Builds and tests run.

@souljorje
Copy link
Contributor

@852Kerfunkle I already made it long time ago: #397

@852Kerfunkle
Copy link

Ah, I see. Wasn't mentioned here.

What is the argument against allowSyntheticDefaultImports then?

@AndreasGassmann
Copy link
Member

The UI package has changed a lot recently with the release of the new UI. Feel free to re-open this issue if it's still a problem.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

5 participants