adyen-web icon indicating copy to clipboard operation
adyen-web copied to clipboard

Let this work with vanilla ES6

Open RIAEvangelist opened this issue 4 years ago • 15 comments

Is your feature request related to a problem? Please describe. This lib only works if transpiled and bundled

Describe the solution you'd like I would like to be able to write a simple js example and for this to work in plain JS or plain es6

Describe alternatives you've considered The only way I see to make this work is with a transpiler and bundler

RIAEvangelist avatar Jan 05 '21 05:01 RIAEvangelist

Don't they already have the hosted and compiled version? https://docs.adyen.com/checkout/components-web?tab=script_2#step-2-add-components

nickcaballero avatar Jan 05 '21 16:01 nickcaballero

They do, however the way it is transpiled and bundled prevents it from working in any vanilla JS ES6 as documented. It must be compiled and bundled to work. This should be fixable with the bundler settings.

Basically AdyenCheckout is not a constructor. Here is a screenshot to help.

You can see my server is setup and responding appropriately with the paymentMethods, but the Adyen Web is failing. screenshot of adyen checkout failure

You can see I tried both paths here. The code imports successfully both ways, but neither will work as the module does not export anything due to the bundlers settings. The issue is just that the module does not actually export anything unless transpiled and bundled with the app. I didn't check your webpack or other configs, but that is likely where the fix can be made. simple code sample

RIAEvangelist avatar Jan 05 '21 17:01 RIAEvangelist

Hi @RIAEvangelist, and thanks for reaching out.

Our library is already transpiled in the both ways we distribute it, through NPM and through the hosted file which @nickcaballero mentioned out.

If you're using NPM and a bundle tool like Webpack, you can import it as it's suggested in our readme file:

import AdyenCheckout from '@adyen/adyen-web';
import '@adyen/adyen-web/dist/adyen.css';

If you're not, which I think is your case, you can just add a script tag and a link tag in your HTML page as stated in our docs:

<script src="https://checkoutshopper-test.adyen.com/checkoutshopper/sdk/3.18.2/adyen.js" integrity="sha384-/5SuEQKK7mLmDWB+eUPAur02KPkNC7pwAqyPez1TuNjeqRjsNDJdAnrbSxrzua2P" crossorigin="anonymous"></script>
<link rel="stylesheet" href="https://checkoutshopper-test.adyen.com/checkoutshopper/sdk/3.18.2/adyen.css" integrity="sha384-5K4T5NNVv7ZBvNypROEUSjvOL45HszUg/eYfYadY82UF4b+hc+TPQ4SsfTGXufJp" crossorigin="anonymous">

This will add the AdyenCheckout namespace into the windows object, so then there's no need to import anything. You can just use it directly:

var checkout = new AdyenCheckout();

I hope this helps! Keep in mind you can always contact our Support team. Cheers!

pabloai avatar Jan 06 '21 12:01 pabloai

Hi Pablo,

I am not doing what you are describing, I really think this ticket should be left open.

I am writing ES6 code and not using webpack. Therefore, neither library will work at all, as shown in the screenshot. They also do not work as shown in the docs, because the docs show ES6. If you want to have docs that say, this will not work in native ES6, you must use a transpiler and bundler, that is very different, but really there is no reason for Adyen to ignore supporting vanilla JS ES6.

This issue could be fixed by updating the webpack or ts configuration to let Adyen's library be standards compliant. By not doing this, it means Adyen has no interest in making the library work as documented for native ES6 without webpack. This is a basic use case, and it is how the docs show its use. It is also a simple change.

With this choice, Adyen is forcing all teams that want to use native ES6 to include webpack in their application toolchaion, which many smaller companies and individuals do not need, use or desire the overhead of. So this forces them to abandon Adyen as a solution unless they want to write their own lib from scratch using the documented Curl requests. This level of care for your users should not be a problem as it isn't any special code, it is just changing the webpack or ts config to allow it to work in vanilla js ES6.

Please consider reopning this ticket and making this simple change to allow a larger reach and better adoption of Adyesn's platform. This can only serve to increase adoption and Adyen's overall profits due to better developer adoption.

Best regards.

