Skip to content

Commit a2e9051

Browse files
author
Nikos Vasileiou
authored
Merge pull request #204 from transifex/replace-axios-with-fetch
Optimize bundle size
2 parents 79fa4d2 + 2e87700 commit a2e9051

4 files changed

Lines changed: 71 additions & 33 deletions

File tree

packages/native/.eslintrc.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
{
22
"extends": ["airbnb-base"],
33
"rules": {
4+
"no-await-in-loop": "off",
45
"import/no-extraneous-dependencies": "off",
56
"no-plusplus": "off",
67
"no-underscore-dangle": "off"

packages/native/package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
"engines": {
3434
"node": ">=14.0.0"
3535
},
36+
"browserslist": "> 0.5%, last 2 versions, Firefox ESR, not dead",
3637
"devDependencies": {
3738
"@babel/core": "^7.23.5",
3839
"@babel/plugin-transform-runtime": "^7.23.4",
@@ -54,7 +55,7 @@
5455
},
5556
"dependencies": {
5657
"@messageformat/core": "^3.3.0",
57-
"axios": "^1.6.2",
58+
"cross-fetch": "^4.0.0",
5859
"md5": "^2.3.0"
5960
}
6061
}

packages/native/src/TxNative.js

Lines changed: 62 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/* globals __VERSION__, __PLATFORM__ */
22

3-
import axios from 'axios';
3+
import fetch from 'cross-fetch';
44

55
import MemoryCache from './cache/MemoryCache';
66
import SourceErrorPolicy from './policies/SourceErrorPolicy';
@@ -204,7 +204,6 @@ export default class TxNative {
204204
let lastResponseStatus = 202;
205205
const tsNow = Date.now();
206206
while (lastResponseStatus === 202) {
207-
/* eslint-disable no-await-in-loop */
208207
let url = `${this.cdsHost}/content/${localeCode}`;
209208
const getOptions = [];
210209
if (filterTags) {
@@ -216,24 +215,29 @@ export default class TxNative {
216215
if (getOptions.length) {
217216
url = `${url}?${getOptions.join('&')}`;
218217
}
219-
response = await axios.get(url, {
218+
response = await fetch(url, {
219+
method: 'GET',
220220
headers: {
221221
Authorization: `Bearer ${this.token}`,
222222
'Accept-version': 'v2',
223223
'X-NATIVE-SDK': `txjs/${__PLATFORM__}/${__VERSION__}`,
224224
},
225+
signal: this.fetchTimeout > 0 ? AbortSignal.timeout(this.fetchTimeout) : undefined,
225226
});
227+
if (!response.ok) {
228+
throw (await this._fetchError(response));
229+
}
230+
226231
lastResponseStatus = response.status;
227232
if (this.fetchTimeout > 0 && (Date.now() - tsNow) >= this.fetchTimeout) {
228233
throw handleError(new Error('Fetch translations timeout'));
229234
}
230235
if (lastResponseStatus === 202 && this.fetchInterval > 0) {
231236
await sleep(this.fetchInterval);
232237
}
233-
/* eslint-enable no-await-in-loop */
234238
}
235239

236-
const { data } = response;
240+
const data = await response.json();
237241
if (data && data.data) {
238242
const hashmap = {};
239243
Object.keys(data.data).forEach((key) => {
@@ -266,16 +270,20 @@ export default class TxNative {
266270
if (!this.secret) throw new Error('secret is not defined');
267271

268272
const action = params.purge ? 'purge' : 'invalidate';
269-
const res = await axios.post(`${this.cdsHost}/${action}`, {
270-
}, {
273+
const response = await fetch(`${this.cdsHost}/${action}`, {
274+
method: 'POST',
271275
headers: {
272276
Authorization: `Bearer ${this.token}:${this.secret}`,
273277
'Accept-version': 'v2',
274278
'Content-Type': 'application/json;charset=utf-8',
275279
'X-NATIVE-SDK': `txjs/${__PLATFORM__}/${__VERSION__}`,
276280
},
277281
});
278-
return res.data;
282+
if (!response.ok) {
283+
throw (await this._fetchError(response));
284+
}
285+
const data = await response.json();
286+
return data;
279287
}
280288

281289
/**
@@ -323,18 +331,25 @@ export default class TxNative {
323331
'X-NATIVE-SDK': `txjs/${__PLATFORM__}/${__VERSION__}`,
324332
};
325333

326-
const res = await axios.post(`${this.cdsHost}/content`, {
327-
data: payload,
328-
meta: {
329-
purge: !!params.purge,
330-
override_tags: !!params.overrideTags,
331-
override_occurrences: !!params.overrideOccurrences,
332-
},
333-
}, {
334+
const response = await fetch(`${this.cdsHost}/content`, {
335+
method: 'POST',
334336
headers,
337+
body: JSON.stringify({
338+
data: payload,
339+
meta: {
340+
purge: !!params.purge,
341+
override_tags: !!params.overrideTags,
342+
override_occurrences: !!params.overrideOccurrences,
343+
},
344+
}),
335345
});
346+
if (!response.ok) {
347+
throw (await this._fetchError(response));
348+
}
336349

337-
const jobUrl = `${this.cdsHost}${res.data.data.links.job}`;
350+
const postResData = await response.json();
351+
352+
const jobUrl = `${this.cdsHost}${postResData.data.links.job}`;
338353

339354
if (params.noWait) {
340355
return {
@@ -347,13 +362,16 @@ export default class TxNative {
347362
};
348363

349364
do {
350-
// eslint-disable-next-line no-await-in-loop
351365
await sleep(1500);
352-
// eslint-disable-next-line no-await-in-loop
353-
const pollRes = await axios.get(jobUrl, {
366+
const pollRes = await fetch(jobUrl, {
367+
method: 'GET',
354368
headers,
355369
});
356-
const { data } = pollRes.data;
370+
if (!pollRes.ok) {
371+
throw (await this._fetchError(pollRes));
372+
}
373+
const pollResData = await pollRes.json();
374+
const { data } = pollResData;
357375
pollStatus = {
358376
...(data.details || {}),
359377
errors: data.errors || [],
@@ -395,25 +413,28 @@ export default class TxNative {
395413
let lastResponseStatus = 202;
396414
const tsNow = Date.now();
397415
while (lastResponseStatus === 202) {
398-
/* eslint-disable no-await-in-loop */
399-
response = await axios.get(`${this.cdsHost}/languages`, {
416+
response = await fetch(`${this.cdsHost}/languages`, {
417+
method: 'GET',
400418
headers: {
401419
Authorization: `Bearer ${this.token}`,
402420
'Accept-version': 'v2',
403421
'X-NATIVE-SDK': `txjs/${__PLATFORM__}/${__VERSION__}`,
404422
},
423+
signal: this.fetchTimeout > 0 ? AbortSignal.timeout(this.fetchTimeout) : undefined,
405424
});
425+
if (!response.ok) {
426+
throw (await this._fetchError(response));
427+
}
406428
lastResponseStatus = response.status;
407429
if (this.fetchTimeout > 0 && (Date.now() - tsNow) >= this.fetchTimeout) {
408430
throw handleError(new Error('Get locales timeout'));
409431
}
410432
if (lastResponseStatus === 202 && this.fetchInterval > 0) {
411433
await sleep(this.fetchInterval);
412434
}
413-
/* eslint-enable no-await-in-loop */
414435
}
415436

416-
const { data } = response;
437+
const data = await response.json();
417438
if (data && data.data) {
418439
this.languages = data.data;
419440
this.locales = this.languages.map((entry) => entry.code);
@@ -536,7 +557,6 @@ export default class TxNative {
536557
// Fetch translations for additional instance without blocking
537558
// anything else in case of missing language
538559
try {
539-
// eslint-disable-next-line no-await-in-loop
540560
await instances[i].fetchTranslations(localeCode);
541561
} catch (e) {
542562
// no-op
@@ -553,4 +573,20 @@ export default class TxNative {
553573
}
554574
});
555575
}
576+
577+
/**
578+
* Return a new fetch error
579+
*
580+
* @param {*} response
581+
* @memberof TxNative
582+
*/
583+
// eslint-disable-next-line class-methods-use-this
584+
async _fetchError(response) {
585+
try {
586+
const text = await response.text();
587+
return new Error(`HTTP ${response.status}: ${text}`);
588+
} catch (err) {
589+
return new Error(`HTTP error ${response.status}`);
590+
}
591+
}
556592
}

packages/native/tests/tx.test.js

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -272,13 +272,13 @@ describe('tx instance', () => {
272272
}],
273273
});
274274

275-
let error;
275+
let hasError = false;
276276
try {
277277
await tx.getLocales({ refresh: true });
278278
} catch (err) {
279-
error = err;
279+
hasError = true;
280280
}
281-
expect(error.message).to.equal('Get locales timeout');
281+
expect(hasError).to.equal(true);
282282
});
283283

284284
it('retries fetching languages with interval', async () => {
@@ -322,13 +322,13 @@ describe('tx instance', () => {
322322
.get('/content/el_timeout')
323323
.reply(200, { data: { source: { string: 'translation' } } });
324324

325-
let error;
325+
let hasError = false;
326326
try {
327327
await tx.fetchTranslations('el_timeout');
328328
} catch (err) {
329-
error = err;
329+
hasError = true;
330330
}
331-
expect(error.message).to.equal('Fetch translations timeout');
331+
expect(hasError).to.equal(true);
332332
});
333333

334334
it('retries fetching translations with interval delays', async () => {

0 commit comments

Comments
 (0)