Skip to content

Commit 1e536bb

Browse files
authored
chore: localize fetch-json to avoid importing old CJS package (#1300)
* chore: localize fetch-json to avoid importing old CJS package - rewrite fetch-jsonp as ESM but only locally since this is only used for demo purposes * chore: fix build
1 parent 6f53d67 commit 1e536bb

File tree

4 files changed

+93
-13
lines changed

4 files changed

+93
-13
lines changed

packages/demo/package.json

-1
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,6 @@
7474
"copyfiles": "^2.4.1",
7575
"css-loader": "^7.1.2",
7676
"dompurify": "^3.2.2",
77-
"fetch-jsonp": "^1.3.0",
7877
"html-webpack-plugin": "^5.6.3",
7978
"htmlhint": "^1.1.4",
8079
"isomorphic-fetch": "^3.0.0",

packages/demo/src/examples/slickgrid/example3.ts

+4-4
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
import { IHttpClient } from '@aurelia/fetch-client';
22
import { newInstanceOf, resolve } from '@aurelia/kernel';
33
import { I18N } from '@aurelia/i18n';
4-
import fetchJsonp from 'fetch-jsonp';
5-
64
import {
75
type AureliaGridInstance,
86
type AutocompleterOption,
@@ -20,8 +18,10 @@ import {
2018
SortComparers,
2119
type VanillaCalendarOption,
2220
} from 'aurelia-slickgrid';
21+
2322
import { CustomInputEditor } from './custom-inputEditor';
2423
import { CustomInputFilter } from './custom-inputFilter';
24+
import fetchJsonp from './jsonp';
2525

2626
const NB_ITEMS = 100;
2727
const URL_SAMPLE_COLLECTION_DATA = 'assets/data/collection_100_numbers.json';
@@ -279,7 +279,7 @@ export class Example3 {
279279
// this.http.get(`http://gd.geobytes.com/AutoCompleteCity?q=${searchText}`).subscribe(data => updateCallback(data));
280280

281281
/** with JSONP AJAX will work locally but not on the GitHub demo because of CORS */
282-
fetchJsonp(`http://gd.geobytes.com/AutoCompleteCity?q=${searchText}`)
282+
fetchJsonp<string[]>(`http://gd.geobytes.com/AutoCompleteCity?q=${searchText}`, { crossorigin: true })
283283
.then((response: { json: () => Promise<any[]> }) => response.json())
284284
.then((json: any[]) => updateCallback(json))
285285
.catch((ex) => console.log('invalid JSONP response', ex));
@@ -298,7 +298,7 @@ export class Example3 {
298298
filterOptions: {
299299
minLength: 3,
300300
fetch: (searchText: string, updateCallback: (items: false | any[]) => void) => {
301-
fetchJsonp(`http://gd.geobytes.com/AutoCompleteCity?q=${searchText}`)
301+
fetchJsonp<string[]>(`http://gd.geobytes.com/AutoCompleteCity?q=${searchText}`, { crossorigin: true })
302302
.then((response: { json: () => Promise<any[]> }) => response.json())
303303
.then((json: any[]) => updateCallback(json))
304304
.catch((ex: any) => console.log('invalid JSONP response', ex));
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
/*
2+
* copied and rewritten as ESM (just a simple rewrite as ESM to avoid loading a CJS package)
3+
* https://github.com/camsong/fetch-jsonp/blob/master/src/fetch-jsonp.js
4+
*/
5+
6+
interface JsonpOptions {
7+
timeout: number;
8+
jsonpCallback: string;
9+
jsonpCallbackFunction: string;
10+
charset: string;
11+
nonce: string;
12+
referrerPolicy: string;
13+
crossorigin: boolean;
14+
};
15+
16+
const defaultOptions = {
17+
timeout: 5000,
18+
jsonpCallback: 'callback',
19+
jsonpCallbackFunction: null,
20+
};
21+
const generateCallbackFunction = () => `jsonp_${Date.now()}_${Math.ceil(Math.random() * 100000)}`;
22+
const clearFunction = (functionName: string) => delete (window as any)[functionName];
23+
const removeScript = (scriptId: string) => {
24+
const script = document.getElementById(scriptId);
25+
if (script) {
26+
document.getElementsByTagName('head')[0].removeChild(script);
27+
}
28+
};
29+
30+
function fetchJsonp<T = any>(_url: string, options: Partial<JsonpOptions> = {}): Promise<{ ok: boolean; json: () => Promise<T>; }> {
31+
// to avoid param reassign
32+
let url = _url;
33+
const timeout = options.timeout || defaultOptions.timeout;
34+
const jsonpCallback = options.jsonpCallback || defaultOptions.jsonpCallback;
35+
let timeoutId: any;
36+
37+
return new Promise((resolve, reject) => {
38+
const callbackFunction = options.jsonpCallbackFunction || generateCallbackFunction();
39+
const scriptId = `${jsonpCallback}_${callbackFunction}`;
40+
41+
(window as any)[callbackFunction] = (response: T) => {
42+
// keep consistent with fetch API
43+
resolve({ ok: true, json: () => Promise.resolve(response) });
44+
if (timeoutId) clearTimeout(timeoutId);
45+
removeScript(scriptId);
46+
clearFunction(callbackFunction);
47+
};
48+
49+
// Check if the user set their own params, and if not add a ? to start a list of params
50+
url += (url.indexOf('?') === -1) ? '?' : '&';
51+
52+
const jsonpScript = document.createElement('script');
53+
jsonpScript.setAttribute('src', `${url}${jsonpCallback}=${callbackFunction}`);
54+
if (options.charset) {
55+
jsonpScript.setAttribute('charset', options.charset);
56+
}
57+
if (options.nonce) {
58+
jsonpScript.setAttribute('nonce', options.nonce);
59+
}
60+
if (options.referrerPolicy) {
61+
jsonpScript.setAttribute('referrerPolicy', options.referrerPolicy);
62+
}
63+
if (options.crossorigin) {
64+
jsonpScript.setAttribute('crossorigin', 'true');
65+
}
66+
jsonpScript.id = scriptId;
67+
document.getElementsByTagName('head')[0].appendChild(jsonpScript);
68+
69+
timeoutId = setTimeout(() => {
70+
reject(new Error(`JSONP request to ${_url} timed out`));
71+
72+
clearFunction(callbackFunction);
73+
removeScript(scriptId);
74+
(window as any)[callbackFunction] = () => {
75+
clearFunction(callbackFunction);
76+
};
77+
}, timeout);
78+
79+
// Caught if got 404/500
80+
jsonpScript.onerror = () => {
81+
reject(new Error(`JSONP request to ${_url} failed`));
82+
clearFunction(callbackFunction);
83+
removeScript(scriptId);
84+
if (timeoutId) clearTimeout(timeoutId);
85+
};
86+
});
87+
}
88+
89+
export default fetchJsonp;

pnpm-lock.yaml

-8
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)