browserslist.tsx 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637
  1. import {lazy, Suspense, useEffect, useMemo, useState} from 'react';
  2. import styled from '@emotion/styled';
  3. import {CodeSnippet} from 'sentry/components/codeSnippet';
  4. import * as Layout from 'sentry/components/layouts/thirds';
  5. import LoadingIndicator from 'sentry/components/loadingIndicator';
  6. import LoadingMask from 'sentry/components/loadingMask';
  7. import {t} from 'sentry/locale';
  8. import {space} from 'sentry/styles/space';
  9. import EventView from 'sentry/utils/discover/eventView';
  10. import {decodeScalar} from 'sentry/utils/queryString';
  11. import {MutableSearch} from 'sentry/utils/tokenizeSearch';
  12. import useApi from 'sentry/utils/useApi';
  13. import {useLocation} from 'sentry/utils/useLocation';
  14. import useOrganization from 'sentry/utils/useOrganization';
  15. import {useParams} from 'sentry/utils/useParams';
  16. // const browsersListOutput = [
  17. // 'chrome 111',
  18. // 'chrome 110',
  19. // 'chrome 109',
  20. // 'chrome 108',
  21. // 'chrome 107',
  22. // 'chrome 106',
  23. // 'chrome 105',
  24. // 'chrome 104',
  25. // 'chrome 103',
  26. // 'chrome 102',
  27. // 'edge 111',
  28. // 'edge 110',
  29. // 'firefox 111',
  30. // 'firefox 110',
  31. // 'firefox 109',
  32. // 'firefox 108',
  33. // 'firefox 107',
  34. // 'firefox 106',
  35. // 'firefox 105',
  36. // 'firefox 104',
  37. // 'firefox 103',
  38. // 'firefox 102',
  39. // 'ios_saf 16.4',
  40. // 'ios_saf 16.3',
  41. // 'ios_saf 16.2',
  42. // 'ios_saf 16.1',
  43. // 'ios_saf 16.0',
  44. // 'ios_saf 15.6',
  45. // 'ios_saf 15.5',
  46. // 'ios_saf 15.4',
  47. // 'ios_saf 15.2-15.3',
  48. // 'ios_saf 15.0-15.1',
  49. // 'ios_saf 14.5-14.8',
  50. // 'ios_saf 14.0-14.4',
  51. // 'op_mob 73',
  52. // 'safari 16.4',
  53. // 'safari 16.3',
  54. // 'safari 16.2',
  55. // 'safari 16.1',
  56. // 'safari 16.0',
  57. // 'safari 15.6',
  58. // 'safari 15.5',
  59. // 'safari 15.4',
  60. // 'safari 15.2-15.3',
  61. // 'safari 15.1',
  62. // 'safari 15',
  63. // ];
  64. const packageJsonBrowsersList = {
  65. browserslist: {
  66. production: [
  67. 'last 10 Chrome versions',
  68. 'last 10 Firefox versions',
  69. 'last 2 Edge major versions',
  70. 'last 2 Safari major versions',
  71. 'last 3 iOS major versions',
  72. 'last 1 OperaMobile version',
  73. 'Firefox ESR',
  74. ],
  75. development: [
  76. 'last 10 Chrome versions',
  77. 'last 10 Firefox versions',
  78. 'last 2 Edge major versions',
  79. 'last 2 Safari major versions',
  80. 'last 3 iOS major versions',
  81. 'last 1 OperaMobile version',
  82. 'Firefox ESR',
  83. ],
  84. test: ['current node'],
  85. },
  86. };
  87. const browsersListOutput = `chrome 111
  88. chrome 110
  89. chrome 109
  90. chrome 108
  91. chrome 107
  92. chrome 106
  93. chrome 105
  94. chrome 104
  95. chrome 103
  96. chrome 102
  97. edge 111
  98. edge 110
  99. firefox 111
  100. firefox 110
  101. firefox 109
  102. firefox 108
  103. firefox 107
  104. firefox 106
  105. firefox 105
  106. firefox 104
  107. firefox 103
  108. firefox 102
  109. ios_saf 16.4
  110. ios_saf 16.3
  111. ios_saf 16.2
  112. ios_saf 16.1
  113. ios_saf 16.0
  114. ios_saf 15.6
  115. ios_saf 15.5
  116. ios_saf 15.4
  117. ios_saf 15.2-15.3
  118. ios_saf 15.0-15.1
  119. ios_saf 14.5-14.8
  120. ios_saf 14.0-14.4
  121. op_mob 73
  122. safari 16.4
  123. safari 16.3
  124. safari 16.2
  125. safari 16.1
  126. safari 16.0
  127. safari 15.6
  128. safari 15.5
  129. safari 15.4
  130. safari 15.2-15.3
  131. safari 15.1
  132. safari 15`;
  133. const browsersList = {
  134. chrome: {
  135. max: 111,
  136. min: 102,
  137. },
  138. edge: {
  139. max: 111,
  140. min: 110,
  141. },
  142. firefox: {
  143. max: 111,
  144. min: 102,
  145. },
  146. ios_saf: {
  147. max: 16.4,
  148. min: 15.4,
  149. },
  150. op_mob: {
  151. max: 73,
  152. min: 73,
  153. },
  154. safari: {
  155. max: 16.4,
  156. min: 15,
  157. },
  158. };
  159. // const SUPPORTED_BROWSERS = [
  160. // 'Chrome',
  161. // 'Firefox',
  162. // 'Edge',
  163. // 'Safari',
  164. // 'Mobile Safari',
  165. // 'Opera Mobile',
  166. // ];
  167. // const SUPPORTED_BROWSERS = ['Chrome'];
  168. const LazyContextIcon = lazy(
  169. () => import('sentry/components/events/contextSummary/contextIcon')
  170. );
  171. export default function BrowsersList() {
  172. const org = useOrganization();
  173. const api = useApi();
  174. const location = useLocation();
  175. const params = useParams();
  176. const [_, setLoading] = useState(false);
  177. const {release} = params;
  178. const eventView = useMemo(() => {
  179. const query = decodeScalar(location.query.query, '');
  180. const conditions = new MutableSearch(query);
  181. conditions.addFilterValue('release', release);
  182. return EventView.fromNewQueryWithLocation(
  183. {
  184. id: '',
  185. name: '',
  186. version: 2,
  187. fields: ['count()'],
  188. projects: [],
  189. orderby: '-count',
  190. query: conditions.formatString(),
  191. },
  192. location
  193. );
  194. }, [location, release]);
  195. useEffect(() => {
  196. api.clear();
  197. setLoading(true);
  198. async function fetchEvents() {
  199. await api.requestPromise(`/organizations/${org.slug}/events/`, {
  200. query: {
  201. ...eventView.getEventsAPIPayload(location),
  202. },
  203. method: 'GET',
  204. });
  205. setLoading(false);
  206. }
  207. fetchEvents();
  208. }, [api, org, location, eventView]);
  209. return (
  210. <Layout.Page>
  211. <BrowserAnalysisWrapper style={{display: 'flex', justifyContent: 'space-evenly'}}>
  212. <BrowserAnalysis browser="Chrome" />
  213. <BrowserAnalysis browser="Firefox" />
  214. <BrowserAnalysis browser="Safari" />
  215. <BrowserAnalysis browser="Edge" />
  216. </BrowserAnalysisWrapper>
  217. <div style={{fontSize: '24px', fontWeight: 'bold', textAlign: 'center'}}>
  218. {t('Generated with ')}
  219. <code>caniuse-lite@1.0.30001473</code>
  220. </div>
  221. <div style={{display: 'flex', justifyContent: 'space-evenly'}}>
  222. <CodeSnippet language="json">
  223. {JSON.stringify(packageJsonBrowsersList, null, 2)}
  224. </CodeSnippet>
  225. <CodeSnippet language="txt">{browsersListOutput}</CodeSnippet>
  226. </div>
  227. </Layout.Page>
  228. );
  229. }
  230. interface BrowserAnalysisProps {
  231. browser: string;
  232. }
  233. function BrowserAnalysis({browser}: BrowserAnalysisProps) {
  234. const org = useOrganization();
  235. const api = useApi();
  236. const location = useLocation();
  237. const params = useParams();
  238. const [results, setResults] = useState(undefined);
  239. const {release} = params;
  240. const eventView = useMemo(() => {
  241. const query = decodeScalar(location.query.query, '');
  242. const conditions = new MutableSearch(query);
  243. conditions.addFilterValue('release', release);
  244. conditions.addFilterValue('browser.name', browser);
  245. return EventView.fromNewQueryWithLocation(
  246. {
  247. id: '',
  248. name: '',
  249. version: 2,
  250. fields: ['browser', 'count()'],
  251. projects: [],
  252. orderby: '-count',
  253. query: conditions.formatString(),
  254. },
  255. location
  256. );
  257. }, [location, release, browser]);
  258. useEffect(() => {
  259. api.clear();
  260. setResults(undefined);
  261. async function fetchEvents() {
  262. const res = await api.requestPromise(`/organizations/${org.slug}/events/`, {
  263. query: {
  264. ...eventView.getEventsAPIPayload(location),
  265. },
  266. method: 'GET',
  267. });
  268. setResults(res);
  269. }
  270. fetchEvents();
  271. }, [api, org, location, eventView]);
  272. if (!results) {
  273. return <LoadingIndicator />;
  274. }
  275. const browserslistInfo = browsersList[browser.toLowerCase()];
  276. const parsed = parseRes(results);
  277. return (
  278. <div>
  279. <Suspense fallback={<LoadingMask />}>
  280. <LazyContextIcon name={browser.toLowerCase()} size="sm" />
  281. </Suspense>
  282. {' ' + browser}:
  283. <br />
  284. Below Min Version {browserslistInfo.min}: {parsed.unsupportedBelow.toFixed(2)}%
  285. <br />
  286. Supported: {parsed.supported.toFixed(2)}%
  287. <br />
  288. Above Max Version {browserslistInfo.max}: {parsed.unsupportedAbove.toFixed(2)}%
  289. <br />
  290. <br />
  291. </div>
  292. );
  293. }
  294. function parseRes(res: any) {
  295. let total = 0;
  296. let unsupportedBelow = 0;
  297. let unsupportedAbove = 0;
  298. let supported = 0;
  299. res.data.forEach(item => {
  300. total += item['count()'];
  301. const [browser, version] = item.browser.split(' ');
  302. const browserslistInfo = browsersList[browser.toLowerCase()];
  303. const parts = version.split('.');
  304. const intVersion = parseFloat(`${parts[0]}.${parts[1]}`);
  305. if (intVersion < browserslistInfo.min) {
  306. unsupportedBelow += item['count()'];
  307. } else if (intVersion > browserslistInfo.max) {
  308. unsupportedAbove += item['count()'];
  309. } else {
  310. supported += item['count()'];
  311. }
  312. });
  313. return {
  314. // total,
  315. unsupportedBelow: (unsupportedBelow / total) * 100,
  316. unsupportedAbove: (unsupportedAbove / total) * 100,
  317. supported: (supported / total) * 100,
  318. };
  319. }
  320. const BrowserAnalysisWrapper = styled('div')`
  321. display: flex;
  322. justify-content: space-evenly;
  323. padding-top: ${space(2)};
  324. `;
  325. // const _browsersListOutput = ```chrome 111
  326. // chrome 110
  327. // chrome 109
  328. // chrome 108
  329. // chrome 107
  330. // chrome 106
  331. // chrome 105
  332. // chrome 104
  333. // chrome 103
  334. // chrome 102
  335. // edge 111
  336. // edge 110
  337. // firefox 111
  338. // firefox 110
  339. // firefox 109
  340. // firefox 108
  341. // firefox 107
  342. // firefox 106
  343. // firefox 105
  344. // firefox 104
  345. // firefox 103
  346. // firefox 102
  347. // ios_saf 16.4
  348. // ios_saf 16.3
  349. // ios_saf 16.2
  350. // ios_saf 16.1
  351. // ios_saf 16.0
  352. // ios_saf 15.6
  353. // ios_saf 15.5
  354. // ios_saf 15.4
  355. // ios_saf 15.2-15.3
  356. // ios_saf 15.0-15.1
  357. // ios_saf 14.5-14.8
  358. // ios_saf 14.0-14.4
  359. // op_mob 73
  360. // safari 16.4
  361. // safari 16.3
  362. // safari 16.2
  363. // safari 16.1
  364. // safari 16.0
  365. // safari 15.6
  366. // safari 15.5
  367. // safari 15.4
  368. // safari 15.2-15.3
  369. // safari 15.1
  370. // safari 15```;
  371. // const browsersList = {
  372. // chrome: {
  373. // min: 102,
  374. // max: 111,
  375. // },
  376. // edge: {
  377. // min: 110,
  378. // max: 111,
  379. // },
  380. // firefox: {
  381. // min: 102,
  382. // max: 111,
  383. // },
  384. // ios_saf: {
  385. // min: 14,
  386. // max: 16.4,
  387. // },
  388. // op_mob: {
  389. // min: 73,
  390. // max: 73,
  391. // },
  392. // safari: {
  393. // min: 15,
  394. // max: 16.4,
  395. // },
  396. // };
  397. // const RES = {
  398. // data: [
  399. // {
  400. // browser: 'Chrome 115.0.0',
  401. // 'count()': 47468,
  402. // },
  403. // {
  404. // browser: 'Chrome 116.0.0',
  405. // 'count()': 28574,
  406. // },
  407. // {
  408. // browser: 'Chrome 114.0.0',
  409. // 'count()': 6404,
  410. // },
  411. // {
  412. // browser: 'Chrome 88.0.4324',
  413. // 'count()': 1073,
  414. // },
  415. // {
  416. // browser: 'Chrome 113.0.0',
  417. // 'count()': 775,
  418. // },
  419. // {
  420. // browser: 'Chrome 108.0.0',
  421. // 'count()': 653,
  422. // },
  423. // {
  424. // browser: 'Chrome 112.0.0',
  425. // 'count()': 543,
  426. // },
  427. // {
  428. // browser: 'Chrome 112.0.5615',
  429. // 'count()': 388,
  430. // },
  431. // {
  432. // browser: 'Chrome 104.0.0',
  433. // 'count()': 317,
  434. // },
  435. // {
  436. // browser: 'Chrome 107.0.0',
  437. // 'count()': 291,
  438. // },
  439. // {
  440. // browser: 'Chrome 103.0.0',
  441. // 'count()': 239,
  442. // },
  443. // {
  444. // browser: 'Chrome 111.0.0',
  445. // 'count()': 191,
  446. // },
  447. // {
  448. // browser: 'Chrome 79.0.3945',
  449. // 'count()': 168,
  450. // },
  451. // {
  452. // browser: 'Chrome 110.0.0',
  453. // 'count()': 128,
  454. // },
  455. // {
  456. // browser: 'Chrome 105.0.0',
  457. // 'count()': 127,
  458. // },
  459. // {
  460. // browser: 'Chrome 109.0.0',
  461. // 'count()': 112,
  462. // },
  463. // {
  464. // browser: 'Chrome 117.0.0',
  465. // 'count()': 106,
  466. // },
  467. // {
  468. // browser: 'Chrome 80.0.3987',
  469. // 'count()': 82,
  470. // },
  471. // {
  472. // browser: 'Chrome 106.0.5249',
  473. // 'count()': 75,
  474. // },
  475. // {
  476. // browser: 'Chrome 87.0.4280',
  477. // 'count()': 60,
  478. // },
  479. // {
  480. // browser: 'Chrome 106.0.0',
  481. // 'count()': 57,
  482. // },
  483. // {
  484. // browser: 'Chrome 95.0.4638',
  485. // 'count()': 52,
  486. // },
  487. // {
  488. // browser: 'Chrome 118.0.0',
  489. // 'count()': 40,
  490. // },
  491. // {
  492. // browser: 'Chrome 100.0.4896',
  493. // 'count()': 36,
  494. // },
  495. // {
  496. // browser: 'Chrome 101.0.4951',
  497. // 'count()': 35,
  498. // },
  499. // {
  500. // browser: 'Chrome 111.0.5563',
  501. // 'count()': 31,
  502. // },
  503. // {
  504. // browser: 'Chrome 110.0.5481',
  505. // 'count()': 30,
  506. // },
  507. // {
  508. // browser: 'Chrome 102.0.5005',
  509. // 'count()': 27,
  510. // },
  511. // {
  512. // browser: 'Chrome 103.0.5060',
  513. // 'count()': 26,
  514. // },
  515. // {
  516. // browser: 'Chrome 86.0.4240',
  517. // 'count()': 25,
  518. // },
  519. // {
  520. // browser: 'Chrome 102.0.0',
  521. // 'count()': 25,
  522. // },
  523. // {
  524. // browser: 'Chrome 101.0.0',
  525. // 'count()': 23,
  526. // },
  527. // {
  528. // browser: 'Chrome 114.0.5735',
  529. // 'count()': 22,
  530. // },
  531. // {
  532. // browser: 'Chrome 96.0.4664',
  533. // 'count()': 19,
  534. // },
  535. // {
  536. // browser: 'Chrome 92.0.4515',
  537. // 'count()': 15,
  538. // },
  539. // {
  540. // browser: 'Chrome 116.0.5845',
  541. // 'count()': 13,
  542. // },
  543. // {
  544. // browser: 'Chrome 91.0.4472',
  545. // 'count()': 8,
  546. // },
  547. // {
  548. // browser: 'Chrome 108.0.5359',
  549. // 'count()': 7,
  550. // },
  551. // {
  552. // browser: 'Chrome 97.0.4692',
  553. // 'count()': 6,
  554. // },
  555. // {
  556. // browser: 'Chrome 104.0.5112',
  557. // 'count()': 6,
  558. // },
  559. // {
  560. // browser: 'Chrome 99.0.4844',
  561. // 'count()': 6,
  562. // },
  563. // {
  564. // browser: 'Chrome 89.0.4389',
  565. // 'count()': 6,
  566. // },
  567. // {
  568. // browser: 'Chrome 115.0.21929',
  569. // 'count()': 5,
  570. // },
  571. // {
  572. // browser: 'Chrome 115.0.5790',
  573. // 'count()': 5,
  574. // },
  575. // {
  576. // browser: 'Chrome 112.0.24',
  577. // 'count()': 4,
  578. // },
  579. // {
  580. // browser: 'Chrome 90.0.4430',
  581. // 'count()': 4,
  582. // },
  583. // {
  584. // browser: 'Chrome 114.0.24',
  585. // 'count()': 4,
  586. // },
  587. // {
  588. // browser: 'Chrome 113.0.5666',
  589. // 'count()': 4,
  590. // },
  591. // {
  592. // browser: 'Chrome 98.0.4758',
  593. // 'count()': 4,
  594. // },
  595. // {
  596. // browser: 'Chrome 81.0.4044',
  597. // 'count()': 3,
  598. // },
  599. // ],
  600. // };