RIAEvangelist avatar Jan 06 '21 17:01 RIAEvangelist

I decided to follow up and check if the window object was exposed when importing the npm ES6 module natively. Sure enough it is. This does not follow the documentation, and is not standard ES6 implementation. I see two solutions:

  1. fix the documentation to show new window.AdyenCheckout even in the ES6 import scenario, as AdyenCheckout is not exported even from the npm module.
  2. fix the code so AdyenCheckout is actually exported in the npm module.

I believe the confusion is that the devs used typescript ES6 to write the module but transpiled it down to ES5 exposing it in the global, thereby making the docs incorrect for using vanilla ES6 examples.

I included screenshots below :

Importing npm module actual code importing npm module

even with NPM module, ONLY window.Adyen is available. result of importing native ES6

This does not match the documentation nor standard ES6 module named exports, which are shown in the docs here adyen doc

In order for this to be correct, the user MUST use window.AdyenCheckout as new AdyenCheckout no matter how you import it is not a named export. Adyen's code always forces this to be declared in the global window scope, regardless of npm module or script The reason this is a problem is that ES6 module scopes are local to the module. If a user wants to use something from the global they must explicitly say window. This should either be changed in the code, or documented.

This is further complicated by the fact that the docs say import AdyenCheckout from '...' but there is no named export for the npm module. So inorder to get the code to work we must import * as AdyenCheckout from '...' this allows the window instantiation to happen, but just imports a symbol as the Adyen module throws an error does not export default any other way in native ES6.

I hope this helps.

RIAEvangelist avatar Jan 06 '21 18:01 RIAEvangelist

Hello again @RIAEvangelist,

We can of course re-open the ticket, no problem with that. I created 2 small demos to show how we intend the library to be used:

  • Loading the library from our self hosted script file. This demo uses only vanilla JS: https://codesandbox.io/s/sad-mahavira-7cged?file=/src/index.js
  • Loading the library from NPM. This demo uses a bundler: https://codesandbox.io/s/practical-feynman-x6q6o?file=/src/index.js

In the first example, using window.AdyenCheckout is recommended but not mandatory. This self hosted script uses UMD to make it easier to use in different environments.

Also in our next major release, which will be v4, we're migrating from Webpack to Rollup.js to offer more output formats apart of UMD like CommonJS and ES Modules.

I hope this helps, cheers.

pabloai avatar Jan 07 '21 13:01 pabloai

If you write a native ESM module, without transpiling, you actually do need to use window.AdyenCheckout because neither the NPM module, nor the script tag install, export a named AdyenCheckout constructor. They both explicitly create on the window object. I assume the confusion here is because the code is written in TS flavor ES6, but transpiled to ES5. Please check out what I am pointing out with a simple test in chrome. Try importing the adyen-web lib dist.js. You will see it fails unless you import * and use window. to access it. Also, ESM modules global is scoped to the module itself. So you would need to use window or globalThis.

Also, awesome, and thanks for re-opening. I am finishing a write-up and completed native ES6/ESM implementation for the way Adyen style implementation the code needs to be done. I understand Native ESM modules might not have been an intended target, but they are the native route. That said, the code can work as is, but the docs should probably be updated to show how to do this via native ESM. I find this to be really important because otherwise, you are leaving it up to the dev to feel determined enough to figure this out.

I'll put up a link to my example and experience for your team to consider. I hope I haven't pushed any of the wrong buttons with my standards-compliance nerdisms.

I know this is a bit "Well Acktchually", but... Well Acktchually

RIAEvangelist avatar Jan 07 '21 18:01 RIAEvangelist

OK, so this is just my first pass at the Drop-In implementation. By no means is it complete, it's just a native ESM/ES6 example. I spent a couple of hours doing it last night and an hour or so writing everything up this morning. I hope the Gifs are taken lightheartedly as they are meant to be fun and add a jovial flavor to the writeup.

Brandon Nozaki Miller Adyen Web Dropin Prototype

RIAEvangelist avatar Jan 07 '21 18:01 RIAEvangelist

Btw, as an update, if I import the module with a bogus name I can access it as you suggest, but again this is not how it is documented nor really how one would expect.


