From de037e43e0e4e26af9398335de6c25f67e06be4e Mon Sep 17 00:00:00 2001 From: Vjacheslav Trushkin Date: Sat, 6 Jun 2020 12:50:17 +0300 Subject: [PATCH] Fix cache in JSONP module, add optional axios module (disabled by default because it is much bigger than jsonp) --- packages/iconify/package-lock.json | 6 +- packages/iconify/package.json | 1 + packages/iconify/rollup.config.js | 9 +- packages/iconify/src/modules/api-axios.ts | 146 ++++++++++++++++++++++ packages/iconify/src/modules/api-jsonp.ts | 13 +- 5 files changed, 164 insertions(+), 11 deletions(-) create mode 100644 packages/iconify/src/modules/api-axios.ts diff --git a/packages/iconify/package-lock.json b/packages/iconify/package-lock.json index 0e39d33..230a36c 100644 --- a/packages/iconify/package-lock.json +++ b/packages/iconify/package-lock.json @@ -273,7 +273,6 @@ "resolved": "https://registry.npmjs.org/axios/-/axios-0.19.2.tgz", "integrity": "sha512-fjgm5MvRHLhx+osE2xoekY70AhARk3a6hkN+3Io1jc00jtquGvxYlKlsFUhmUET0V5te6CcZI7lcv2Ym61mjHA==", "dev": true, - "optional": true, "requires": { "follow-redirects": "1.5.10" } @@ -385,7 +384,6 @@ "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", "dev": true, - "optional": true, "requires": { "ms": "2.0.0" } @@ -422,7 +420,6 @@ "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.5.10.tgz", "integrity": "sha512-0V5l4Cizzvqt5D44aTXbFZz+FtyXV1vrDN6qrelxtfYQKW0KO0W2T/hkE8xvGa/540LkZlkaUjO4ailYTFtHVQ==", "dev": true, - "optional": true, "requires": { "debug": "=3.1.0" } @@ -617,8 +614,7 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true, - "optional": true + "dev": true }, "once": { "version": "1.4.0", diff --git a/packages/iconify/package.json b/packages/iconify/package.json index 7876788..ebbc593 100644 --- a/packages/iconify/package.json +++ b/packages/iconify/package.json @@ -29,6 +29,7 @@ "@rollup/plugin-commonjs": "^11.1.0", "@rollup/plugin-node-resolve": "^7.1.3", "@rollup/plugin-replace": "^2.3.2", + "axios": "^0.19.2", "rollup": "^1.32.0", "rollup-plugin-terser": "^5.2.0", "typescript": "^3.9.3" diff --git a/packages/iconify/rollup.config.js b/packages/iconify/rollup.config.js index bd18839..be27942 100644 --- a/packages/iconify/rollup.config.js +++ b/packages/iconify/rollup.config.js @@ -83,7 +83,14 @@ const config = []; footer, }, ], - plugins: [resolve(), commonjs(), replace(replacements), buble()], + plugins: [ + resolve({ + browser: true, + }), + commonjs(), + replace(replacements), + buble(), + ], }; if (compress) { item.plugins.push(terser()); diff --git a/packages/iconify/src/modules/api-axios.ts b/packages/iconify/src/modules/api-axios.ts new file mode 100644 index 0000000..75e6cb9 --- /dev/null +++ b/packages/iconify/src/modules/api-axios.ts @@ -0,0 +1,146 @@ +import axios from 'axios'; +import { RedundancyPendingItem } from '@cyberalien/redundancy'; +import { + APIQueryParams, + IconifyAPIPrepareQuery, + IconifyAPISendQuery, +} from '@iconify/core/lib/api/modules'; +import { getAPIConfig } from '@iconify/core/lib/api/config'; + +/** + * Endpoint + */ +let endPoint = '{prefix}.json?icons={icons}'; + +/** + * Cache + */ +const maxLengthCache: Record = Object.create(null); +const pathCache: Record = Object.create(null); + +/** + * Calculate maximum icons list length for prefix + */ +function calculateMaxLength(provider: string, prefix: string): number { + // Get config and store path + const config = getAPIConfig(provider); + if (!config) { + return 0; + } + + // Calculate + let result; + if (!config.maxURL) { + result = 0; + } else { + let maxHostLength = 0; + config.resources.forEach((host) => { + maxHostLength = Math.max(maxHostLength, host.length); + }); + + // Get available length + result = + config.maxURL - + maxHostLength - + config.path.length - + endPoint + .replace('{provider}', provider) + .replace('{prefix}', prefix) + .replace('{icons}', '').length; + } + + // Cache stuff and return result + const cacheKey = provider + ':' + prefix; + pathCache[cacheKey] = config.path; + maxLengthCache[cacheKey] = result; + return result; +} + +/** + * Prepare params + */ +export const prepareQuery: IconifyAPIPrepareQuery = ( + provider: string, + prefix: string, + icons: string[] +): APIQueryParams[] => { + const results: APIQueryParams[] = []; + + // Get maximum icons list length + let maxLength = maxLengthCache[prefix]; + if (maxLength === void 0) { + maxLength = calculateMaxLength(provider, prefix); + } + + // Split icons + let item: APIQueryParams = { + provider, + prefix, + icons: [], + }; + let length = 0; + icons.forEach((name, index) => { + length += name.length + 1; + if (length >= maxLength && index > 0) { + // Next set + results.push(item); + item = { + provider, + prefix, + icons: [], + }; + length = name.length; + } + + item.icons.push(name); + }); + results.push(item); + + return results; +}; + +/** + * Load icons + */ +export const sendQuery: IconifyAPISendQuery = ( + host: string, + params: APIQueryParams, + status: RedundancyPendingItem +): void => { + const provider = params.provider; + const prefix = params.prefix; + const icons = params.icons; + const iconsList = icons.join(','); + + const cacheKey = provider + ':' + prefix; + let path = + pathCache[cacheKey] + + endPoint + .replace('{provider}', provider) + .replace('{prefix}', prefix) + .replace('{icons}', iconsList); + + // console.log('API query:', host + path); + const instance = axios.create({ + baseURL: host, + }); + instance + .get(path) + .then((response) => { + if (response.status !== 200) { + return; + } + + // Copy data. No need to parse it, axios parses JSON data + const data = response.data; + if (typeof data !== 'object' || data === null) { + return; + } + + // Store cache and complete + status.done(data); + }) + .catch((err) => { + // Do nothing + }); +}; diff --git a/packages/iconify/src/modules/api-jsonp.ts b/packages/iconify/src/modules/api-jsonp.ts index aaeb898..67dea6d 100644 --- a/packages/iconify/src/modules/api-jsonp.ts +++ b/packages/iconify/src/modules/api-jsonp.ts @@ -19,7 +19,7 @@ let global: JSONPRoot | null = null; let endPoint = '{prefix}.js?icons={icons}&callback={callback}'; /** - * Cache + * Cache: provider:prefix = value */ const maxLengthCache: Record = Object.create(null); const pathCache: Record = Object.create(null); @@ -120,8 +120,9 @@ function calculateMaxLength(provider: string, prefix: string): number { } // Cache stuff and return result - pathCache[prefix] = config.path; - maxLengthCache[prefix] = result; + const cacheKey = provider + ':' + prefix; + pathCache[cacheKey] = config.path; + maxLengthCache[cacheKey] = result; return result; } @@ -136,7 +137,8 @@ export const prepareQuery: IconifyAPIPrepareQuery = ( const results: APIQueryParams[] = []; // Get maximum icons list length - let maxLength = maxLengthCache[prefix]; + const cacheKey = provider + ':' + prefix; + let maxLength = maxLengthCache[cacheKey]; if (maxLength === void 0) { maxLength = calculateMaxLength(provider, prefix); } @@ -180,6 +182,7 @@ export const sendQuery: IconifyAPISendQuery = ( const prefix = params.prefix; const icons = params.icons; const iconsList = icons.join(','); + const cacheKey = provider + ':' + prefix; // Create callback prefix const cbPrefix = prefix.split('-').shift().slice(0, 3); @@ -196,7 +199,7 @@ export const sendQuery: IconifyAPISendQuery = ( const callbackName = cbPrefix + cbCounter; let path = - pathCache[prefix] + + pathCache[cacheKey] + endPoint .replace('{provider}', provider) .replace('{prefix}', prefix)