Sqids NPM module error "not a constructor"

I’m trying to make a plugin for Sqids - an NPM package which turns numbers into short URL-safe codes like YouTube (e.g. [1,2,3] becomes 86Rf07).

I have the following code in my server-side action:

function(properties, context) {
    var Sqids = import( 'sqids' ); // using require or import makes no difference to the error
    var s = new Sqids();  // this line causes the error
    
	return {
        		"id": s.encode([properties.number]) // don't even get to this line
           }
}

I get the error “Sqids is not a constructor”:

image

I feel like I’m using Sqids as intended and it really should be a constructor, as this is the example on npm.org:

image

My green ‘Deployment package is up to date’ line is at the bottom under my dependencies in the plugin builder.

Am I doing something basic wrong?

dynamic imports are async and return a promise.

If you are trying to import an ECMAScript module you can use a dynamic import but you need to await the promise.
If you are trying to import a CommonJs module you should use require.

1 Like

Thank you for your reply and for the hint.

How can I tell if it’s an ECMAScript or CommonJs module? The package.json has this line

 "module": "esm/sqids.js",

so does “esm/sqids.js” means it’s an ECMAScript module? In which case I can’t use require (and I have to use import)? (Noting that I have tried require( ‘sqids’ ) and I get the same error.)

From the link you provided, I understand that there’s also static import syntax:

import Sqids from "sqids";

However, any use of that either outside or inside the run_server function provokes an error from the plugin builder’s code checker - saying it’s not valid JavaScript.

Is import supported on Bubble? It’s not mentioned in their guide:

https://manual.bubble.io/account-and-marketplace/building-plugins/building-actions#using-node-modules-in-a-server-side-action

I’ve spent an hour trying to understand it and this is what I’ve come up with to try to use the dynamic (asynchronous) import function:

async function(properties, context) {
    await context.v3.async((callback) => {
        import( "sqids" ).then((Sqids) => {

            var s = new Sqids();
            
            callback( null, {
                 "id": s.encode([properties.number]),
                 "debug": JSON.stringify( "it worked" )        
            }); 
        });
    });
}

Unfortunately, it gives the same error: Sqids is not a constructor! In other experiments I’ve established that typeof(Sqids) == “object”, but any attempt to use JSON.stringify() to return a debugging result gives some kind of silent error (that line doesn’t seem to execute? But I know JSON.stringify works in other lines, just as long as it’s not trying to stringify s).

I’m floundering around in the dark, and I would appreciate another hint, please!

@michael.fielding this is what you need to do.

context.v3 is deprecated.
Ssa are commonjs, therefore you can only use require and dynamic import.
You can see what kind of module is provided by a library from its package.json, this library provides both types.
Once you require/import the module you need to know if you need the default export or a named export.
const Sqids = require("sqids").default is what you need.
This is basic stuff about modules that usually is handled by your tooling of choice. Because with ssa there isn’t a build step you need to understand at least the basic about how modules works.
If you are unsure about how to use a module you can test it locally with node v18, just install the dependency and execute a file with your logic. It’s quicker than trying stuff with ssa.

Incredible, thank you. I would never have got there without your help, @ankur1 and @dorilama - I’m immensely grateful.

I’ve released v 1.0.0 of Sqids - short codes from numbers, and will announce it on the forum shortly.

Try the demo if you like.

1 Like