Skip to content

Commit

Permalink
Optimize bundle:
Browse files Browse the repository at this point in the history
- Replace axios with fetch
- Add browserslist to reduce bundle size
- Add timeout on fetch requests
  • Loading branch information
nbasili committed Jan 4, 2024
1 parent e7c0547 commit 1f27171
Show file tree
Hide file tree
Showing 4 changed files with 55 additions and 33 deletions.
1 change: 1 addition & 0 deletions packages/native/.eslintrc.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
{
"extends": ["airbnb-base"],
"rules": {
"no-await-in-loop": "off",
"import/no-extraneous-dependencies": "off",
"no-plusplus": "off",
"no-underscore-dangle": "off"
Expand Down
3 changes: 2 additions & 1 deletion packages/native/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
"engines": {
"node": ">=14.0.0"
},
"browserslist": "> 0.5%, last 2 versions, Firefox ESR, not dead",
"devDependencies": {
"@babel/core": "^7.23.5",
"@babel/plugin-transform-runtime": "^7.23.4",
Expand All @@ -54,7 +55,7 @@
},
"dependencies": {
"@messageformat/core": "^3.3.0",
"axios": "^1.6.2",
"cross-fetch": "^4.0.0",
"md5": "^2.3.0"
}
}
72 changes: 46 additions & 26 deletions packages/native/src/TxNative.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/* globals __VERSION__, __PLATFORM__ */

import axios from 'axios';
import fetch from 'cross-fetch';

import MemoryCache from './cache/MemoryCache';
import SourceErrorPolicy from './policies/SourceErrorPolicy';
Expand Down Expand Up @@ -204,7 +204,6 @@ export default class TxNative {
let lastResponseStatus = 202;
const tsNow = Date.now();
while (lastResponseStatus === 202) {
/* eslint-disable no-await-in-loop */
let url = `${this.cdsHost}/content/${localeCode}`;
const getOptions = [];
if (filterTags) {
Expand All @@ -216,24 +215,29 @@ export default class TxNative {
if (getOptions.length) {
url = `${url}?${getOptions.join('&')}`;
}
response = await axios.get(url, {
response = await fetch(url, {
method: 'GET',
headers: {
Authorization: `Bearer ${this.token}`,
'Accept-version': 'v2',
'X-NATIVE-SDK': `txjs/${__PLATFORM__}/${__VERSION__}`,
},
signal: this.fetchTimeout > 0 ? AbortSignal.timeout(this.fetchTimeout) : undefined,
});
if (!response.ok) {
throw new Error(`HTTP error ${response.status}`);
}

lastResponseStatus = response.status;
if (this.fetchTimeout > 0 && (Date.now() - tsNow) >= this.fetchTimeout) {
throw handleError(new Error('Fetch translations timeout'));
}
if (lastResponseStatus === 202 && this.fetchInterval > 0) {
await sleep(this.fetchInterval);
}
/* eslint-enable no-await-in-loop */
}

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

const action = params.purge ? 'purge' : 'invalidate';
const res = await axios.post(`${this.cdsHost}/${action}`, {
}, {
const response = await fetch(`${this.cdsHost}/${action}`, {
method: 'POST',
headers: {
Authorization: `Bearer ${this.token}:${this.secret}`,
'Accept-version': 'v2',
'Content-Type': 'application/json;charset=utf-8',
'X-NATIVE-SDK': `txjs/${__PLATFORM__}/${__VERSION__}`,
},
});
return res.data;
if (!response.ok) {
throw new Error(`HTTP error ${response.status}`);
}
const data = await response.json();
return data;
}

/**
Expand Down Expand Up @@ -323,18 +331,25 @@ export default class TxNative {
'X-NATIVE-SDK': `txjs/${__PLATFORM__}/${__VERSION__}`,
};

const res = await axios.post(`${this.cdsHost}/content`, {
data: payload,
meta: {
purge: !!params.purge,
override_tags: !!params.overrideTags,
override_occurrences: !!params.overrideOccurrences,
},
}, {
const response = await fetch(`${this.cdsHost}/content`, {
method: 'POST',
headers,
body: JSON.stringify({
data: payload,
meta: {
purge: !!params.purge,
override_tags: !!params.overrideTags,
override_occurrences: !!params.overrideOccurrences,
},
}),
});
if (!response.ok) {
throw new Error(`HTTP error ${response.status}`);
}

const postResData = await response.json();

const jobUrl = `${this.cdsHost}${res.data.data.links.job}`;
const jobUrl = `${this.cdsHost}${postResData.data.links.job}`;

if (params.noWait) {
return {
Expand All @@ -347,13 +362,16 @@ export default class TxNative {
};

do {
// eslint-disable-next-line no-await-in-loop
await sleep(1500);
// eslint-disable-next-line no-await-in-loop
const pollRes = await axios.get(jobUrl, {
const pollRes = await fetch(jobUrl, {
method: 'GET',
headers,
});
const { data } = pollRes.data;
if (!pollRes.ok) {
throw new Error(`HTTP error ${response.status}`);
}
const pollResData = await pollRes.json();
const { data } = pollResData;
pollStatus = {
...(data.details || {}),
errors: data.errors || [],
Expand Down Expand Up @@ -395,25 +413,28 @@ export default class TxNative {
let lastResponseStatus = 202;
const tsNow = Date.now();
while (lastResponseStatus === 202) {
/* eslint-disable no-await-in-loop */
response = await axios.get(`${this.cdsHost}/languages`, {
response = await fetch(`${this.cdsHost}/languages`, {
method: 'GET',
headers: {
Authorization: `Bearer ${this.token}`,
'Accept-version': 'v2',
'X-NATIVE-SDK': `txjs/${__PLATFORM__}/${__VERSION__}`,
},
signal: this.fetchTimeout > 0 ? AbortSignal.timeout(this.fetchTimeout) : undefined,
});
if (!response.ok) {
throw new Error(`HTTP error ${response.status}`);
}
lastResponseStatus = response.status;
if (this.fetchTimeout > 0 && (Date.now() - tsNow) >= this.fetchTimeout) {
throw handleError(new Error('Get locales timeout'));
}
if (lastResponseStatus === 202 && this.fetchInterval > 0) {
await sleep(this.fetchInterval);
}
/* eslint-enable no-await-in-loop */
}

const { data } = response;
const data = await response.json();
if (data && data.data) {
this.languages = data.data;
this.locales = this.languages.map((entry) => entry.code);
Expand Down Expand Up @@ -536,7 +557,6 @@ export default class TxNative {
// Fetch translations for additional instance without blocking
// anything else in case of missing language
try {
// eslint-disable-next-line no-await-in-loop
await instances[i].fetchTranslations(localeCode);
} catch (e) {
// no-op
Expand Down
12 changes: 6 additions & 6 deletions packages/native/tests/tx.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -272,13 +272,13 @@ describe('tx instance', () => {
}],
});

let error;
let hasError = false;
try {
await tx.getLocales({ refresh: true });
} catch (err) {
error = err;
hasError = true;
}
expect(error.message).to.equal('Get locales timeout');
expect(hasError).to.equal(true);
});

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

let error;
let hasError = false;
try {
await tx.fetchTranslations('el_timeout');
} catch (err) {
error = err;
hasError = true;
}
expect(error.message).to.equal('Fetch translations timeout');
expect(hasError).to.equal(true);
});

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

0 comments on commit 1f27171

Please sign in to comment.