Skip to content

Commit

Permalink
test using both esm and umd options available
Browse files Browse the repository at this point in the history
  • Loading branch information
imx-mikhala committed Feb 13, 2024
1 parent aec9747 commit 5cb3135
Show file tree
Hide file tree
Showing 6 changed files with 108 additions and 43 deletions.
54 changes: 46 additions & 8 deletions packages/checkout/sdk/src/sdk.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ import { FiatRampService, FiatRampWidgetParams } from './fiatRamp';
import { getItemRequirementsFromRequirements } from './smartCheckout/itemRequirements';
import { CheckoutError, CheckoutErrorType } from './errors';
import { AvailabilityService, availabilityService } from './availability';
import { loadUnresolved } from './widgets/load';
import { getCdnUrl, loadUnresolvedBundle } from './widgets/load';
import { WidgetsInit } from './types/widgets';
import { HttpClient } from './api/http';
import { isMatchingAddress } from './utils/utils';
Expand All @@ -76,6 +76,7 @@ const SANDBOX_CONFIGURATION = {
},
passport: undefined,
};
const WIDGETS_SCRIPT_TIMEOUT = 100;

// Checkout SDK
export class Checkout {
Expand Down Expand Up @@ -118,18 +119,55 @@ export class Checkout {
// Preload the configurations
await checkout.config.remote.getConfig();

const load = loadUnresolved(init.version);
const checkoutWidgetsModule = await import(/* webpackIgnore: true */load.cdnUrl);
// Resolves the factory for the esm build of the widgets
if (init.useEsModules) {
const cdnUrl = getCdnUrl(init.version);
// WebpackIgnore comment required to prevent webpack modifying the import statement and
// breaking the dynamic import in certain applications integrating checkout
const checkoutWidgetsModule = await import(/* webpackIgnore: true */ cdnUrl);

const factory = new Promise<ImmutableCheckoutWidgets.WidgetsFactory>((resolve, reject) => {
try {
const factory = new Promise<ImmutableCheckoutWidgets.WidgetsFactory>((resolve, reject) => {
if (checkoutWidgetsModule && checkoutWidgetsModule.WidgetsFactory) {
resolve(new checkoutWidgetsModule.WidgetsFactory(checkout, init.config));
} else {
throw new Error('WidgetsFactory is not found in the imported module.');
reject(new CheckoutError(
'Unable to resolve the WidgetsFactory from the checkout widgets module',
CheckoutErrorType.WIDGETS_SCRIPT_LOAD_ERROR,
));
}
});

return factory;
}

// Resolves the factory for the umd build of the widgets
const factory = new Promise<ImmutableCheckoutWidgets.WidgetsFactory>((resolve, reject) => {
function checkForWidgetsBundleLoaded() {
if (typeof ImmutableCheckoutWidgets !== 'undefined') {
resolve(new ImmutableCheckoutWidgets.WidgetsFactory(checkout, init.config));
} else {
// If ImmutableCheckoutWidgets is not defined, wait for set amount of time.
// When time has elapsed, check again if ImmutableCheckoutWidgets is defined.
// Once it's defined, the promise will resolve and setTimeout won't be called again.
setTimeout(checkForWidgetsBundleLoaded, WIDGETS_SCRIPT_TIMEOUT);
}
}

try {
const script = loadUnresolvedBundle(init.version);
if (script.loaded && typeof ImmutableCheckoutWidgets !== 'undefined') {
resolve(new ImmutableCheckoutWidgets.WidgetsFactory(checkout, init.config));
} else {
checkForWidgetsBundleLoaded();
}
} catch (error) {
reject(error);
} catch (err: any) {
reject(
new CheckoutError(
'Failed to load widgets script',
CheckoutErrorType.WIDGETS_SCRIPT_LOAD_ERROR,
{ error: err },
),
);
}
});

Expand Down
7 changes: 5 additions & 2 deletions packages/checkout/sdk/src/types/widgets.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,12 @@ import { SemanticVersion } from '../widgets/definitions/types';
/**
* Represents the configuration options for instantiating the Checkout Widgets factory.
* @property {WidgetConfiguration} config - global configuration options for the widgets.
* @property {SemanticVersion | undefined} version - version of the Checkout widgets bundle (default latest version will be used).
* @property {SemanticVersion | undefined} version - version of the Checkout widgets bundle(default latest version will be used).
* @property {boolean | undefined} useEsModules - Set to true to use the esm build of the widgets.
*/
export type WidgetsInit = {
config: WidgetConfiguration;
version?: SemanticVersion
version?: SemanticVersion;
/** Loads separate parts of the widget script as required for performance improvements. */
useEsModules?: boolean;
};
40 changes: 25 additions & 15 deletions packages/checkout/sdk/src/widgets/load.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
// import { useLocalBundle } from '../env';
import { useLocalBundle } from '../env';
import { SemanticVersion } from './definitions/types';
import { validateAndBuildVersion } from './version';

export function loadUnresolved(
// Loads the checkout widgets bundle from the CDN and appends the script to the document head
export function loadUnresolvedBundle(
version?: SemanticVersion,
): { loaded: boolean, cdnUrl: string } {
): { loaded: boolean, element: HTMLScriptElement } {
if (window === undefined) {
throw new Error('missing window object: please run Checkout client side');
}
Expand All @@ -13,25 +14,34 @@ export function loadUnresolved(
throw new Error('missing document object: please run Checkout client side');
}

// const scriptId = 'immutable-checkout-widgets-bundle';
const scriptId = 'immutable-checkout-widgets-bundle';
const validVersion = validateAndBuildVersion(version);

// Prevent the script to be loaded more than once
// by checking the presence of the script and its version.
// const initScript = document.getElementById(scriptId) as HTMLScriptElement;
// if (initScript) return { loaded: true, element: initScript };
const initScript = document.getElementById(scriptId) as HTMLScriptElement;
if (initScript) return { loaded: true, element: initScript };

// const tag = document.createElement('script');
const tag = document.createElement('script');

const cdnUrl = `https://cdn.jsdelivr.net/npm/@imtbl/sdk@${validVersion}/dist/browser/checkout/widgets.js`;
// if (useLocalBundle()) cdnUrl = `http://${window.location.host}/lib/js/widgets.js`;
let cdnUrl = `https://cdn.jsdelivr.net/npm/@imtbl/sdk@${validVersion}/dist/browser/checkout/widgets.js`;
if (useLocalBundle()) cdnUrl = `http://${window.location.host}/lib/js/widgets.js`;

// tag.setAttribute('id', scriptId);
// tag.setAttribute('data-version', validVersion);
// tag.setAttribute('type', 'module');
// tag.setAttribute('src', cdnUrl);
tag.setAttribute('id', scriptId);
tag.setAttribute('data-version', validVersion);
tag.setAttribute('src', cdnUrl);

// document.head.appendChild(tag);
document.head.appendChild(tag);

return { loaded: false, cdnUrl };
return { loaded: false, element: tag };
}

// Gets the CDN url for the split checkout widgets bundle
export function getCdnUrl(
version?: SemanticVersion,
): string {
const validVersion = validateAndBuildVersion(version);
let cdnUrl = `https://cdn.jsdelivr.net/npm/@imtbl/sdk@${validVersion}/dist/browser/checkout/widgets-esm.js`;
if (useLocalBundle()) cdnUrl = `http://${window.location.host}/lib/js/index.js`;
return cdnUrl;
}
30 changes: 22 additions & 8 deletions packages/checkout/widgets-lib/rollup.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,19 @@ import replace from '@rollup/plugin-replace';
import nodePolyfills from 'rollup-plugin-polyfill-node';

const defaultPlugin = [
resolve({
browser: true,
dedupe: ['react', 'react-dom'],
}),
nodePolyfills(),
commonjs(),
json(),
replace({
preventAssignment: true,
'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV || 'production'),
}),
typescript()
typescript(),
terser()
]

export default [
Expand All @@ -24,14 +31,21 @@ export default [
format: 'es'
},
plugins: [
resolve({
browser: true,
dedupe: ['react', 'react-dom'],
}),
nodePolyfills(),
commonjs(),
...defaultPlugin,
terser()
]
},
{
watch: false,
input: 'src/index.ts',
output: {
file: 'dist/widgets.js',
format: 'umd',
name: 'ImmutableCheckoutWidgets',
inlineDynamicImports: true
},
context: 'window',
plugins: [
...defaultPlugin,,
]
}
]
4 changes: 2 additions & 2 deletions sdk/module-release.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,9 @@
"fileCopy": [
{
"src": "../packages/checkout/widgets-lib/dist/index.js",
"dest": "./dist/browser/checkout/widgets.js",
"dest": "./dist/browser/checkout/widgets-esm.js",
"stage": "prod",
"splitBundle": true
"copyAllJsFiles": true
},
{
"src": "../packages/checkout/sdk/dist/browser.js",
Expand Down
16 changes: 8 additions & 8 deletions sdk/scripts/copyBrowserBundles.js
Original file line number Diff line number Diff line change
Expand Up @@ -54,17 +54,17 @@ const main = () => {

fs.writeFileSync(destPath, data);

// Copy over all chunks when the splitBundle flag is set
if (item.splitBundle) {
// Copy over all js files when the copyAllJsFiles flag is set
if (item.copyAllJsFiles) {
const srcDirectory = path.dirname(sourceFile);
const chunkFiles = fs.readdirSync(srcDirectory);
chunkFiles.forEach((chunkFile) => {
const jsFiles = fs.readdirSync(srcDirectory);
jsFiles.forEach((jsFile) => {
// Check if the file is a .js file
if (path.extname(chunkFile) === '.js') {
if (path.extname(jsFile) === '.js') {
// Skip copying the original file and only copy .js chunks
if (chunkFile !== path.basename(sourceFile)) {
const chunkSrcPath = path.join(srcDirectory, chunkFile);
const chunkDestPath = path.join(directoryPath, chunkFile);
if (jsFile !== path.basename(sourceFile)) {
const chunkSrcPath = path.join(srcDirectory, jsFile);
const chunkDestPath = path.join(directoryPath, jsFile);
fs.copyFileSync(chunkSrcPath, chunkDestPath);
}
}
Expand Down

0 comments on commit 5cb3135

Please sign in to comment.