import * as AdyenCheckout from '/node_modules/@adyen/adyen-web/dist/adyen.js';
//import * as AdyenCheckout from 'https://checkoutshopper-test.adyen.com/checkoutshopper/sdk/3.18.2/adyen.js';

//this blocks the use of AdyenCheckout in this ESM because of scoping
console.log(AdyenCheckout)
//Logs a Symbol ref to the empty export of the module
console.log(window.AdyenCheckout)
//logs the AdyenCheckout module


import * as ClobberFreeAdyenCheckout from '/node_modules/@adyen/adyen-web/dist/adyen.js';
//import * as ClobberFreeAdyenCheckout from 'https://checkoutshopper-test.adyen.com/checkoutshopper/sdk/3.18.2/adyen.js';

//this logs the window.AdyenCheckout because we used the name ClobberFreeAdyenCheckout for the import
console.log(AdyenCheckout) //really a ref to window.AdyenCheckout ^

//also logs the global AdyenCheckout
console.log(window.AdyenCheckout)

Or perhaps the best option especially to simplify your work updating the docs :


import '/node_modules/@adyen/adyen-web/dist/adyen.js';
//import 'https://checkoutshopper-test.adyen.com/checkoutshopper/sdk/3.18.2/adyen.js';

//this logs the window.AdyenCheckout because we did not import any name
console.log(AdyenCheckout) //really a ref to window.AdyenCheckout ^

//also logs the global AdyenCheckout
console.log(window.AdyenCheckout)

Hope that's helpful :)

RIAEvangelist avatar Jan 08 '21 02:01 RIAEvangelist

Just my few cents here, while the issue described by @RIAEvangelist is present its not something we actually have to worry about in the near future for the intended audience IMO, I'm not expecting anyone using the Adyen platform to build applications without using a bundler like webpack and given the current status of native ES6 modules being not being popular over a bundler, I'm not expecting people to start doing this in real world projects anytime soon. So while this ticket can be kept open and I agree there needs to be some overall improvements in the module definitions, it doesn't have to be prioritized IMO

deepu105 avatar Jan 14 '21 20:01 deepu105

Hi @deepu105 I understand what you are saying. The main thing I think would be good, and easy, to do is update the docs to be accurate. Even if Adyen doesn't see it as an intended use case.

Also, about the state of ES6, had I not used the private classes in the strong-type module it would be fully supported by all modern browsers. ES6 actually has 95-97% implementation & penetration depending on the country you look at (excluding private class members etc.).

You can get a great overview of the state of ES6 from this google dev video on transitioning to modern js. It also describes the environmental and economic impact of transpiling, not that that really matters here though. A simple doc update showing how the code actually works would suffice.

I watched that google developer video on the state of modern js at 1.75 speed though. So much to learn, and so little time.

Best!

RIAEvangelist avatar Jan 14 '21 21:01 RIAEvangelist

@RIAEvangelist It might also be possible to just import the module without a name. Since window is the default namespace, AdyenCheckout should resolve correctly. So just import 'addressToModule';

nickcaballero avatar Jan 14 '21 23:01 nickcaballero

@nickcaballero yup, that's the quick fix I'm suggesting for the docs just above @deepu105's post

it's the last code snippet here

Added it here so you don't have to actually click the link.


import '/node_modules/@adyen/adyen-web/dist/adyen.js';
//import 'https://checkoutshopper-test.adyen.com/checkoutshopper/sdk/3.18.2/adyen.js';

//this logs the window.AdyenCheckout because we did not import any name
console.log(AdyenCheckout) //really a ref to window.AdyenCheckout ^

//also logs the global AdyenCheckout
console.log(window.AdyenCheckout)

RIAEvangelist avatar Jan 15 '21 00:01 RIAEvangelist

A form of the suggested documentation was pushed to prod in the docs.

Also, I am now a member of the dev advocate at Adyen. Woot for filing tickets!

RIAEvangelist avatar Apr 07 '21 16:04 RIAEvangelist

I see these changes were reverted after I noted the change. This brings this issue back to life.

RIAEvangelist avatar Apr 09 '21 22:04 RIAEvangelist