CINXE.COM

Pure ESM package · GitHub

<!DOCTYPE html> <html lang="en" data-color-mode="auto" data-light-theme="light" data-dark-theme="dark" data-a11y-animated-images="system" data-a11y-link-underlines="true" > <head> <meta charset="utf-8"> <link rel="dns-prefetch" href="https://github.githubassets.com"> <link rel="dns-prefetch" href="https://avatars.githubusercontent.com"> <link rel="dns-prefetch" href="https://github-cloud.s3.amazonaws.com"> <link rel="dns-prefetch" href="https://user-images.githubusercontent.com/"> <link rel="preconnect" href="https://github.githubassets.com" crossorigin> <link rel="preconnect" href="https://avatars.githubusercontent.com"> <link crossorigin="anonymous" media="all" rel="stylesheet" href="https://github.githubassets.com/assets/light-3e154969b9f9.css" /><link crossorigin="anonymous" media="all" rel="stylesheet" href="https://github.githubassets.com/assets/dark-9c5b7a476542.css" /><link data-color-theme="dark_dimmed" crossorigin="anonymous" media="all" rel="stylesheet" data-href="https://github.githubassets.com/assets/dark_dimmed-afda8eb0fb33.css" /><link data-color-theme="dark_high_contrast" crossorigin="anonymous" media="all" rel="stylesheet" data-href="https://github.githubassets.com/assets/dark_high_contrast-2494e44ccdc5.css" /><link data-color-theme="dark_colorblind" crossorigin="anonymous" media="all" rel="stylesheet" data-href="https://github.githubassets.com/assets/dark_colorblind-56fff47acadc.css" /><link data-color-theme="light_colorblind" crossorigin="anonymous" media="all" rel="stylesheet" data-href="https://github.githubassets.com/assets/light_colorblind-71cd4cc132ec.css" /><link data-color-theme="light_high_contrast" crossorigin="anonymous" media="all" rel="stylesheet" data-href="https://github.githubassets.com/assets/light_high_contrast-fd5499848985.css" /><link data-color-theme="light_tritanopia" crossorigin="anonymous" media="all" rel="stylesheet" data-href="https://github.githubassets.com/assets/light_tritanopia-31d17ba3e139.css" /><link data-color-theme="dark_tritanopia" crossorigin="anonymous" media="all" rel="stylesheet" data-href="https://github.githubassets.com/assets/dark_tritanopia-68d6b2c79663.css" /> <link crossorigin="anonymous" media="all" rel="stylesheet" href="https://github.githubassets.com/assets/primer-primitives-4cf0d59ab51a.css" /> <link crossorigin="anonymous" media="all" rel="stylesheet" href="https://github.githubassets.com/assets/primer-af846850481e.css" /> <link crossorigin="anonymous" media="all" rel="stylesheet" href="https://github.githubassets.com/assets/global-e41ff91f8baa.css" /> <link crossorigin="anonymous" media="all" rel="stylesheet" href="https://github.githubassets.com/assets/github-d3b66f11d613.css" /> <script type="application/json" id="client-env">{"locale":"en","featureFlags":["copilot_new_references_ui","copilot_beta_features_opt_in","copilot_chat_static_thread_suggestions","copilot_conversational_ux_history_refs","copilot_implicit_context","copilot_smell_icebreaker_ux","experimentation_azure_variant_endpoint","failbot_handle_non_errors","geojson_azure_maps","ghost_pilot_confidence_truncation_25","ghost_pilot_confidence_truncation_40","hovercard_accessibility","issues_react_new_timeline","issues_react_avatar_refactor","issues_react_remove_placeholders","issues_react_cache_fix_workaround","issues_react_blur_item_picker_on_close","marketing_pages_search_explore_provider","remove_child_patch","sample_network_conn_type","site_metered_billing_update","issues_react_first_time_contribution_banner","jk_navigation_in_list_view","ui_commands_respect_modals","lifecycle_label_name_updates"]}</script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/wp-runtime-118ecaabd77e.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/vendors-node_modules_dompurify_dist_purify_js-b73fdff77a4e.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/vendors-node_modules_oddbird_popover-polyfill_dist_popover_js-aff936e590ed.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/vendors-node_modules_github_arianotify-polyfill_ariaNotify-polyfill_js-node_modules_github_mi-247092-740e4ddd559d.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/ui_packages_failbot_failbot_ts-a46544e9ee5e.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/environment-cd35650c2e9c.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/vendors-node_modules_primer_behaviors_dist_esm_index_mjs-4aa4b0e95669.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/vendors-node_modules_github_selector-observer_dist_index_esm_js-f690fd9ae3d5.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/vendors-node_modules_github_relative-time-element_dist_index_js-6d3967acd51c.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/vendors-node_modules_github_combobox-nav_dist_index_js-node_modules_github_g-emoji-element_di-6ce195-53781cbc550f.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/vendors-node_modules_github_auto-complete-element_dist_index_js-node_modules_github_catalyst_-6afc16-3cdfa69a0406.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/vendors-node_modules_github_text-expander-element_dist_index_js-f5498b8d4e5d.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/vendors-node_modules_github_filter-input-element_dist_index_js-node_modules_github_remote-inp-b5f1d7-492b5042c841.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/vendors-node_modules_github_mini-throttle_dist_index_js-node_modules_stacktrace-parser_dist_s-1f651a-1e3d784c897c.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/vendors-node_modules_github_file-attachment-element_dist_index_js-node_modules_primer_view-co-7671f1-dc6cac136d88.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/github-elements-71486356f507.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/element-registry-e3ab8405ef80.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/vendors-node_modules_braintree_browser-detection_dist_browser-detection_js-node_modules_githu-bb80ec-634de60bacfa.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/vendors-node_modules_lit-html_lit-html_js-ce7225a304c5.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/vendors-node_modules_github_hydro-analytics-client_dist_analytics-client_js-node_modules_gith-f3aee1-e6893db9c19e.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/vendors-node_modules_github_mini-throttle_dist_index_js-node_modules_morphdom_dist_morphdom-e-7c534c-f8a5485c982a.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/vendors-node_modules_github_turbo_dist_turbo_es2017-esm_js-858e043fcf76.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/vendors-node_modules_github_remote-form_dist_index_js-node_modules_delegated-events_dist_inde-893f9f-6cf3320416b8.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/vendors-node_modules_scroll-anchoring_dist_scroll-anchoring_esm_js-node_modules_stacktrace-pa-a71630-6f3c4f0189d8.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/vendors-node_modules_color-convert_index_js-0e07cc183eed.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/vendors-node_modules_github_quote-selection_dist_index_js-node_modules_github_session-resume_-0b5e12-889cec8cf448.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/ui_packages_updatable-content_updatable-content_ts-eae9df0dd562.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/app_assets_modules_github_behaviors_task-list_ts-app_assets_modules_github_sso_ts-ui_packages-900dde-18d1c91a7872.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/app_assets_modules_github_sticky-scroll-into-view_ts-7cbef09a422c.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/app_assets_modules_github_behaviors_ajax-error_ts-app_assets_modules_github_behaviors_include-d0d0a6-0e9fa537dc4f.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/app_assets_modules_github_behaviors_commenting_edit_ts-app_assets_modules_github_behaviors_ht-83c235-c89801ebbe15.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/behaviors-93287f4de493.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/vendors-node_modules_delegated-events_dist_index_js-node_modules_github_catalyst_lib_index_js-f6223d90c7ba.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/notifications-global-3366f6b6298e.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/vendors-node_modules_delegated-events_dist_index_js-node_modules_github_hotkey_dist_index_js-d92e69b3521a.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/vendors-node_modules_github_mini-throttle_dist_index_js-node_modules_github_remote-form_dist_-e6e00d-5e6fcc2d213d.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/ui_packages_form-utils_form-utils_ts-ui_packages_input-navigation-behavior_input-navigation-b-a97423-97468312ad00.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/app_assets_modules_github_diffs_blob-lines_ts-app_assets_modules_github_diffs_linkable-line-n-b8c0ea-77a5219efe36.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/gist-0633f0ca324a.js"></script> <title>Pure ESM package · GitHub</title> <meta name="route-pattern" content="/:user_id/:gist_id(.:format)" data-turbo-transient> <meta name="route-controller" content="gists_gists" data-turbo-transient> <meta name="route-action" content="show" data-turbo-transient> <meta name="current-catalog-service-hash" content="56253a530ab9027b25719525dcbe6007461a3202218f6f5dfce5a601c121cbcb"> <meta name="request-id" content="AABA:108F85:11858D:1499C9:67439DCC" data-pjax-transient="true"/><meta name="html-safe-nonce" content="6d3aa54af218acbf477917ac6a0537619052b202e83ac524edad718475cd7ead" data-pjax-transient="true"/><meta name="visitor-payload" content="eyJyZWZlcnJlciI6IiIsInJlcXVlc3RfaWQiOiJBQUJBOjEwOEY4NToxMTg1OEQ6MTQ5OUM5OjY3NDM5RENDIiwidmlzaXRvcl9pZCI6Ijc3MDMwNjA0MDU4NzAxMDgxMDgiLCJyZWdpb25fZWRnZSI6InNvdXRoZWFzdGFzaWEiLCJyZWdpb25fcmVuZGVyIjoic291dGhlYXN0YXNpYSJ9" data-pjax-transient="true"/><meta name="visitor-hmac" content="dc3e1b1efeee4f2bea8320f376135bf2dbed6480484afdc97a6e9b9d8b6122f2" data-pjax-transient="true"/> <meta name="github-keyboard-shortcuts" content="copilot" data-turbo-transient="true" /> <meta name="selected-link" value="gist_code" data-turbo-transient> <link rel="assets" href="https://github.githubassets.com/"> <meta name="google-site-verification" content="Apib7-x98H0j5cPqHWwSMm6dNU4GmODRoqxLiDzdx9I"> <meta name="octolytics-url" content="https://collector.github.com/github/collect" /> <meta name="analytics-location" content="/&lt;user-name&gt;/&lt;gist-id&gt;" data-turbo-transient="true" /> <meta name="user-login" content=""> <meta name="viewport" content="width=device-width"> <meta name="description" content="Pure ESM package. GitHub Gist: instantly share code, notes, and snippets."> <link rel="search" type="application/opensearchdescription+xml" href="/opensearch-gist.xml" title="Gist"> <link rel="fluid-icon" href="https://gist.github.com/fluidicon.png" title="GitHub"> <meta property="fb:app_id" content="1401488693436528"> <meta name="apple-itunes-app" content="app-id=1477376905, app-argument=https://gist.github.com/sindresorhus/a39789f98801d908bbc7ff3ecc99d99c" /> <meta name="twitter:image" content="https://github.githubassets.com/assets/gist-og-image-54fd7dc0713e.png" /><meta name="twitter:site" content="@github" /><meta name="twitter:card" content="summary_large_image" /><meta name="twitter:title" content="Pure ESM package" /><meta name="twitter:description" content="Pure ESM package. GitHub Gist: instantly share code, notes, and snippets." /> <meta property="og:image" content="https://github.githubassets.com/assets/gist-og-image-54fd7dc0713e.png" /><meta property="og:image:alt" content="Pure ESM package. GitHub Gist: instantly share code, notes, and snippets." /><meta property="og:site_name" content="Gist" /><meta property="og:type" content="article" /><meta property="og:title" content="Pure ESM package" /><meta property="og:url" content="https://gist.github.com/sindresorhus/a39789f98801d908bbc7ff3ecc99d99c" /><meta property="og:description" content="Pure ESM package. GitHub Gist: instantly share code, notes, and snippets." /><meta property="article:author" content="262588213843476" /><meta property="article:publisher" content="262588213843476" /> <meta name="hostname" content="gist.github.com"> <meta name="expected-hostname" content="gist.github.com"> <meta http-equiv="x-pjax-version" content="272935131c2027f789efabd5bf30904ffaea35908a22afd03d8f75128cee7e1b" data-turbo-track="reload"> <meta http-equiv="x-pjax-csp-version" content="ace39c3b6632770952207593607e6e0be0db363435a8b877b1f96abe6430f345" data-turbo-track="reload"> <meta http-equiv="x-pjax-css-version" content="8968ee26e93ec8c6d3c4e91c77fb9d206091689d451ebbcddeca3832587a5b30" data-turbo-track="reload"> <meta http-equiv="x-pjax-js-version" content="c4972ae1cf5d4607c47252349fc1b47a24ff0ea303e5a8fbbe18ec27725a87ee" data-turbo-track="reload"> <meta name="turbo-cache-control" content="no-preview" data-turbo-transient=""> <link href="/sindresorhus.atom" rel="alternate" title="atom" type="application/atom+xml"> <link crossorigin="anonymous" media="all" rel="stylesheet" href="https://github.githubassets.com/assets/gist-622547bb175b.css" /> <meta name="turbo-body-classes" content="logged-out env-production page-responsive"> <meta name="browser-stats-url" content="https://api.github.com/_private/browser/stats"> <meta name="browser-errors-url" content="https://api.github.com/_private/browser/errors"> <link rel="mask-icon" href="https://github.githubassets.com/assets/pinned-octocat-093da3e6fa40.svg" color="#000000"> <link rel="alternate icon" class="js-site-favicon" type="image/png" href="https://github.githubassets.com/favicons/favicon.png"> <link rel="icon" class="js-site-favicon" type="image/svg+xml" href="https://github.githubassets.com/favicons/favicon.svg" data-base-href="https://github.githubassets.com/favicons/favicon"> <meta name="theme-color" content="#1e2327"> <meta name="color-scheme" content="light dark" /> </head> <body class="logged-out env-production page-responsive" style="word-wrap: break-word;"> <div data-turbo-body class="logged-out env-production page-responsive" style="word-wrap: break-word;"> <div class="position-relative header-wrapper js-header-wrapper "> <a href="#start-of-content" data-skip-target-assigned="false" class="px-2 py-4 color-bg-accent-emphasis color-fg-on-emphasis show-on-focus js-skip-to-content">Skip to content</a> <span data-view-component="true" class="progress-pjax-loader Progress position-fixed width-full"> <span style="width: 0%;" data-view-component="true" class="Progress-item progress-pjax-loader-bar left-0 top-0 color-bg-accent-emphasis"></span> </span> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/primer-react-765944243383.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/react-core-cd0a67881543.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/react-lib-7b7b5264f6c1.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/octicons-react-45c3a19dd792.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/vendors-node_modules_emotion_is-prop-valid_dist_emotion-is-prop-valid_esm_js-node_modules_emo-62da9f-54c0c921f04b.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/vendors-node_modules_github_mini-throttle_dist_index_js-node_modules_stacktrace-parser_dist_s-e7dcdd-285fc29e9fa5.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/vendors-node_modules_oddbird_popover-polyfill_dist_popover-fn_js-4896ddd4b7bb.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/ui_packages_ui-commands_ui-commands_ts-d25fac54a6bc.js"></script> <script crossorigin="anonymous" defer="defer" type="application/javascript" src="https://github.githubassets.com/assets/keyboard-shortcuts-dialog-ed30662f9578.js"></script> <link crossorigin="anonymous" media="all" rel="stylesheet" href="https://github.githubassets.com/assets/primer-react.9fa170e9435ed4b922b9.module.css" /> <react-partial partial-name="keyboard-shortcuts-dialog" data-ssr="false" data-attempted-ssr="false" > <script type="application/json" data-target="react-partial.embeddedData">{"props":{"docsUrl":"https://docs.github.com/get-started/accessibility/keyboard-shortcuts"}}</script> <div data-target="react-partial.reactRoot"></div> </react-partial> <div class="Header js-details-container Details flex-wrap flex-md-nowrap p-responsive" role="banner" > <div class="Header-item d-none d-md-flex"> <a class="Header-link" data-hotkey="g d" aria-label="Gist Homepage " href="/"> <svg aria-hidden="true" height="24" viewBox="0 0 24 24" version="1.1" width="24" data-view-component="true" class="octicon octicon-mark-github v-align-middle d-inline-block d-md-none"> <path d="M12.5.75C6.146.75 1 5.896 1 12.25c0 5.089 3.292 9.387 7.863 10.91.575.101.79-.244.79-.546 0-.273-.014-1.178-.014-2.142-2.889.532-3.636-.704-3.866-1.35-.13-.331-.69-1.352-1.18-1.625-.402-.216-.977-.748-.014-.762.906-.014 1.553.834 1.769 1.179 1.035 1.74 2.688 1.25 3.349.948.1-.747.402-1.25.733-1.538-2.559-.287-5.232-1.279-5.232-5.678 0-1.25.445-2.285 1.178-3.09-.115-.288-.517-1.467.115-3.048 0 0 .963-.302 3.163 1.179.92-.259 1.897-.388 2.875-.388.977 0 1.955.13 2.875.388 2.2-1.495 3.162-1.179 3.162-1.179.633 1.581.23 2.76.115 3.048.733.805 1.179 1.825 1.179 3.09 0 4.413-2.688 5.39-5.247 5.678.417.36.776 1.05.776 2.128 0 1.538-.014 2.774-.014 3.162 0 .302.216.662.79.547C20.709 21.637 24 17.324 24 12.25 24 5.896 18.854.75 12.5.75Z"></path> </svg> <svg aria-hidden="true" height="24" viewBox="0 0 68 24" version="1.1" width="68" data-view-component="true" class="octicon octicon-logo-github v-align-middle d-none d-md-inline-block"> <path d="M27.8 17.908h-.03c.013 0 .022.014.035.017l.01-.002-.016-.015Zm.005.017c-.14.001-.49.073-.861.073-1.17 0-1.575-.536-1.575-1.234v-4.652h2.385c.135 0 .24-.12.24-.283V9.302c0-.133-.12-.252-.24-.252H25.37V5.913c0-.119-.075-.193-.21-.193h-3.24c-.136 0-.21.074-.21.193V9.14s-1.636.401-1.741.416a.255.255 0 0 0-.195.253v2.021c0 .164.12.282.255.282h1.665v4.876c0 3.627 2.55 3.998 4.29 3.998.796 0 1.756-.252 1.906-.327.09-.03.135-.134.135-.238v-2.23a.264.264 0 0 0-.219-.265Zm35.549-3.272c0-2.69-1.095-3.047-2.25-2.928-.9.06-1.62.505-1.62.505v5.232s.735.506 1.83.536c1.545.044 2.04-.506 2.04-3.345ZM67 14.415c0 5.099-1.665 6.555-4.576 6.555-2.46 0-3.78-1.233-3.78-1.233s-.06.683-.135.773c-.045.089-.12.118-.21.118h-2.22c-.15 0-.286-.119-.286-.252l.03-16.514a.26.26 0 0 1 .255-.252h3.196a.26.26 0 0 1 .255.252v5.604s1.23-.788 3.03-.788l-.015-.03c1.8 0 4.456.67 4.456 5.767ZM53.918 9.05h-3.15c-.165 0-.255.119-.255.282v8.086s-.826.58-1.95.58c-1.126 0-1.456-.506-1.456-1.62v-7.06a.262.262 0 0 0-.255-.254h-3.21a.262.262 0 0 0-.256.253v7.596c0 3.27 1.846 4.087 4.381 4.087 2.085 0 3.78-1.145 3.78-1.145s.076.58.12.67c.03.074.136.133.24.133h2.011a.243.243 0 0 0 .255-.253l.03-11.103c0-.133-.12-.252-.285-.252Zm-35.556-.015h-3.195c-.135 0-.255.134-.255.297v10.91c0 .297.195.401.45.401h2.88c.3 0 .375-.134.375-.401V9.287a.262.262 0 0 0-.255-.252ZM16.787 4.01c-1.155 0-2.07.907-2.07 2.051 0 1.145.915 2.051 2.07 2.051a2.04 2.04 0 0 0 2.04-2.05 2.04 2.04 0 0 0-2.04-2.052Zm24.74-.372H38.36a.262.262 0 0 0-.255.253v6.08H33.14v-6.08a.262.262 0 0 0-.255-.253h-3.196a.262.262 0 0 0-.255.253v16.514c0 .133.135.252.255.252h3.196a.262.262 0 0 0 .255-.253v-7.06h4.966l-.03 7.06c0 .134.12.253.255.253h3.195a.262.262 0 0 0 .255-.253V3.892a.262.262 0 0 0-.255-.253Zm-28.31 7.313v8.532c0 .06-.015.163-.09.193 0 0-1.875 1.323-4.966 1.323C4.426 21 0 19.84 0 12.2S3.87 2.986 7.651 3c3.27 0 4.59.728 4.8.862.06.075.09.134.09.208l-.63 2.646c0 .134-.134.297-.3.253-.54-.164-1.35-.49-3.255-.49-2.205 0-4.575.623-4.575 5.543s2.25 5.5 3.87 5.5c1.38 0 1.875-.164 1.875-.164V13.94H7.321c-.165 0-.285-.12-.285-.253v-2.735c0-.134.12-.252.285-.252h5.61c.166 0 .286.118.286.252Z"></path> </svg> <svg aria-hidden="true" height="24" viewBox="0 0 38 24" version="1.1" width="38" data-view-component="true" class="octicon octicon-logo-gist v-align-middle d-none d-md-inline-block"> <path d="M7.05 13.095v-1.5h5.28v8.535c-1.17.555-2.925.96-5.385.96C1.665 21.09 0 17.055 0 12.045S1.695 3 6.945 3c2.43 0 3.96.495 4.92.99v1.575c-1.83-.75-3-1.095-4.92-1.095-3.855 0-5.22 3.315-5.22 7.59s1.365 7.575 5.205 7.575c1.335 0 2.97-.105 3.795-.51v-6.03H7.05Zm16.47 1.035h.045c3.33.3 4.125 1.425 4.125 3.345 0 1.815-1.14 3.615-4.71 3.615-1.125 0-2.745-.285-3.495-.585v-1.41c.705.255 1.83.54 3.495.54 2.43 0 3.09-1.035 3.09-2.13 0-1.065-.33-1.815-2.655-2.01-3.39-.3-4.095-1.5-4.095-3.12 0-1.665 1.08-3.465 4.38-3.465 1.095 0 2.34.135 3.375.585v1.41c-.915-.3-1.83-.54-3.405-.54-2.325 0-2.82.855-2.82 2.01 0 1.035.42 1.56 2.67 1.755Zm12.87-4.995v1.275h-3.63v7.305c0 1.425.795 2.01 2.25 2.01.3 0 .63 0 .915-.045v1.335c-.255.045-.75.075-1.035.075-1.965 0-3.75-.9-3.75-3.195v-7.5H28.8v-.72l2.34-.66V5.85l1.62-.465v3.75h3.63ZM16.635 9.09v9.615c0 .81.285 1.05 1.005 1.05v1.335c-1.71 0-2.58-.705-2.58-2.58V9.09h1.575Zm.375-3.495c0 .66-.51 1.17-1.17 1.17a1.14 1.14 0 0 1-1.155-1.17c0-.66.48-1.17 1.155-1.17s1.17.51 1.17 1.17Z"></path> </svg> </a> </div> <div class="Header-item d-md-none"> <button aria-label="Toggle navigation" aria-expanded="false" type="button" data-view-component="true" class="Header-link js-details-target btn-link"> <svg aria-hidden="true" height="24" viewBox="0 0 24 24" version="1.1" width="24" data-view-component="true" class="octicon octicon-three-bars"> <path d="M3.75 5.25a.75.75 0 0 0 0 1.5h16.5a.75.75 0 0 0 0-1.5H3.75Zm0 6a.75.75 0 0 0 0 1.5h16.5a.75.75 0 0 0 0-1.5H3.75Zm0 6a.75.75 0 0 0 0 1.5h16.5a.75.75 0 0 0 0-1.5H3.75Z"></path> </svg> </button> </div> <div class="Header-item Header-item--full js-site-search flex-column flex-md-row width-full flex-order-2 flex-md-order-none mr-0 mr-md-3 mt-3 mt-md-0 Details-content--hidden-not-important d-md-flex"> <div class="header-search flex-self-stretch flex-md-self-auto mr-0 mr-md-3 mb-3 mb-md-0"> <!-- '"` --><!-- </textarea></xmp> --></option></form><form class="position-relative js-quicksearch-form" role="search" aria-label="Site" data-turbo="false" action="/search" accept-charset="UTF-8" method="get"> <div class="header-search-wrapper form-control input-sm js-chromeless-input-container"> <input type="text" class="form-control input-sm js-site-search-focus header-search-input" data-hotkey="s,/" name="q" aria-label="Search" placeholder="Search…" autocorrect="off" autocomplete="off" autocapitalize="off"> </div> </form></div> <nav aria-label="Global" class="d-flex flex-column flex-md-row flex-self-stretch flex-md-self-auto"> <a class="Header-link mr-0 mr-md-3 py-2 py-md-0 border-top border-md-top-0 border-white-fade" data-ga-click="Header, go to all gists, text:all gists" href="/discover">All gists</a> <a class="Header-link mr-0 mr-md-3 py-2 py-md-0 border-top border-md-top-0 border-white-fade" data-ga-click="Header, go to GitHub, text:Back to GitHub" href="https://github.com">Back to GitHub</a> <a class="Header-link d-block d-md-none mr-0 mr-md-3 py-2 py-md-0 border-top border-md-top-0 border-white-fade" data-ga-click="Header, sign in" data-hydro-click="{&quot;event_type&quot;:&quot;authentication.click&quot;,&quot;payload&quot;:{&quot;location_in_page&quot;:&quot;gist header&quot;,&quot;repository_id&quot;:null,&quot;auth_type&quot;:&quot;LOG_IN&quot;,&quot;originating_url&quot;:&quot;https://gist.github.com/sindresorhus/a39789f98801d908bbc7ff3ecc99d99c&quot;,&quot;user_id&quot;:null}}" data-hydro-click-hmac="31bd1883b94f451ecf4562ce82b590bec6e0fda2c61799b5c11767799f1bcd96" href="https://gist.github.com/auth/github?return_to=https%3A%2F%2Fgist.github.com%2Fsindresorhus%2Fa39789f98801d908bbc7ff3ecc99d99c"> Sign in </a> <a class="Header-link d-block d-md-none mr-0 mr-md-3 py-2 py-md-0 border-top border-md-top-0 border-white-fade" data-ga-click="Header, sign up" data-hydro-click="{&quot;event_type&quot;:&quot;authentication.click&quot;,&quot;payload&quot;:{&quot;location_in_page&quot;:&quot;gist header&quot;,&quot;repository_id&quot;:null,&quot;auth_type&quot;:&quot;SIGN_UP&quot;,&quot;originating_url&quot;:&quot;https://gist.github.com/sindresorhus/a39789f98801d908bbc7ff3ecc99d99c&quot;,&quot;user_id&quot;:null}}" data-hydro-click-hmac="c4f1a5eea578edaf590601d8ce87d5c1ece57a71b97128c7042c6bcdc9cfbb67" href="/join?return_to=https%3A%2F%2Fgist.github.com%2Fsindresorhus%2Fa39789f98801d908bbc7ff3ecc99d99c&amp;source=header-gist"> Sign up </a></nav> </div> <div class="Header-item Header-item--full flex-justify-center d-md-none position-relative"> <a class="Header-link" data-hotkey="g d" aria-label="Gist Homepage " href="/"> <svg aria-hidden="true" height="24" viewBox="0 0 24 24" version="1.1" width="24" data-view-component="true" class="octicon octicon-mark-github v-align-middle d-inline-block d-md-none"> <path d="M12.5.75C6.146.75 1 5.896 1 12.25c0 5.089 3.292 9.387 7.863 10.91.575.101.79-.244.79-.546 0-.273-.014-1.178-.014-2.142-2.889.532-3.636-.704-3.866-1.35-.13-.331-.69-1.352-1.18-1.625-.402-.216-.977-.748-.014-.762.906-.014 1.553.834 1.769 1.179 1.035 1.74 2.688 1.25 3.349.948.1-.747.402-1.25.733-1.538-2.559-.287-5.232-1.279-5.232-5.678 0-1.25.445-2.285 1.178-3.09-.115-.288-.517-1.467.115-3.048 0 0 .963-.302 3.163 1.179.92-.259 1.897-.388 2.875-.388.977 0 1.955.13 2.875.388 2.2-1.495 3.162-1.179 3.162-1.179.633 1.581.23 2.76.115 3.048.733.805 1.179 1.825 1.179 3.09 0 4.413-2.688 5.39-5.247 5.678.417.36.776 1.05.776 2.128 0 1.538-.014 2.774-.014 3.162 0 .302.216.662.79.547C20.709 21.637 24 17.324 24 12.25 24 5.896 18.854.75 12.5.75Z"></path> </svg> <svg aria-hidden="true" height="24" viewBox="0 0 68 24" version="1.1" width="68" data-view-component="true" class="octicon octicon-logo-github v-align-middle d-none d-md-inline-block"> <path d="M27.8 17.908h-.03c.013 0 .022.014.035.017l.01-.002-.016-.015Zm.005.017c-.14.001-.49.073-.861.073-1.17 0-1.575-.536-1.575-1.234v-4.652h2.385c.135 0 .24-.12.24-.283V9.302c0-.133-.12-.252-.24-.252H25.37V5.913c0-.119-.075-.193-.21-.193h-3.24c-.136 0-.21.074-.21.193V9.14s-1.636.401-1.741.416a.255.255 0 0 0-.195.253v2.021c0 .164.12.282.255.282h1.665v4.876c0 3.627 2.55 3.998 4.29 3.998.796 0 1.756-.252 1.906-.327.09-.03.135-.134.135-.238v-2.23a.264.264 0 0 0-.219-.265Zm35.549-3.272c0-2.69-1.095-3.047-2.25-2.928-.9.06-1.62.505-1.62.505v5.232s.735.506 1.83.536c1.545.044 2.04-.506 2.04-3.345ZM67 14.415c0 5.099-1.665 6.555-4.576 6.555-2.46 0-3.78-1.233-3.78-1.233s-.06.683-.135.773c-.045.089-.12.118-.21.118h-2.22c-.15 0-.286-.119-.286-.252l.03-16.514a.26.26 0 0 1 .255-.252h3.196a.26.26 0 0 1 .255.252v5.604s1.23-.788 3.03-.788l-.015-.03c1.8 0 4.456.67 4.456 5.767ZM53.918 9.05h-3.15c-.165 0-.255.119-.255.282v8.086s-.826.58-1.95.58c-1.126 0-1.456-.506-1.456-1.62v-7.06a.262.262 0 0 0-.255-.254h-3.21a.262.262 0 0 0-.256.253v7.596c0 3.27 1.846 4.087 4.381 4.087 2.085 0 3.78-1.145 3.78-1.145s.076.58.12.67c.03.074.136.133.24.133h2.011a.243.243 0 0 0 .255-.253l.03-11.103c0-.133-.12-.252-.285-.252Zm-35.556-.015h-3.195c-.135 0-.255.134-.255.297v10.91c0 .297.195.401.45.401h2.88c.3 0 .375-.134.375-.401V9.287a.262.262 0 0 0-.255-.252ZM16.787 4.01c-1.155 0-2.07.907-2.07 2.051 0 1.145.915 2.051 2.07 2.051a2.04 2.04 0 0 0 2.04-2.05 2.04 2.04 0 0 0-2.04-2.052Zm24.74-.372H38.36a.262.262 0 0 0-.255.253v6.08H33.14v-6.08a.262.262 0 0 0-.255-.253h-3.196a.262.262 0 0 0-.255.253v16.514c0 .133.135.252.255.252h3.196a.262.262 0 0 0 .255-.253v-7.06h4.966l-.03 7.06c0 .134.12.253.255.253h3.195a.262.262 0 0 0 .255-.253V3.892a.262.262 0 0 0-.255-.253Zm-28.31 7.313v8.532c0 .06-.015.163-.09.193 0 0-1.875 1.323-4.966 1.323C4.426 21 0 19.84 0 12.2S3.87 2.986 7.651 3c3.27 0 4.59.728 4.8.862.06.075.09.134.09.208l-.63 2.646c0 .134-.134.297-.3.253-.54-.164-1.35-.49-3.255-.49-2.205 0-4.575.623-4.575 5.543s2.25 5.5 3.87 5.5c1.38 0 1.875-.164 1.875-.164V13.94H7.321c-.165 0-.285-.12-.285-.253v-2.735c0-.134.12-.252.285-.252h5.61c.166 0 .286.118.286.252Z"></path> </svg> <svg aria-hidden="true" height="24" viewBox="0 0 38 24" version="1.1" width="38" data-view-component="true" class="octicon octicon-logo-gist v-align-middle d-none d-md-inline-block"> <path d="M7.05 13.095v-1.5h5.28v8.535c-1.17.555-2.925.96-5.385.96C1.665 21.09 0 17.055 0 12.045S1.695 3 6.945 3c2.43 0 3.96.495 4.92.99v1.575c-1.83-.75-3-1.095-4.92-1.095-3.855 0-5.22 3.315-5.22 7.59s1.365 7.575 5.205 7.575c1.335 0 2.97-.105 3.795-.51v-6.03H7.05Zm16.47 1.035h.045c3.33.3 4.125 1.425 4.125 3.345 0 1.815-1.14 3.615-4.71 3.615-1.125 0-2.745-.285-3.495-.585v-1.41c.705.255 1.83.54 3.495.54 2.43 0 3.09-1.035 3.09-2.13 0-1.065-.33-1.815-2.655-2.01-3.39-.3-4.095-1.5-4.095-3.12 0-1.665 1.08-3.465 4.38-3.465 1.095 0 2.34.135 3.375.585v1.41c-.915-.3-1.83-.54-3.405-.54-2.325 0-2.82.855-2.82 2.01 0 1.035.42 1.56 2.67 1.755Zm12.87-4.995v1.275h-3.63v7.305c0 1.425.795 2.01 2.25 2.01.3 0 .63 0 .915-.045v1.335c-.255.045-.75.075-1.035.075-1.965 0-3.75-.9-3.75-3.195v-7.5H28.8v-.72l2.34-.66V5.85l1.62-.465v3.75h3.63ZM16.635 9.09v9.615c0 .81.285 1.05 1.005 1.05v1.335c-1.71 0-2.58-.705-2.58-2.58V9.09h1.575Zm.375-3.495c0 .66-.51 1.17-1.17 1.17a1.14 1.14 0 0 1-1.155-1.17c0-.66.48-1.17 1.155-1.17s1.17.51 1.17 1.17Z"></path> </svg> </a> </div> <div class="Header-item f4 mr-0" role="navigation" aria-label="Sign in or sign up"> <a class="Header-link no-underline mr-3" data-ga-click="Header, sign in" data-hydro-click="{&quot;event_type&quot;:&quot;authentication.click&quot;,&quot;payload&quot;:{&quot;location_in_page&quot;:&quot;gist header&quot;,&quot;repository_id&quot;:null,&quot;auth_type&quot;:&quot;LOG_IN&quot;,&quot;originating_url&quot;:&quot;https://gist.github.com/sindresorhus/a39789f98801d908bbc7ff3ecc99d99c&quot;,&quot;user_id&quot;:null}}" data-hydro-click-hmac="31bd1883b94f451ecf4562ce82b590bec6e0fda2c61799b5c11767799f1bcd96" href="https://gist.github.com/auth/github?return_to=https%3A%2F%2Fgist.github.com%2Fsindresorhus%2Fa39789f98801d908bbc7ff3ecc99d99c"> Sign&nbsp;in </a> <a class="Header-link d-inline-block no-underline border color-border-default rounded px-2 py-1" data-ga-click="Header, sign up" data-hydro-click="{&quot;event_type&quot;:&quot;authentication.click&quot;,&quot;payload&quot;:{&quot;location_in_page&quot;:&quot;gist header&quot;,&quot;repository_id&quot;:null,&quot;auth_type&quot;:&quot;SIGN_UP&quot;,&quot;originating_url&quot;:&quot;https://gist.github.com/sindresorhus/a39789f98801d908bbc7ff3ecc99d99c&quot;,&quot;user_id&quot;:null}}" data-hydro-click-hmac="c4f1a5eea578edaf590601d8ce87d5c1ece57a71b97128c7042c6bcdc9cfbb67" href="/join?return_to=https%3A%2F%2Fgist.github.com%2Fsindresorhus%2Fa39789f98801d908bbc7ff3ecc99d99c&amp;source=header-gist"> Sign&nbsp;up </a> </div> </div> <div hidden="hidden" data-view-component="true" class="js-stale-session-flash stale-session-flash flash flash-warn flash-full"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-alert"> <path d="M6.457 1.047c.659-1.234 2.427-1.234 3.086 0l6.082 11.378A1.75 1.75 0 0 1 14.082 15H1.918a1.75 1.75 0 0 1-1.543-2.575Zm1.763.707a.25.25 0 0 0-.44 0L1.698 13.132a.25.25 0 0 0 .22.368h12.164a.25.25 0 0 0 .22-.368Zm.53 3.996v2.5a.75.75 0 0 1-1.5 0v-2.5a.75.75 0 0 1 1.5 0ZM9 11a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z"></path> </svg> <span class="js-stale-session-flash-signed-in" hidden>You signed in with another tab or window. <a class="Link--inTextBlock" href="">Reload</a> to refresh your session.</span> <span class="js-stale-session-flash-signed-out" hidden>You signed out in another tab or window. <a class="Link--inTextBlock" href="">Reload</a> to refresh your session.</span> <span class="js-stale-session-flash-switched" hidden>You switched accounts on another tab or window. <a class="Link--inTextBlock" href="">Reload</a> to refresh your session.</span> <button id="icon-button-9d6579bf-3fdd-45d2-88db-aa88999fa3fb" aria-labelledby="tooltip-cf9115d0-badc-48f8-99fd-265779a6e383" type="button" data-view-component="true" class="Button Button--iconOnly Button--invisible Button--medium flash-close js-flash-close"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-x Button-visual"> <path d="M3.72 3.72a.75.75 0 0 1 1.06 0L8 6.94l3.22-3.22a.749.749 0 0 1 1.275.326.749.749 0 0 1-.215.734L9.06 8l3.22 3.22a.749.749 0 0 1-.326 1.275.749.749 0 0 1-.734-.215L8 9.06l-3.22 3.22a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042L6.94 8 3.72 4.78a.75.75 0 0 1 0-1.06Z"></path> </svg> </button><tool-tip id="tooltip-cf9115d0-badc-48f8-99fd-265779a6e383" for="icon-button-9d6579bf-3fdd-45d2-88db-aa88999fa3fb" popover="manual" data-direction="s" data-type="label" data-view-component="true" class="sr-only position-absolute">Dismiss alert</tool-tip> </div> </div> <div id="start-of-content" class="show-on-focus"></div> <div id="js-flash-container" class="flash-container" data-turbo-replace> <template class="js-flash-template"> <div class="flash flash-full {{ className }}"> <div > <button autofocus class="flash-close js-flash-close" type="button" aria-label="Dismiss this message"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-x"> <path d="M3.72 3.72a.75.75 0 0 1 1.06 0L8 6.94l3.22-3.22a.749.749 0 0 1 1.275.326.749.749 0 0 1-.215.734L9.06 8l3.22 3.22a.749.749 0 0 1-.326 1.275.749.749 0 0 1-.734-.215L8 9.06l-3.22 3.22a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042L6.94 8 3.72 4.78a.75.75 0 0 1 0-1.06Z"></path> </svg> </button> <div aria-atomic="true" role="alert" class="js-flash-alert"> <div>{{ message }}</div> </div> </div> </div> </template> </div> <div class="application-main " data-commit-hovercards-enabled data-discussion-hovercards-enabled data-issue-and-pr-hovercards-enabled > <div itemscope itemtype="http://schema.org/Code"> <main id="gist-pjax-container"> <div class="gist-detail-intro gist-banner pb-3"> <div class="text-center container-lg px-3"> <p class="lead"> Instantly share code, notes, and snippets. </p> </div> </div> <div class="gisthead pagehead pb-0 pt-3 mb-4"> <div class="px-0"> <div class="mb-3 d-flex px-3 px-md-3 px-lg-5"> <div class="flex-auto min-width-0 width-fit mr-3"> <div class="d-flex"> <div class="d-none d-md-block"> <a class="mr-2 flex-shrink-0" data-hovercard-type="user" data-hovercard-url="/users/sindresorhus/hovercard" data-octo-click="hovercard-link-click" data-octo-dimensions="link_type:self" href="/sindresorhus"><img class="avatar avatar-user" src="https://avatars.githubusercontent.com/u/170270?s=64&amp;v=4" width="32" height="32" alt="@sindresorhus" /></a> </div> <div class="d-flex flex-column width-full"> <div class="d-flex flex-row width-full"> <h1 class="wb-break-word f3 text-normal mb-md-0 mb-1"> <span class="author"><a data-hovercard-type="user" data-hovercard-url="/users/sindresorhus/hovercard" data-octo-click="hovercard-link-click" data-octo-dimensions="link_type:self" href="/sindresorhus">sindresorhus</a></span><!-- --><span class="mx-1 color-fg-muted">/</span><!-- --><strong itemprop="name" class="css-truncate-target mr-1" style="max-width: 410px"><a href="/sindresorhus/a39789f98801d908bbc7ff3ecc99d99c">esm-package.md</a></strong> </h1> </div> <div class="note m-0"> Last active <relative-time tense="past" datetime="2024-11-23T11:11:41Z" data-view-component="true">November 23, 2024 11:11</relative-time> </div> </div> </div> </div> <ul class="d-md-flex pagehead-actions float-none mr-2"> </ul> <div class="d-inline-block d-md-none ml-auto"> <action-menu data-select-variant="none" data-view-component="true" class="flex-self-start ml-auto d-inline-block"> <focus-group direction="vertical" mnemonics retain> <button id="gist_options-button" popovertarget="gist_options-overlay" aria-controls="gist_options-list" aria-haspopup="true" aria-labelledby="tooltip-981a7308-34db-48ce-b74e-35cf317bd65c" type="button" data-view-component="true" class="Button Button--iconOnly Button--secondary Button--small"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-kebab-horizontal Button-visual"> <path d="M8 9a1.5 1.5 0 1 0 0-3 1.5 1.5 0 0 0 0 3ZM1.5 9a1.5 1.5 0 1 0 0-3 1.5 1.5 0 0 0 0 3Zm13 0a1.5 1.5 0 1 0 0-3 1.5 1.5 0 0 0 0 3Z"></path> </svg> </button><tool-tip id="tooltip-981a7308-34db-48ce-b74e-35cf317bd65c" for="gist_options-button" popover="manual" data-direction="s" data-type="label" data-view-component="true" class="sr-only position-absolute">Show Gist options</tool-tip> <anchored-position id="gist_options-overlay" anchor="gist_options-button" align="start" side="outside-bottom" anchor-offset="normal" popover="auto" data-view-component="true"> <div data-view-component="true" class="Overlay Overlay--size-auto"> <div data-view-component="true" class="Overlay-body Overlay-body--paddingNone"> <action-list> <div data-view-component="true"> <ul aria-labelledby="gist_options-button" id="gist_options-list" role="menu" data-view-component="true" class="ActionListWrap--inset ActionListWrap"> <li rel="nofollow" data-hydro-click="{&quot;event_type&quot;:&quot;clone_or_download.click&quot;,&quot;payload&quot;:{&quot;feature_clicked&quot;:&quot;DOWNLOAD_ZIP&quot;,&quot;git_repository_type&quot;:&quot;GIST&quot;,&quot;gist_id&quot;:108176789,&quot;originating_url&quot;:&quot;https://gist.github.com/sindresorhus/a39789f98801d908bbc7ff3ecc99d99c&quot;,&quot;user_id&quot;:null}}" data-hydro-click-hmac="f9ded38b670b6333537c0fbac1a10b296831445629bb6f281b6b937727ecd2a1" data-ga-click="Gist, download zip, location:gist overview" data-targets="action-list.items" data-item-id="download_from_gist_options" role="none" data-view-component="true" class="ActionListItem"> <a tabindex="-1" id="item-356e24cf-9898-4a78-8bf7-272b9f94661a" href="/sindresorhus/a39789f98801d908bbc7ff3ecc99d99c/archive/53696a46351bd10ff2d34493949740b911df04d7.zip" role="menuitem" data-view-component="true" class="ActionListContent"> <span data-view-component="true" class="ActionListItem-label"> Download ZIP </span> </a> </li> </ul> </div></action-list> </div> </div></anchored-position> </focus-group> </action-menu> </div> <ul class="d-md-flex d-none pagehead-actions float-none"> <li> <a id="gist-star-button" href="/login?return_to=https%3A%2F%2Fgist.github.com%2Fsindresorhus%2Fa39789f98801d908bbc7ff3ecc99d99c" rel="nofollow" data-hydro-click="{&quot;event_type&quot;:&quot;authentication.click&quot;,&quot;payload&quot;:{&quot;location_in_page&quot;:&quot;gist star button&quot;,&quot;repository_id&quot;:null,&quot;auth_type&quot;:&quot;LOG_IN&quot;,&quot;originating_url&quot;:&quot;https://gist.github.com/sindresorhus/a39789f98801d908bbc7ff3ecc99d99c&quot;,&quot;user_id&quot;:null}}" data-hydro-click-hmac="e403104275f302603d4bdedf77ac0482d736b97ee948dc21484e050235b3a2c5" aria-label="You must be signed in to star a gist" data-view-component="true" class="btn-with-count Button--secondary Button--small Button"> <span class="Button-content"> <span class="Button-visual Button-leadingVisual"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-star"> <path d="M8 .25a.75.75 0 0 1 .673.418l1.882 3.815 4.21.612a.75.75 0 0 1 .416 1.279l-3.046 2.97.719 4.192a.751.751 0 0 1-1.088.791L8 12.347l-3.766 1.98a.75.75 0 0 1-1.088-.79l.72-4.194L.818 6.374a.75.75 0 0 1 .416-1.28l4.21-.611L7.327.668A.75.75 0 0 1 8 .25Zm0 2.445L6.615 5.5a.75.75 0 0 1-.564.41l-3.097.45 2.24 2.184a.75.75 0 0 1 .216.664l-.528 3.084 2.769-1.456a.75.75 0 0 1 .698 0l2.77 1.456-.53-3.084a.75.75 0 0 1 .216-.664l2.24-2.183-3.096-.45a.75.75 0 0 1-.564-.41L8 2.694Z"></path> </svg> </span> <span class="Button-label">Star</span> <span class="Button-visual Button-trailingVisual"> <span class="sr-only">(<span aria-hidden="true" title="3,018" data-view-component="true" class="Counter">3,018</span>)</span> <span aria-hidden="true" title="3,018" data-view-component="true" class="Counter">3,018</span> </span> </span> </a><tool-tip id="tooltip-cc18e415-c662-468a-a9b8-8962812486f0" for="gist-star-button" popover="manual" data-direction="n" data-type="description" data-view-component="true" class="sr-only position-absolute">You must be signed in to star a gist</tool-tip> </li> <li> <a id="gist-fork-button" href="/login?return_to=https%3A%2F%2Fgist.github.com%2Fsindresorhus%2Fa39789f98801d908bbc7ff3ecc99d99c" rel="nofollow" data-hydro-click="{&quot;event_type&quot;:&quot;authentication.click&quot;,&quot;payload&quot;:{&quot;location_in_page&quot;:&quot;gist fork button&quot;,&quot;repository_id&quot;:null,&quot;auth_type&quot;:&quot;LOG_IN&quot;,&quot;originating_url&quot;:&quot;https://gist.github.com/sindresorhus/a39789f98801d908bbc7ff3ecc99d99c&quot;,&quot;user_id&quot;:null}}" data-hydro-click-hmac="2345540dbc066c1fa90da8d99837f49d0cf4ecb184cbebb6c490f1d5f1767527" aria-label="You must be signed in to fork a gist" data-view-component="true" class="btn-with-count Button--secondary Button--small Button"> <span class="Button-content"> <span class="Button-visual Button-leadingVisual"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-repo-forked"> <path d="M5 5.372v.878c0 .414.336.75.75.75h4.5a.75.75 0 0 0 .75-.75v-.878a2.25 2.25 0 1 1 1.5 0v.878a2.25 2.25 0 0 1-2.25 2.25h-1.5v2.128a2.251 2.251 0 1 1-1.5 0V8.5h-1.5A2.25 2.25 0 0 1 3.5 6.25v-.878a2.25 2.25 0 1 1 1.5 0ZM5 3.25a.75.75 0 1 0-1.5 0 .75.75 0 0 0 1.5 0Zm6.75.75a.75.75 0 1 0 0-1.5.75.75 0 0 0 0 1.5Zm-3 8.75a.75.75 0 1 0-1.5 0 .75.75 0 0 0 1.5 0Z"></path> </svg> </span> <span class="Button-label">Fork</span> <span class="Button-visual Button-trailingVisual"> <span class="sr-only">(<span aria-hidden="true" title="220" data-view-component="true" class="Counter">220</span>)</span> <span aria-hidden="true" title="220" data-view-component="true" class="Counter">220</span> </span> </span> </a><tool-tip id="tooltip-50c2c27f-3a96-4c5f-90da-9b77a7bdfc35" for="gist-fork-button" popover="manual" data-direction="n" data-type="description" data-view-component="true" class="sr-only position-absolute">You must be signed in to fork a gist</tool-tip> </li> </ul> </div> <ul class="d-flex d-md-none px-3 mb-2 pagehead-actions float-none" > <li> <div data-view-component="true" class="flex-items-center d-inline-flex"> <action-menu data-menu-input="gist-share-url-sized-down" data-select-variant="single" data-dynamic-label="" data-view-component="true" class="flex-shrink-0"> <focus-group direction="vertical" mnemonics retain> <button id="action-menu-2f1a93d6-c3d9-4b86-b319-f0e5d3f5aa78-button" popovertarget="action-menu-2f1a93d6-c3d9-4b86-b319-f0e5d3f5aa78-overlay" aria-controls="action-menu-2f1a93d6-c3d9-4b86-b319-f0e5d3f5aa78-list" aria-haspopup="true" type="button" data-view-component="true" class="rounded-right-0 border-right-0 Button--secondary Button--small Button"> <span class="Button-content"> <span class="Button-label">Embed</span> </span> <span class="Button-visual Button-trailingAction"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-triangle-down"> <path d="m4.427 7.427 3.396 3.396a.25.25 0 0 0 .354 0l3.396-3.396A.25.25 0 0 0 11.396 7H4.604a.25.25 0 0 0-.177.427Z"></path> </svg> </span> </button> <anchored-position id="action-menu-2f1a93d6-c3d9-4b86-b319-f0e5d3f5aa78-overlay" anchor="action-menu-2f1a93d6-c3d9-4b86-b319-f0e5d3f5aa78-button" align="start" side="outside-bottom" anchor-offset="normal" popover="auto" data-view-component="true"> <div data-view-component="true" class="Overlay Overlay--size-auto"> <div data-view-component="true" class="Overlay-body Overlay-body--paddingNone"> <action-list> <div data-view-component="true"> <ul aria-labelledby="action-menu-2f1a93d6-c3d9-4b86-b319-f0e5d3f5aa78-button" id="action-menu-2f1a93d6-c3d9-4b86-b319-f0e5d3f5aa78-list" role="menu" data-view-component="true" class="ActionListWrap--inset ActionListWrap"> <li data-targets="action-list.items" role="none" data-view-component="true" class="ActionListItem"> <button value="&lt;script src=&quot;https://gist.github.com/sindresorhus/a39789f98801d908bbc7ff3ecc99d99c.js&quot;&gt;&lt;/script&gt;" tabindex="-1" data-hydro-click="{&quot;event_type&quot;:&quot;clone_or_download.click&quot;,&quot;payload&quot;:{&quot;feature_clicked&quot;:&quot;EMBED&quot;,&quot;git_repository_type&quot;:&quot;GIST&quot;,&quot;gist_id&quot;:108176789,&quot;originating_url&quot;:&quot;https://gist.github.com/sindresorhus/a39789f98801d908bbc7ff3ecc99d99c&quot;,&quot;user_id&quot;:null}}" data-hydro-click-hmac="2c680db921f22a350cd1e5c8ef639c3a8861b74583cc9347d295ef5cf15f387d" id="item-36b4566f-6655-47bd-aa7f-d78429c2271a" type="button" role="menuitemradio" aria-checked="true" data-view-component="true" class="ActionListContent"> <span class="ActionListItem-visual ActionListItem-action--leading"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-check ActionListItem-singleSelectCheckmark"> <path d="M13.78 4.22a.75.75 0 0 1 0 1.06l-7.25 7.25a.75.75 0 0 1-1.06 0L2.22 9.28a.751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018L6 10.94l6.72-6.72a.75.75 0 0 1 1.06 0Z"></path> </svg> </span> <span data-view-component="true" class="ActionListItem-descriptionWrap"> <span data-view-component="true" class="ActionListItem-label"> Embed </span> <span data-view-component="true" class="ActionListItem-description">Embed this gist in your website.</span> </span></button> </li> <li data-targets="action-list.items" role="none" data-view-component="true" class="ActionListItem"> <button value="https://gist.github.com/sindresorhus/a39789f98801d908bbc7ff3ecc99d99c" tabindex="-1" data-hydro-click="{&quot;event_type&quot;:&quot;clone_or_download.click&quot;,&quot;payload&quot;:{&quot;feature_clicked&quot;:&quot;SHARE&quot;,&quot;git_repository_type&quot;:&quot;GIST&quot;,&quot;gist_id&quot;:108176789,&quot;originating_url&quot;:&quot;https://gist.github.com/sindresorhus/a39789f98801d908bbc7ff3ecc99d99c&quot;,&quot;user_id&quot;:null}}" data-hydro-click-hmac="66d1c57d4ac3cc5b984400f7eb3413ffd8f90437bb9a34923755c128a104fbf1" id="item-7c167bfd-abd7-4cbe-bf72-dcb56b91f351" type="button" role="menuitemradio" aria-checked="false" data-view-component="true" class="ActionListContent"> <span class="ActionListItem-visual ActionListItem-action--leading"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-check ActionListItem-singleSelectCheckmark"> <path d="M13.78 4.22a.75.75 0 0 1 0 1.06l-7.25 7.25a.75.75 0 0 1-1.06 0L2.22 9.28a.751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018L6 10.94l6.72-6.72a.75.75 0 0 1 1.06 0Z"></path> </svg> </span> <span data-view-component="true" class="ActionListItem-descriptionWrap"> <span data-view-component="true" class="ActionListItem-label"> Share </span> <span data-view-component="true" class="ActionListItem-description">Copy sharable link for this gist.</span> </span></button> </li> <li data-targets="action-list.items" role="none" data-view-component="true" class="ActionListItem"> <button value="https://gist.github.com/a39789f98801d908bbc7ff3ecc99d99c.git" tabindex="-1" data-hydro-click="{&quot;event_type&quot;:&quot;clone_or_download.click&quot;,&quot;payload&quot;:{&quot;feature_clicked&quot;:&quot;USE_HTTPS&quot;,&quot;git_repository_type&quot;:&quot;GIST&quot;,&quot;gist_id&quot;:108176789,&quot;originating_url&quot;:&quot;https://gist.github.com/sindresorhus/a39789f98801d908bbc7ff3ecc99d99c&quot;,&quot;user_id&quot;:null}}" data-hydro-click-hmac="2bc0f7997e89aad5e2f7fbed840ee12f87e3b29dffcb6839cb99d9b249e669ef" id="item-36b04e9f-44f9-444c-b69b-dd90b96cd23b" type="button" role="menuitemradio" aria-checked="false" data-view-component="true" class="ActionListContent"> <span class="ActionListItem-visual ActionListItem-action--leading"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-check ActionListItem-singleSelectCheckmark"> <path d="M13.78 4.22a.75.75 0 0 1 0 1.06l-7.25 7.25a.75.75 0 0 1-1.06 0L2.22 9.28a.751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018L6 10.94l6.72-6.72a.75.75 0 0 1 1.06 0Z"></path> </svg> </span> <span data-view-component="true" class="ActionListItem-descriptionWrap"> <span data-view-component="true" class="ActionListItem-label"> Clone via HTTPS </span> <span data-view-component="true" class="ActionListItem-description">Clone using the web URL.</span> </span></button> </li> <li role="presentation" aria-hidden="true" data-view-component="true" class="ActionList-sectionDivider"></li> <li target="_blank" rel="noopener noreferrer" data-targets="action-list.items" role="none" data-view-component="true" class="ActionListItem"> <a tabindex="-1" id="item-25bbe548-4dcc-4f56-b907-69de42cb782d" href="https://docs.github.com/articles/which-remote-url-should-i-use" role="menuitemradio" aria-checked="false" data-view-component="true" class="ActionListContent ActionListContent--visual16"> <span class="ActionListItem-visual ActionListItem-action--leading"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-check ActionListItem-singleSelectCheckmark"> <path d="M13.78 4.22a.75.75 0 0 1 0 1.06l-7.25 7.25a.75.75 0 0 1-1.06 0L2.22 9.28a.751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018L6 10.94l6.72-6.72a.75.75 0 0 1 1.06 0Z"></path> </svg> </span> <span class="ActionListItem-visual ActionListItem-visual--leading"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-question"> <path d="M0 8a8 8 0 1 1 16 0A8 8 0 0 1 0 8Zm8-6.5a6.5 6.5 0 1 0 0 13 6.5 6.5 0 0 0 0-13ZM6.92 6.085h.001a.749.749 0 1 1-1.342-.67c.169-.339.436-.701.849-.977C6.845 4.16 7.369 4 8 4a2.756 2.756 0 0 1 1.637.525c.503.377.863.965.863 1.725 0 .448-.115.83-.329 1.15-.205.307-.47.513-.692.662-.109.072-.22.138-.313.195l-.006.004a6.24 6.24 0 0 0-.26.16.952.952 0 0 0-.276.245.75.75 0 0 1-1.248-.832c.184-.264.42-.489.692-.661.103-.067.207-.132.313-.195l.007-.004c.1-.061.182-.11.258-.161a.969.969 0 0 0 .277-.245C8.96 6.514 9 6.427 9 6.25a.612.612 0 0 0-.262-.525A1.27 1.27 0 0 0 8 5.5c-.369 0-.595.09-.74.187a1.01 1.01 0 0 0-.34.398ZM9 11a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z"></path> </svg> </span> <span data-view-component="true" class="ActionListItem-label"> Learn more about clone URLs </span> </a> </li> </ul> </div></action-list> </div> </div></anchored-position> </focus-group> </action-menu> <primer-text-field class="FormControl width-full FormControl--fullWidth"> <label for="gist-share-url-sized-down" class="sr-only FormControl-label"> Clone this repository at &amp;lt;script src=&amp;quot;https://gist.github.com/sindresorhus/a39789f98801d908bbc7ff3ecc99d99c.js&amp;quot;&amp;gt;&amp;lt;/script&amp;gt; </label> <div class="FormControl-input-wrap FormControl-input-wrap--small"> <input id="gist-share-url-sized-down" aria-label="Clone this repository at &amp;lt;script src=&amp;quot;https://gist.github.com/sindresorhus/a39789f98801d908bbc7ff3ecc99d99c.js&amp;quot;&amp;gt;&amp;lt;/script&amp;gt;" value="&lt;script src=&quot;https://gist.github.com/sindresorhus/a39789f98801d908bbc7ff3ecc99d99c.js&quot;&gt;&lt;/script&gt;" readonly="readonly" data-autoselect="true" data-target="primer-text-field.inputElement " aria-describedby="validation-1fc1f341-5792-4258-9de9-654c53e10c90" class="form-control FormControl-monospace FormControl-input FormControl-small rounded-left-0 rounded-right-0 border-right-0" type="text" name="gist-share-url-sized-down" /> </div> <div class="FormControl-inlineValidation" id="validation-1fc1f341-5792-4258-9de9-654c53e10c90" hidden="hidden"> <span class="FormControl-inlineValidation--visual" data-target="primer-text-field.validationSuccessIcon" hidden><svg aria-hidden="true" height="12" viewBox="0 0 12 12" version="1.1" width="12" data-view-component="true" class="octicon octicon-check-circle-fill"> <path d="M6 0a6 6 0 1 1 0 12A6 6 0 0 1 6 0Zm-.705 8.737L9.63 4.403 8.392 3.166 5.295 6.263l-1.7-1.702L2.356 5.8l2.938 2.938Z"></path> </svg></span> <span class=" FormControl-inlineValidation--visual" data-target="primer-text-field.validationErrorIcon"><svg aria-hidden="true" height="12" viewBox="0 0 12 12" version="1.1" width="12" data-view-component="true" class="octicon octicon-alert-fill"> <path d="M4.855.708c.5-.896 1.79-.896 2.29 0l4.675 8.351a1.312 1.312 0 0 1-1.146 1.954H1.33A1.313 1.313 0 0 1 .183 9.058ZM7 7V3H5v4Zm-1 3a1 1 0 1 0 0-2 1 1 0 0 0 0 2Z"></path> </svg></span> <span></span> </div> </primer-text-field> <span data-view-component="true"> <clipboard-copy id="clipboard-button" aria-label="Copy" for="gist-share-url-sized-down" data-hydro-click="{&quot;event_type&quot;:&quot;clone_or_download.click&quot;,&quot;payload&quot;:{&quot;feature_clicked&quot;:&quot;COPY_URL&quot;,&quot;git_repository_type&quot;:&quot;GIST&quot;,&quot;gist_id&quot;:108176789,&quot;originating_url&quot;:&quot;https://gist.github.com/sindresorhus/a39789f98801d908bbc7ff3ecc99d99c&quot;,&quot;user_id&quot;:null}}" data-hydro-click-hmac="3ce51d5f2c6f56fa8921de1ebbae6bab3c039f75dee73875fe4c553c905affb2" type="button" data-view-component="true" class="rounded-left-0 Button--secondary Button--small Button"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-copy"> <path d="M0 6.75C0 5.784.784 5 1.75 5h1.5a.75.75 0 0 1 0 1.5h-1.5a.25.25 0 0 0-.25.25v7.5c0 .138.112.25.25.25h7.5a.25.25 0 0 0 .25-.25v-1.5a.75.75 0 0 1 1.5 0v1.5A1.75 1.75 0 0 1 9.25 16h-7.5A1.75 1.75 0 0 1 0 14.25Z"></path><path d="M5 1.75C5 .784 5.784 0 6.75 0h7.5C15.216 0 16 .784 16 1.75v7.5A1.75 1.75 0 0 1 14.25 11h-7.5A1.75 1.75 0 0 1 5 9.25Zm1.75-.25a.25.25 0 0 0-.25.25v7.5c0 .138.112.25.25.25h7.5a.25.25 0 0 0 .25-.25v-7.5a.25.25 0 0 0-.25-.25Z"></path> </svg> <svg style="display: none;" aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-check color-fg-success"> <path d="M13.78 4.22a.75.75 0 0 1 0 1.06l-7.25 7.25a.75.75 0 0 1-1.06 0L2.22 9.28a.751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018L6 10.94l6.72-6.72a.75.75 0 0 1 1.06 0Z"></path> </svg> </clipboard-copy> <div aria-live="polite" aria-atomic="true" class="sr-only" data-clipboard-copy-feedback></div> </span> </div> </li> <li> <button href="https://desktop.github.com" data-hydro-click="{&quot;event_type&quot;:&quot;clone_or_download.click&quot;,&quot;payload&quot;:{&quot;feature_clicked&quot;:&quot;OPEN_IN_DESKTOP&quot;,&quot;git_repository_type&quot;:&quot;GIST&quot;,&quot;gist_id&quot;:108176789,&quot;originating_url&quot;:&quot;https://gist.github.com/sindresorhus/a39789f98801d908bbc7ff3ecc99d99c&quot;,&quot;user_id&quot;:null}}" data-hydro-click-hmac="e11bf60372d2ee3da815839af5a44467e81dede6873d1ed4dfb132d3312d9e93" data-platforms="windows,mac" id="icon-button-d276daf3-8981-4843-bcb6-af5b0440b4ee" aria-labelledby="tooltip-0a147a01-087a-495f-b3c4-fadd5f7bd938" type="button" data-view-component="true" class="Button Button--iconOnly Button--secondary Button--small js-remove-unless-platform"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-desktop-download Button-visual"> <path d="m4.927 5.427 2.896 2.896a.25.25 0 0 0 .354 0l2.896-2.896A.25.25 0 0 0 10.896 5H8.75V.75a.75.75 0 1 0-1.5 0V5H5.104a.25.25 0 0 0-.177.427Z"></path><path d="M1.573 2.573a.25.25 0 0 0-.073.177v7.5a.25.25 0 0 0 .25.25h12.5a.25.25 0 0 0 .25-.25v-7.5a.25.25 0 0 0-.25-.25h-3a.75.75 0 1 1 0-1.5h3A1.75 1.75 0 0 1 16 2.75v7.5A1.75 1.75 0 0 1 14.25 12h-3.727c.099 1.041.52 1.872 1.292 2.757A.75.75 0 0 1 11.25 16h-6.5a.75.75 0 0 1-.565-1.243c.772-.885 1.192-1.716 1.292-2.757H1.75A1.75 1.75 0 0 1 0 10.25v-7.5A1.75 1.75 0 0 1 1.75 1h3a.75.75 0 0 1 0 1.5h-3a.25.25 0 0 0-.177.073ZM6.982 12a5.72 5.72 0 0 1-.765 2.5h3.566a5.72 5.72 0 0 1-.765-2.5H6.982Z"></path> </svg> </button><tool-tip id="tooltip-0a147a01-087a-495f-b3c4-fadd5f7bd938" for="icon-button-d276daf3-8981-4843-bcb6-af5b0440b4ee" popover="manual" data-direction="s" data-type="label" data-view-component="true" class="sr-only position-absolute">Save sindresorhus/a39789f98801d908bbc7ff3ecc99d99c to your computer and use it in GitHub Desktop.</tool-tip> </li> </ul> <div class="d-flex flex-md-row flex-column px-0 pr-md-3 px-lg-5"> <div class="flex-md-order-1 flex-order-2 flex-auto"> <nav class="UnderlineNav box-shadow-none px-3 px-lg-0" aria-label="Gist" data-pjax="#gist-pjax-container"> <div class="UnderlineNav-body"> <a class="js-selected-navigation-item selected UnderlineNav-item" data-pjax="true" data-hotkey="g c" aria-current="page" data-selected-links="gist_code /sindresorhus/a39789f98801d908bbc7ff3ecc99d99c" href="/sindresorhus/a39789f98801d908bbc7ff3ecc99d99c"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-code UnderlineNav-octicon"> <path d="m11.28 3.22 4.25 4.25a.75.75 0 0 1 0 1.06l-4.25 4.25a.749.749 0 0 1-1.275-.326.749.749 0 0 1 .215-.734L13.94 8l-3.72-3.72a.749.749 0 0 1 .326-1.275.749.749 0 0 1 .734.215Zm-6.56 0a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042L2.06 8l3.72 3.72a.749.749 0 0 1-.326 1.275.749.749 0 0 1-.734-.215L.47 8.53a.75.75 0 0 1 0-1.06Z"></path> </svg> Code </a> <a class="js-selected-navigation-item UnderlineNav-item" data-pjax="true" data-hotkey="g r" data-selected-links="gist_revisions /sindresorhus/a39789f98801d908bbc7ff3ecc99d99c/revisions" href="/sindresorhus/a39789f98801d908bbc7ff3ecc99d99c/revisions"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-git-commit UnderlineNav-octicon"> <path d="M11.93 8.5a4.002 4.002 0 0 1-7.86 0H.75a.75.75 0 0 1 0-1.5h3.32a4.002 4.002 0 0 1 7.86 0h3.32a.75.75 0 0 1 0 1.5Zm-1.43-.75a2.5 2.5 0 1 0-5 0 2.5 2.5 0 0 0 5 0Z"></path> </svg> Revisions <span title="44" data-view-component="true" class="Counter">44</span> </a> <a class="js-selected-navigation-item UnderlineNav-item" data-pjax="true" data-hotkey="g s" data-selected-links="gist_stars /sindresorhus/a39789f98801d908bbc7ff3ecc99d99c/stargazers" href="/sindresorhus/a39789f98801d908bbc7ff3ecc99d99c/stargazers"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-star UnderlineNav-octicon"> <path d="M8 .25a.75.75 0 0 1 .673.418l1.882 3.815 4.21.612a.75.75 0 0 1 .416 1.279l-3.046 2.97.719 4.192a.751.751 0 0 1-1.088.791L8 12.347l-3.766 1.98a.75.75 0 0 1-1.088-.79l.72-4.194L.818 6.374a.75.75 0 0 1 .416-1.28l4.21-.611L7.327.668A.75.75 0 0 1 8 .25Zm0 2.445L6.615 5.5a.75.75 0 0 1-.564.41l-3.097.45 2.24 2.184a.75.75 0 0 1 .216.664l-.528 3.084 2.769-1.456a.75.75 0 0 1 .698 0l2.77 1.456-.53-3.084a.75.75 0 0 1 .216-.664l2.24-2.183-3.096-.45a.75.75 0 0 1-.564-.41L8 2.694Z"></path> </svg> Stars <span title="3,001" data-view-component="true" class="Counter">3,001</span> </a> <a class="js-selected-navigation-item UnderlineNav-item" data-pjax="true" data-hotkey="g f" data-selected-links="gist_forks /sindresorhus/a39789f98801d908bbc7ff3ecc99d99c/forks" href="/sindresorhus/a39789f98801d908bbc7ff3ecc99d99c/forks"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-git-branch UnderlineNav-octicon"> <path d="M9.5 3.25a2.25 2.25 0 1 1 3 2.122V6A2.5 2.5 0 0 1 10 8.5H6a1 1 0 0 0-1 1v1.128a2.251 2.251 0 1 1-1.5 0V5.372a2.25 2.25 0 1 1 1.5 0v1.836A2.493 2.493 0 0 1 6 7h4a1 1 0 0 0 1-1v-.628A2.25 2.25 0 0 1 9.5 3.25Zm-6 0a.75.75 0 1 0 1.5 0 .75.75 0 0 0-1.5 0Zm8.25-.75a.75.75 0 1 0 0 1.5.75.75 0 0 0 0-1.5ZM4.25 12a.75.75 0 1 0 0 1.5.75.75 0 0 0 0-1.5Z"></path> </svg> Forks <span title="220" data-view-component="true" class="Counter">220</span> </a> </div> </nav> </div> <div class="d-md-flex d-none flex-items-center flex-md-order-2 flex-order-1" data-multiple> <div data-view-component="true" class="flex-items-center d-inline-flex"> <action-menu data-menu-input="gist-share-url-original" data-select-variant="single" data-dynamic-label="" data-view-component="true" class="flex-shrink-0"> <focus-group direction="vertical" mnemonics retain> <button id="action-menu-50ab231a-a00b-470a-9d6b-577f0df92106-button" popovertarget="action-menu-50ab231a-a00b-470a-9d6b-577f0df92106-overlay" aria-controls="action-menu-50ab231a-a00b-470a-9d6b-577f0df92106-list" aria-haspopup="true" type="button" data-view-component="true" class="rounded-right-0 border-right-0 Button--secondary Button--small Button"> <span class="Button-content"> <span class="Button-label">Embed</span> </span> <span class="Button-visual Button-trailingAction"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-triangle-down"> <path d="m4.427 7.427 3.396 3.396a.25.25 0 0 0 .354 0l3.396-3.396A.25.25 0 0 0 11.396 7H4.604a.25.25 0 0 0-.177.427Z"></path> </svg> </span> </button> <anchored-position id="action-menu-50ab231a-a00b-470a-9d6b-577f0df92106-overlay" anchor="action-menu-50ab231a-a00b-470a-9d6b-577f0df92106-button" align="start" side="outside-bottom" anchor-offset="normal" popover="auto" data-view-component="true"> <div data-view-component="true" class="Overlay Overlay--size-auto"> <div data-view-component="true" class="Overlay-body Overlay-body--paddingNone"> <action-list> <div data-view-component="true"> <ul aria-labelledby="action-menu-50ab231a-a00b-470a-9d6b-577f0df92106-button" id="action-menu-50ab231a-a00b-470a-9d6b-577f0df92106-list" role="menu" data-view-component="true" class="ActionListWrap--inset ActionListWrap"> <li data-targets="action-list.items" role="none" data-view-component="true" class="ActionListItem"> <button value="&lt;script src=&quot;https://gist.github.com/sindresorhus/a39789f98801d908bbc7ff3ecc99d99c.js&quot;&gt;&lt;/script&gt;" tabindex="-1" data-hydro-click="{&quot;event_type&quot;:&quot;clone_or_download.click&quot;,&quot;payload&quot;:{&quot;feature_clicked&quot;:&quot;EMBED&quot;,&quot;git_repository_type&quot;:&quot;GIST&quot;,&quot;gist_id&quot;:108176789,&quot;originating_url&quot;:&quot;https://gist.github.com/sindresorhus/a39789f98801d908bbc7ff3ecc99d99c&quot;,&quot;user_id&quot;:null}}" data-hydro-click-hmac="2c680db921f22a350cd1e5c8ef639c3a8861b74583cc9347d295ef5cf15f387d" id="item-f4f5e270-3fcb-467d-aa20-503d0768920b" type="button" role="menuitemradio" aria-checked="true" data-view-component="true" class="ActionListContent"> <span class="ActionListItem-visual ActionListItem-action--leading"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-check ActionListItem-singleSelectCheckmark"> <path d="M13.78 4.22a.75.75 0 0 1 0 1.06l-7.25 7.25a.75.75 0 0 1-1.06 0L2.22 9.28a.751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018L6 10.94l6.72-6.72a.75.75 0 0 1 1.06 0Z"></path> </svg> </span> <span data-view-component="true" class="ActionListItem-descriptionWrap"> <span data-view-component="true" class="ActionListItem-label"> Embed </span> <span data-view-component="true" class="ActionListItem-description">Embed this gist in your website.</span> </span></button> </li> <li data-targets="action-list.items" role="none" data-view-component="true" class="ActionListItem"> <button value="https://gist.github.com/sindresorhus/a39789f98801d908bbc7ff3ecc99d99c" tabindex="-1" data-hydro-click="{&quot;event_type&quot;:&quot;clone_or_download.click&quot;,&quot;payload&quot;:{&quot;feature_clicked&quot;:&quot;SHARE&quot;,&quot;git_repository_type&quot;:&quot;GIST&quot;,&quot;gist_id&quot;:108176789,&quot;originating_url&quot;:&quot;https://gist.github.com/sindresorhus/a39789f98801d908bbc7ff3ecc99d99c&quot;,&quot;user_id&quot;:null}}" data-hydro-click-hmac="66d1c57d4ac3cc5b984400f7eb3413ffd8f90437bb9a34923755c128a104fbf1" id="item-48e6a284-2646-48ac-ae3d-c9ad5d2fe837" type="button" role="menuitemradio" aria-checked="false" data-view-component="true" class="ActionListContent"> <span class="ActionListItem-visual ActionListItem-action--leading"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-check ActionListItem-singleSelectCheckmark"> <path d="M13.78 4.22a.75.75 0 0 1 0 1.06l-7.25 7.25a.75.75 0 0 1-1.06 0L2.22 9.28a.751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018L6 10.94l6.72-6.72a.75.75 0 0 1 1.06 0Z"></path> </svg> </span> <span data-view-component="true" class="ActionListItem-descriptionWrap"> <span data-view-component="true" class="ActionListItem-label"> Share </span> <span data-view-component="true" class="ActionListItem-description">Copy sharable link for this gist.</span> </span></button> </li> <li data-targets="action-list.items" role="none" data-view-component="true" class="ActionListItem"> <button value="https://gist.github.com/a39789f98801d908bbc7ff3ecc99d99c.git" tabindex="-1" data-hydro-click="{&quot;event_type&quot;:&quot;clone_or_download.click&quot;,&quot;payload&quot;:{&quot;feature_clicked&quot;:&quot;USE_HTTPS&quot;,&quot;git_repository_type&quot;:&quot;GIST&quot;,&quot;gist_id&quot;:108176789,&quot;originating_url&quot;:&quot;https://gist.github.com/sindresorhus/a39789f98801d908bbc7ff3ecc99d99c&quot;,&quot;user_id&quot;:null}}" data-hydro-click-hmac="2bc0f7997e89aad5e2f7fbed840ee12f87e3b29dffcb6839cb99d9b249e669ef" id="item-a3eb5800-17f2-4d7c-a2e3-b7d8ccdeae0f" type="button" role="menuitemradio" aria-checked="false" data-view-component="true" class="ActionListContent"> <span class="ActionListItem-visual ActionListItem-action--leading"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-check ActionListItem-singleSelectCheckmark"> <path d="M13.78 4.22a.75.75 0 0 1 0 1.06l-7.25 7.25a.75.75 0 0 1-1.06 0L2.22 9.28a.751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018L6 10.94l6.72-6.72a.75.75 0 0 1 1.06 0Z"></path> </svg> </span> <span data-view-component="true" class="ActionListItem-descriptionWrap"> <span data-view-component="true" class="ActionListItem-label"> Clone via HTTPS </span> <span data-view-component="true" class="ActionListItem-description">Clone using the web URL.</span> </span></button> </li> <li role="presentation" aria-hidden="true" data-view-component="true" class="ActionList-sectionDivider"></li> <li target="_blank" rel="noopener noreferrer" data-targets="action-list.items" role="none" data-view-component="true" class="ActionListItem"> <a tabindex="-1" id="item-ec2d7976-4310-4a64-93dc-27beb6f36bc7" href="https://docs.github.com/articles/which-remote-url-should-i-use" role="menuitemradio" aria-checked="false" data-view-component="true" class="ActionListContent ActionListContent--visual16"> <span class="ActionListItem-visual ActionListItem-action--leading"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-check ActionListItem-singleSelectCheckmark"> <path d="M13.78 4.22a.75.75 0 0 1 0 1.06l-7.25 7.25a.75.75 0 0 1-1.06 0L2.22 9.28a.751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018L6 10.94l6.72-6.72a.75.75 0 0 1 1.06 0Z"></path> </svg> </span> <span class="ActionListItem-visual ActionListItem-visual--leading"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-question"> <path d="M0 8a8 8 0 1 1 16 0A8 8 0 0 1 0 8Zm8-6.5a6.5 6.5 0 1 0 0 13 6.5 6.5 0 0 0 0-13ZM6.92 6.085h.001a.749.749 0 1 1-1.342-.67c.169-.339.436-.701.849-.977C6.845 4.16 7.369 4 8 4a2.756 2.756 0 0 1 1.637.525c.503.377.863.965.863 1.725 0 .448-.115.83-.329 1.15-.205.307-.47.513-.692.662-.109.072-.22.138-.313.195l-.006.004a6.24 6.24 0 0 0-.26.16.952.952 0 0 0-.276.245.75.75 0 0 1-1.248-.832c.184-.264.42-.489.692-.661.103-.067.207-.132.313-.195l.007-.004c.1-.061.182-.11.258-.161a.969.969 0 0 0 .277-.245C8.96 6.514 9 6.427 9 6.25a.612.612 0 0 0-.262-.525A1.27 1.27 0 0 0 8 5.5c-.369 0-.595.09-.74.187a1.01 1.01 0 0 0-.34.398ZM9 11a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z"></path> </svg> </span> <span data-view-component="true" class="ActionListItem-label"> Learn more about clone URLs </span> </a> </li> </ul> </div></action-list> </div> </div></anchored-position> </focus-group> </action-menu> <primer-text-field class="FormControl width-full FormControl--fullWidth"> <label for="gist-share-url-original" class="sr-only FormControl-label"> Clone this repository at &amp;lt;script src=&amp;quot;https://gist.github.com/sindresorhus/a39789f98801d908bbc7ff3ecc99d99c.js&amp;quot;&amp;gt;&amp;lt;/script&amp;gt; </label> <div class="FormControl-input-wrap FormControl-input-wrap--small"> <input id="gist-share-url-original" aria-label="Clone this repository at &amp;lt;script src=&amp;quot;https://gist.github.com/sindresorhus/a39789f98801d908bbc7ff3ecc99d99c.js&amp;quot;&amp;gt;&amp;lt;/script&amp;gt;" value="&lt;script src=&quot;https://gist.github.com/sindresorhus/a39789f98801d908bbc7ff3ecc99d99c.js&quot;&gt;&lt;/script&gt;" readonly="readonly" data-autoselect="true" data-target="primer-text-field.inputElement " aria-describedby="validation-dcccd835-a41f-486a-aa20-a79217eb51c4" class="form-control FormControl-monospace FormControl-input FormControl-small rounded-left-0 rounded-right-0 border-right-0" type="text" name="gist-share-url-original" /> </div> <div class="FormControl-inlineValidation" id="validation-dcccd835-a41f-486a-aa20-a79217eb51c4" hidden="hidden"> <span class="FormControl-inlineValidation--visual" data-target="primer-text-field.validationSuccessIcon" hidden><svg aria-hidden="true" height="12" viewBox="0 0 12 12" version="1.1" width="12" data-view-component="true" class="octicon octicon-check-circle-fill"> <path d="M6 0a6 6 0 1 1 0 12A6 6 0 0 1 6 0Zm-.705 8.737L9.63 4.403 8.392 3.166 5.295 6.263l-1.7-1.702L2.356 5.8l2.938 2.938Z"></path> </svg></span> <span class=" FormControl-inlineValidation--visual" data-target="primer-text-field.validationErrorIcon"><svg aria-hidden="true" height="12" viewBox="0 0 12 12" version="1.1" width="12" data-view-component="true" class="octicon octicon-alert-fill"> <path d="M4.855.708c.5-.896 1.79-.896 2.29 0l4.675 8.351a1.312 1.312 0 0 1-1.146 1.954H1.33A1.313 1.313 0 0 1 .183 9.058ZM7 7V3H5v4Zm-1 3a1 1 0 1 0 0-2 1 1 0 0 0 0 2Z"></path> </svg></span> <span></span> </div> </primer-text-field> <span data-view-component="true"> <clipboard-copy id="clipboard-button" aria-label="Copy" for="gist-share-url-original" data-hydro-click="{&quot;event_type&quot;:&quot;clone_or_download.click&quot;,&quot;payload&quot;:{&quot;feature_clicked&quot;:&quot;COPY_URL&quot;,&quot;git_repository_type&quot;:&quot;GIST&quot;,&quot;gist_id&quot;:108176789,&quot;originating_url&quot;:&quot;https://gist.github.com/sindresorhus/a39789f98801d908bbc7ff3ecc99d99c&quot;,&quot;user_id&quot;:null}}" data-hydro-click-hmac="3ce51d5f2c6f56fa8921de1ebbae6bab3c039f75dee73875fe4c553c905affb2" type="button" data-view-component="true" class="rounded-left-0 Button--secondary Button--small Button"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-copy"> <path d="M0 6.75C0 5.784.784 5 1.75 5h1.5a.75.75 0 0 1 0 1.5h-1.5a.25.25 0 0 0-.25.25v7.5c0 .138.112.25.25.25h7.5a.25.25 0 0 0 .25-.25v-1.5a.75.75 0 0 1 1.5 0v1.5A1.75 1.75 0 0 1 9.25 16h-7.5A1.75 1.75 0 0 1 0 14.25Z"></path><path d="M5 1.75C5 .784 5.784 0 6.75 0h7.5C15.216 0 16 .784 16 1.75v7.5A1.75 1.75 0 0 1 14.25 11h-7.5A1.75 1.75 0 0 1 5 9.25Zm1.75-.25a.25.25 0 0 0-.25.25v7.5c0 .138.112.25.25.25h7.5a.25.25 0 0 0 .25-.25v-7.5a.25.25 0 0 0-.25-.25Z"></path> </svg> <svg style="display: none;" aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-check color-fg-success"> <path d="M13.78 4.22a.75.75 0 0 1 0 1.06l-7.25 7.25a.75.75 0 0 1-1.06 0L2.22 9.28a.751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018L6 10.94l6.72-6.72a.75.75 0 0 1 1.06 0Z"></path> </svg> </clipboard-copy> <div aria-live="polite" aria-atomic="true" class="sr-only" data-clipboard-copy-feedback></div> </span> </div> <div class="ml-2"> <button href="https://desktop.github.com" data-hydro-click="{&quot;event_type&quot;:&quot;clone_or_download.click&quot;,&quot;payload&quot;:{&quot;feature_clicked&quot;:&quot;OPEN_IN_DESKTOP&quot;,&quot;git_repository_type&quot;:&quot;GIST&quot;,&quot;gist_id&quot;:108176789,&quot;originating_url&quot;:&quot;https://gist.github.com/sindresorhus/a39789f98801d908bbc7ff3ecc99d99c&quot;,&quot;user_id&quot;:null}}" data-hydro-click-hmac="e11bf60372d2ee3da815839af5a44467e81dede6873d1ed4dfb132d3312d9e93" data-platforms="windows,mac" id="icon-button-7dc235ca-2e0c-4c5a-9165-fbef2e2dd901" aria-labelledby="tooltip-53f313ca-024b-4c5e-ba54-5b39b3557e2a" type="button" data-view-component="true" class="Button Button--iconOnly Button--secondary Button--small js-remove-unless-platform"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-desktop-download Button-visual"> <path d="m4.927 5.427 2.896 2.896a.25.25 0 0 0 .354 0l2.896-2.896A.25.25 0 0 0 10.896 5H8.75V.75a.75.75 0 1 0-1.5 0V5H5.104a.25.25 0 0 0-.177.427Z"></path><path d="M1.573 2.573a.25.25 0 0 0-.073.177v7.5a.25.25 0 0 0 .25.25h12.5a.25.25 0 0 0 .25-.25v-7.5a.25.25 0 0 0-.25-.25h-3a.75.75 0 1 1 0-1.5h3A1.75 1.75 0 0 1 16 2.75v7.5A1.75 1.75 0 0 1 14.25 12h-3.727c.099 1.041.52 1.872 1.292 2.757A.75.75 0 0 1 11.25 16h-6.5a.75.75 0 0 1-.565-1.243c.772-.885 1.192-1.716 1.292-2.757H1.75A1.75 1.75 0 0 1 0 10.25v-7.5A1.75 1.75 0 0 1 1.75 1h3a.75.75 0 0 1 0 1.5h-3a.25.25 0 0 0-.177.073ZM6.982 12a5.72 5.72 0 0 1-.765 2.5h3.566a5.72 5.72 0 0 1-.765-2.5H6.982Z"></path> </svg> </button><tool-tip id="tooltip-53f313ca-024b-4c5e-ba54-5b39b3557e2a" for="icon-button-7dc235ca-2e0c-4c5a-9165-fbef2e2dd901" popover="manual" data-direction="s" data-type="label" data-view-component="true" class="sr-only position-absolute">Save sindresorhus/a39789f98801d908bbc7ff3ecc99d99c to your computer and use it in GitHub Desktop.</tool-tip> </div> <div class="ml-2"> <a class="btn btn-sm" rel="nofollow" data-hydro-click="{&quot;event_type&quot;:&quot;clone_or_download.click&quot;,&quot;payload&quot;:{&quot;feature_clicked&quot;:&quot;DOWNLOAD_ZIP&quot;,&quot;git_repository_type&quot;:&quot;GIST&quot;,&quot;gist_id&quot;:108176789,&quot;originating_url&quot;:&quot;https://gist.github.com/sindresorhus/a39789f98801d908bbc7ff3ecc99d99c&quot;,&quot;user_id&quot;:null}}" data-hydro-click-hmac="f9ded38b670b6333537c0fbac1a10b296831445629bb6f281b6b937727ecd2a1" data-ga-click="Gist, download zip, location:gist overview" href="/sindresorhus/a39789f98801d908bbc7ff3ecc99d99c/archive/53696a46351bd10ff2d34493949740b911df04d7.zip">Download ZIP</a> </div> </div> </div> </div> </div> <div class="container-lg px-3"> <div class="repository-content gist-content" > <div> <div itemprop="about"> Pure ESM package </div> <div class="js-gist-file-update-container js-task-list-container"> <div id="file-esm-package-md" class="file my-2"> <div class="file-header d-flex flex-md-items-center flex-items-start"> <div class="file-actions flex-order-2 pt-0"> <a href="/sindresorhus/a39789f98801d908bbc7ff3ecc99d99c/raw/53696a46351bd10ff2d34493949740b911df04d7/esm-package.md" data-view-component="true" class="Button--secondary Button--small Button"> <span class="Button-content"> <span class="Button-label">Raw</span> </span> </a> </div> <div class="file-info pr-4 d-flex flex-md-items-center flex-items-start flex-order-1 flex-auto"> <span class="mr-1"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-code-square color-fg-muted"> <path d="M0 1.75C0 .784.784 0 1.75 0h12.5C15.216 0 16 .784 16 1.75v12.5A1.75 1.75 0 0 1 14.25 16H1.75A1.75 1.75 0 0 1 0 14.25Zm1.75-.25a.25.25 0 0 0-.25.25v12.5c0 .138.112.25.25.25h12.5a.25.25 0 0 0 .25-.25V1.75a.25.25 0 0 0-.25-.25Zm7.47 3.97a.75.75 0 0 1 1.06 0l2 2a.75.75 0 0 1 0 1.06l-2 2a.749.749 0 0 1-1.275-.326.749.749 0 0 1 .215-.734L10.69 8 9.22 6.53a.75.75 0 0 1 0-1.06ZM6.78 6.53 5.31 8l1.47 1.47a.749.749 0 0 1-.326 1.275.749.749 0 0 1-.734-.215l-2-2a.75.75 0 0 1 0-1.06l2-2a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042Z"></path> </svg> </span> <a class="wb-break-all" href="#file-esm-package-md"> <strong class="user-select-contain gist-blob-name css-truncate-target"> esm-package.md </strong> </a> </div> </div> <div id="file-esm-package-md-readme" class="Box-body readme blob js-code-block-container p-5 p-xl-6 gist-border-0"> <article class="markdown-body entry-content container-lg" itemprop="text"><div class="markdown-heading" dir="auto"><h1 class="heading-element" dir="auto">Pure ESM package</h1><a id="user-content-pure-esm-package" class="anchor" aria-label="Permalink: Pure ESM package" href="#pure-esm-package"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <p dir="auto">The package that linked you here is now pure <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Modules" rel="nofollow">ESM</a>. It cannot be <code>require()</code>'d from CommonJS.</p> <p dir="auto">This means you have the following choices:</p> <ol dir="auto"> <li>Use ESM yourself. <strong>(preferred)</strong><br> Use <code>import foo from 'foo'</code> instead of <code>const foo = require('foo')</code> to import the package. You also need to put <code>"type": "module"</code> in your package.json and more. Follow the below guide.</li> <li>If the package is used in an async context, you could use <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import#dynamic_imports" rel="nofollow"><code>await import(…)</code></a> from CommonJS instead of <code>require(…)</code>.</li> <li>Stay on the existing version of the package until you can move to ESM.</li> <li>Since <a href="https://nodejs.org/en/blog/announcements/v22-release-announce#support-requireing-synchronous-esm-graphs" rel="nofollow">Node.js 22</a>, you may be able to <code>require()</code> ESM modules. However, I <strong>strongly recommend moving to ESM instead</strong>.</li> </ol> <p dir="auto"><strong>You also need to make sure you're on the latest minor version of Node.js. At minimum Node.js 16.</strong></p> <p dir="auto">I would strongly recommend moving to ESM. ESM can still import CommonJS packages, but CommonJS packages cannot import ESM packages synchronously.</p> <p dir="auto"><strong>My repos are not the place to ask ESM/TypeScript/Webpack/Jest/ts-node/CRA support questions.</strong></p> <div class="markdown-heading" dir="auto"><h2 class="heading-element" dir="auto">FAQ</h2><a id="user-content-faq" class="anchor" aria-label="Permalink: FAQ" href="#faq"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <div class="markdown-heading" dir="auto"><h3 class="heading-element" dir="auto">How can I move my CommonJS project to ESM?</h3><a id="user-content-how-can-i-move-my-commonjs-project-to-esm" class="anchor" aria-label="Permalink: How can I move my CommonJS project to ESM?" href="#how-can-i-move-my-commonjs-project-to-esm"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <ul dir="auto"> <li>Add <code>"type": "module"</code> to your package.json.</li> <li>Replace <code>"main": "index.js"</code> with <code>"exports": "./index.js"</code> in your package.json.</li> <li>Update the <code>"engines"</code> field in package.json to Node.js 18: <code>"node": "&gt;=18"</code>.</li> <li>Remove <code>'use strict';</code> from all JavaScript files.</li> <li>Replace all <code>require()</code>/<code>module.export</code> with <code>import</code>/<code>export</code>.</li> <li>Use only full relative file paths for imports: <code>import x from '.';</code> → <code>import x from './index.js';</code>.</li> <li>If you have a TypeScript type definition (for example, <code>index.d.ts</code>), update it to use ESM imports/exports.</li> <li>Use the <a href="https://nodejs.org/api/esm.html#esm_node_imports" rel="nofollow"><code>node:</code> protocol</a> for Node.js built-in imports.</li> </ul> <p dir="auto">Sidenote: If you're looking for guidance on how to add types to your JavaScript package, <a href="https://github.com/sindresorhus/typescript-definition-style-guide">check out my guide</a>.</p> <div class="markdown-heading" dir="auto"><h3 class="heading-element" dir="auto">Can I import ESM packages in my TypeScript project?</h3><a id="user-content-can-i-import-esm-packages-in-my-typescript-project" class="anchor" aria-label="Permalink: Can I import ESM packages in my TypeScript project?" href="#can-i-import-esm-packages-in-my-typescript-project"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <p dir="auto">Yes, but you need to convert your project to output ESM. See below.</p> <div class="markdown-heading" dir="auto"><h3 class="heading-element" dir="auto">How can I make my TypeScript project output ESM?</h3><a id="user-content-how-can-i-make-my-typescript-project-output-esm" class="anchor" aria-label="Permalink: How can I make my TypeScript project output ESM?" href="#how-can-i-make-my-typescript-project-output-esm"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <p dir="auto"><a href="https://www.typescriptlang.org/docs/handbook/esm-node.html" rel="nofollow">Read the official ESM guide.</a></p> <p dir="auto">Quick steps:</p> <ul dir="auto"> <li>Make sure you are using TypeScript 4.7 or later.</li> <li>Add <code>"type": "module"</code> to your package.json.</li> <li>Replace <code>"main": "index.js"</code> with <code>"exports": "./index.js"</code> in your package.json.</li> <li>Update the <code>"engines"</code> field in package.json to Node.js 18: <code>"node": "&gt;=18"</code>.</li> <li>Add <a href="https://www.typescriptlang.org/tsconfig#module" rel="nofollow"><code>"module": "node16", "moduleResolution": "node16"</code></a> to your tsconfig.json. <em>(<a href="https://github.com/sindresorhus/tsconfig/blob/main/tsconfig.json">Example</a>)</em> <ul dir="auto"> <li><strong><code>moduleResolution</code> must be set to <code>node16</code> or <code>nodenext</code>, NOT <code>node</code>!</strong></li> </ul> </li> <li>Use only full relative file paths for imports: <code>import x from '.';</code> → <code>import x from './index.js';</code>.</li> <li>Remove <code>namespace</code> usage and use <code>export</code> instead.</li> <li>Use the <a href="https://nodejs.org/api/esm.html#esm_node_imports" rel="nofollow"><code>node:</code> protocol</a> for Node.js built-in imports.</li> <li><strong>You must use a <code>.js</code> extension in relative imports even though you're importing <code>.ts</code> files.</strong></li> </ul> <p dir="auto">If you use <code>ts-node</code>, follow <a href="https://github.com/TypeStrong/ts-node/issues/1007" data-hovercard-type="issue" data-hovercard-url="/TypeStrong/ts-node/issues/1007/hovercard">this guide</a>. <a href="https://github.com/sindresorhus/got/blob/5f278d74125608b7abe75941cb6a71e21e0fb892/tsconfig.json#L17-L21">Example config.</a></p> <div class="markdown-heading" dir="auto"><h3 class="heading-element" dir="auto">How can I import ESM in Electron?</h3><a id="user-content-how-can-i-import-esm-in-electron" class="anchor" aria-label="Permalink: How can I import ESM in Electron?" href="#how-can-i-import-esm-in-electron"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <p dir="auto">Electron supports ESM as of Electron 28. <a href="https://github.com/electron/electron/blob/main/docs/tutorial/esm.md">Please read this.</a></p> <div class="markdown-heading" dir="auto"><h3 class="heading-element" dir="auto">I'm having problems with ESM and Webpack</h3><a id="user-content-im-having-problems-with-esm-and-webpack" class="anchor" aria-label="Permalink: I'm having problems with ESM and Webpack" href="#im-having-problems-with-esm-and-webpack"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <p dir="auto">The problem is either Webpack or your Webpack configuration. First, ensure you are on the latest version of Webpack. Please don't open an issue on my repo. Try asking on Stack Overflow or <a href="https://github.com/webpack/webpack">open an issue the Webpack repo</a>.</p> <div class="markdown-heading" dir="auto"><h3 class="heading-element" dir="auto">I'm having problems with ESM and Next.js</h3><a id="user-content-im-having-problems-with-esm-and-nextjs" class="anchor" aria-label="Permalink: I'm having problems with ESM and Next.js" href="#im-having-problems-with-esm-and-nextjs"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <p dir="auto">Upgrade to <a href="https://nextjs.org/blog/next-12#es-modules-support-and-url-imports" rel="nofollow">Next.js 12</a> which has full ESM support.</p> <div class="markdown-heading" dir="auto"><h3 class="heading-element" dir="auto">I'm having problems with ESM and Jest</h3><a id="user-content-im-having-problems-with-esm-and-jest" class="anchor" aria-label="Permalink: I'm having problems with ESM and Jest" href="#im-having-problems-with-esm-and-jest"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <p dir="auto"><a href="https://jestjs.io/docs/ecmascript-modules" rel="nofollow">Read this.</a></p> <div class="markdown-heading" dir="auto"><h3 class="heading-element" dir="auto">I'm having problems with ESM and TypeScript</h3><a id="user-content-im-having-problems-with-esm-and-typescript" class="anchor" aria-label="Permalink: I'm having problems with ESM and TypeScript" href="#im-having-problems-with-esm-and-typescript"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <p dir="auto">If you have decided to make your project ESM (<code>"type": "module"</code> in your package.json), make sure you have <a href="https://www.typescriptlang.org/tsconfig#module" rel="nofollow"><code>"module": "node16"</code></a> in your tsconfig.json and that all your import statements to local files use the <code>.js</code> extension, <strong>not</strong> <code>.ts</code> or no extension.</p> <div class="markdown-heading" dir="auto"><h3 class="heading-element" dir="auto">I'm having problems with ESM and <code>ts-node</code></h3><a id="user-content-im-having-problems-with-esm-and-ts-node" class="anchor" aria-label="Permalink: I'm having problems with ESM and ts-node" href="#im-having-problems-with-esm-and-ts-node"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <p dir="auto"><strong>I would recommend <a href="https://github.com/privatenumber/tsx"><code>tsx</code></a> instead.</strong></p> <p dir="auto">Follow <a href="https://github.com/TypeStrong/ts-node/issues/1007" data-hovercard-type="issue" data-hovercard-url="/TypeStrong/ts-node/issues/1007/hovercard">this guide</a> and ensure you are on the latest version of <code>ts-node</code>.</p> <p dir="auto"><a href="https://github.com/sindresorhus/got/blob/5f278d74125608b7abe75941cb6a71e21e0fb892/tsconfig.json#L17-L21">Example config.</a></p> <div class="markdown-heading" dir="auto"><h3 class="heading-element" dir="auto">I'm having problems with ESM and Create React App</h3><a id="user-content-im-having-problems-with-esm-and-create-react-app" class="anchor" aria-label="Permalink: I'm having problems with ESM and Create React App" href="#im-having-problems-with-esm-and-create-react-app"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <p dir="auto">Create React App doesn't yet fully support ESM. I would recommend opening an issue on their repo with the problem you have encountered. One known issue is <a href="https://github.com/facebook/create-react-app/issues/10933" data-hovercard-type="issue" data-hovercard-url="/facebook/create-react-app/issues/10933/hovercard">#10933</a>.</p> <div class="markdown-heading" dir="auto"><h3 class="heading-element" dir="auto">How can I use TypeScript with AVA for an ESM project?</h3><a id="user-content-how-can-i-use-typescript-with-ava-for-an-esm-project" class="anchor" aria-label="Permalink: How can I use TypeScript with AVA for an ESM project?" href="#how-can-i-use-typescript-with-ava-for-an-esm-project"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <p dir="auto">Follow <a href="https://github.com/avajs/ava/blob/main/docs/recipes/typescript.md#for-packages-with-type-module">this guide</a>.</p> <div class="markdown-heading" dir="auto"><h3 class="heading-element" dir="auto">How can I make sure I don't accidentally use CommonJS-specific conventions?</h3><a id="user-content-how-can-i-make-sure-i-dont-accidentally-use-commonjs-specific-conventions" class="anchor" aria-label="Permalink: How can I make sure I don't accidentally use CommonJS-specific conventions?" href="#how-can-i-make-sure-i-dont-accidentally-use-commonjs-specific-conventions"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <p dir="auto">We got you covered with this <a href="https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/prefer-module.md">ESLint rule</a>. You should also use <a href="https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/prefer-node-protocol.md">this rule</a>.</p> <div class="markdown-heading" dir="auto"><h3 class="heading-element" dir="auto">What do I use instead of <code>__dirname</code> and <code>__filename</code>?</h3><a id="user-content-what-do-i-use-instead-of-__dirname-and-__filename" class="anchor" aria-label="Permalink: What do I use instead of __dirname and __filename?" href="#what-do-i-use-instead-of-__dirname-and-__filename"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <p dir="auto"><strong>Node.js 20.11+</strong></p> <p dir="auto">Use <a href="https://nodejs.org/api/esm.html#importmetadirname" rel="nofollow"><code>import.meta.dirname</code></a> and <a href="https://nodejs.org/api/esm.html#importmetafilename" rel="nofollow"><code>import.meta.filename</code></a>.</p> <p dir="auto"><strong>Older Node.js versions</strong></p> <div class="highlight highlight-source-js" dir="auto"><pre><span class="pl-k">import</span> <span class="pl-kos">{</span><span class="pl-s1">fileURLToPath</span><span class="pl-kos">}</span> <span class="pl-k">from</span> <span class="pl-s">'node:url'</span><span class="pl-kos">;</span> <span class="pl-k">import</span> <span class="pl-s1">path</span> <span class="pl-k">from</span> <span class="pl-s">'node:path'</span><span class="pl-kos">;</span> <span class="pl-k">const</span> <span class="pl-s1">__filename</span> <span class="pl-c1">=</span> <span class="pl-en">fileURLToPath</span><span class="pl-kos">(</span><span class="pl-k">import</span><span class="pl-kos">.</span><span class="pl-c1">meta</span><span class="pl-kos">.</span><span class="pl-c1">url</span><span class="pl-kos">)</span><span class="pl-kos">;</span> <span class="pl-k">const</span> <span class="pl-s1">__dirname</span> <span class="pl-c1">=</span> <span class="pl-s1">path</span><span class="pl-kos">.</span><span class="pl-en">dirname</span><span class="pl-kos">(</span><span class="pl-en">fileURLToPath</span><span class="pl-kos">(</span><span class="pl-k">import</span><span class="pl-kos">.</span><span class="pl-c1">meta</span><span class="pl-kos">.</span><span class="pl-c1">url</span><span class="pl-kos">)</span><span class="pl-kos">)</span><span class="pl-kos">;</span></pre></div> <p dir="auto">However, in most cases, this is better:</p> <div class="highlight highlight-source-js" dir="auto"><pre><span class="pl-k">import</span> <span class="pl-kos">{</span><span class="pl-s1">fileURLToPath</span><span class="pl-kos">}</span> <span class="pl-k">from</span> <span class="pl-s">'node:url'</span><span class="pl-kos">;</span> <span class="pl-k">const</span> <span class="pl-s1">foo</span> <span class="pl-c1">=</span> <span class="pl-en">fileURLToPath</span><span class="pl-kos">(</span><span class="pl-k">new</span> <span class="pl-c1">URL</span><span class="pl-kos">(</span><span class="pl-s">'foo.js'</span><span class="pl-kos">,</span> <span class="pl-k">import</span><span class="pl-kos">.</span><span class="pl-c1">meta</span><span class="pl-kos">.</span><span class="pl-c1">url</span><span class="pl-kos">)</span><span class="pl-kos">)</span><span class="pl-kos">;</span></pre></div> <p dir="auto">And many Node.js APIs accept URL directly, so you can just do this:</p> <div class="highlight highlight-source-js" dir="auto"><pre><span class="pl-k">const</span> <span class="pl-s1">foo</span> <span class="pl-c1">=</span> <span class="pl-k">new</span> <span class="pl-c1">URL</span><span class="pl-kos">(</span><span class="pl-s">'foo.js'</span><span class="pl-kos">,</span> <span class="pl-k">import</span><span class="pl-kos">.</span><span class="pl-c1">meta</span><span class="pl-kos">.</span><span class="pl-c1">url</span><span class="pl-kos">)</span><span class="pl-kos">;</span></pre></div> <div class="markdown-heading" dir="auto"><h3 class="heading-element" dir="auto">How can I import a module and bypass the cache for testing?</h3><a id="user-content-how-can-i-import-a-module-and-bypass-the-cache-for-testing" class="anchor" aria-label="Permalink: How can I import a module and bypass the cache for testing?" href="#how-can-i-import-a-module-and-bypass-the-cache-for-testing"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <p dir="auto">There's no good way to do this yet. Not until we get <a href="https://github.com/nodejs/modules/issues/307">ESM loader hooks</a>. For now, this snippet can be useful:</p> <div class="highlight highlight-source-js" dir="auto"><pre><span class="pl-k">const</span> <span class="pl-en">importFresh</span> <span class="pl-c1">=</span> <span class="pl-k">async</span> <span class="pl-s1">modulePath</span> <span class="pl-c1">=&gt;</span> <span class="pl-k">import</span><span class="pl-kos">(</span><span class="pl-s">`<span class="pl-s1"><span class="pl-kos">${</span><span class="pl-s1">modulePath</span><span class="pl-kos">}</span></span>?x=<span class="pl-s1"><span class="pl-kos">${</span><span class="pl-v">Date</span><span class="pl-kos">.</span><span class="pl-en">now</span><span class="pl-kos">(</span><span class="pl-kos">)</span><span class="pl-kos">}</span></span>`</span><span class="pl-kos">)</span><span class="pl-kos">;</span> <span class="pl-k">const</span> <span class="pl-s1">chalk</span> <span class="pl-c1">=</span> <span class="pl-kos">(</span><span class="pl-k">await</span> <span class="pl-en">importFresh</span><span class="pl-kos">(</span><span class="pl-s">'chalk'</span><span class="pl-kos">)</span><span class="pl-kos">)</span><span class="pl-kos">.</span><span class="pl-c1">default</span><span class="pl-kos">;</span></pre></div> <p dir="auto"><em>Note: This will cause memory leaks, so only use it for testing, not in production. Also, it will only reload the imported module, not its dependencies.</em></p> <div class="markdown-heading" dir="auto"><h3 class="heading-element" dir="auto">How can I import JSON?</h3><a id="user-content-how-can-i-import-json" class="anchor" aria-label="Permalink: How can I import JSON?" href="#how-can-i-import-json"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <p dir="auto"><strong>Node.js 18.20+</strong></p> <div class="highlight highlight-source-js" dir="auto"><pre><span class="pl-k">import</span> <span class="pl-s1">packageJson</span> <span class="pl-k">from</span> <span class="pl-s">'./package.json'</span> <span class="pl-s1">with</span> <span class="pl-kos">{</span><span class="pl-s1">type</span>: '<span class="pl-s1">json</span>'<span class="pl-kos">}</span><span class="pl-kos">;</span></pre></div> <p dir="auto"><strong>Older Node.js versions</strong></p> <div class="highlight highlight-source-js" dir="auto"><pre><span class="pl-k">import</span> <span class="pl-s1">fs</span> <span class="pl-k">from</span> <span class="pl-s">'node:fs/promises'</span><span class="pl-kos">;</span> <span class="pl-k">const</span> <span class="pl-s1">packageJson</span> <span class="pl-c1">=</span> <span class="pl-c1">JSON</span><span class="pl-kos">.</span><span class="pl-en">parse</span><span class="pl-kos">(</span><span class="pl-k">await</span> <span class="pl-s1">fs</span><span class="pl-kos">.</span><span class="pl-en">readFile</span><span class="pl-kos">(</span><span class="pl-s">'package.json'</span><span class="pl-kos">)</span><span class="pl-kos">)</span><span class="pl-kos">;</span></pre></div> <div class="markdown-heading" dir="auto"><h3 class="heading-element" dir="auto">When should I use a default export or named exports?</h3><a id="user-content-when-should-i-use-a-default-export-or-named-exports" class="anchor" aria-label="Permalink: When should I use a default export or named exports?" href="#when-should-i-use-a-default-export-or-named-exports"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <p dir="auto">My general rule is that if something exports a single main thing, it should be a default export.</p> <p dir="auto">Keep in mind that you can combine a default export with named exports when it makes sense:</p> <div class="highlight highlight-source-js" dir="auto"><pre><span class="pl-k">import</span> <span class="pl-s1">readJson</span><span class="pl-kos">,</span> <span class="pl-kos">{</span><span class="pl-v">JSONError</span><span class="pl-kos">}</span> <span class="pl-k">from</span> <span class="pl-s">'read-json'</span><span class="pl-kos">;</span></pre></div> <p dir="auto">Here, we had exported the main thing <code>readJson</code>, but we also exported an error as a named export.</p> <div class="markdown-heading" dir="auto"><h4 class="heading-element" dir="auto">Asynchronous and synchronous API</h4><a id="user-content-asynchronous-and-synchronous-api" class="anchor" aria-label="Permalink: Asynchronous and synchronous API" href="#asynchronous-and-synchronous-api"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <p dir="auto">If your package has both an asynchronous and synchronous main API, I would recommend using named exports:</p> <div class="highlight highlight-source-js" dir="auto"><pre><span class="pl-k">import</span> <span class="pl-kos">{</span><span class="pl-s1">readJson</span><span class="pl-kos">,</span> <span class="pl-s1">readJsonSync</span><span class="pl-kos">}</span> <span class="pl-k">from</span> <span class="pl-s">'read-json'</span><span class="pl-kos">;</span></pre></div> <p dir="auto">This makes it clear to the reader that the package exports multiple main APIs. We also follow the Node.js convention of suffixing the synchronous API with <code>Sync</code>.</p> <div class="markdown-heading" dir="auto"><h4 class="heading-element" dir="auto">Readable named exports</h4><a id="user-content-readable-named-exports" class="anchor" aria-label="Permalink: Readable named exports" href="#readable-named-exports"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <p dir="auto">I have noticed a bad pattern of packages using overly generic names for named exports:</p> <div class="highlight highlight-source-js" dir="auto"><pre><span class="pl-k">import</span> <span class="pl-kos">{</span><span class="pl-s1">parse</span><span class="pl-kos">}</span> <span class="pl-k">from</span> <span class="pl-s">'parse-json'</span><span class="pl-kos">;</span></pre></div> <p dir="auto">This forces the consumer to either accept the ambiguous name (which might cause naming conflicts) or rename it:</p> <div class="highlight highlight-source-js" dir="auto"><pre><span class="pl-k">import</span> <span class="pl-kos">{</span><span class="pl-s1">parse</span> <span class="pl-k">as</span> <span class="pl-s1">parseJson</span><span class="pl-kos">}</span> <span class="pl-k">from</span> <span class="pl-s">'parse-json'</span><span class="pl-kos">;</span></pre></div> <p dir="auto">Instead, make it easy for the user:</p> <div class="highlight highlight-source-js" dir="auto"><pre><span class="pl-k">import</span> <span class="pl-kos">{</span><span class="pl-s1">parseJson</span><span class="pl-kos">}</span> <span class="pl-k">from</span> <span class="pl-s">'parse-json'</span><span class="pl-kos">;</span></pre></div> <div class="markdown-heading" dir="auto"><h4 class="heading-element" dir="auto">Examples</h4><a id="user-content-examples" class="anchor" aria-label="Permalink: Examples" href="#examples"><svg class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div> <p dir="auto">With ESM, I now prefer descriptive named exports more often than a namespace default export:</p> <p dir="auto">CommonJS (before):</p> <div class="highlight highlight-source-js" dir="auto"><pre><span class="pl-k">const</span> <span class="pl-s1">isStream</span> <span class="pl-c1">=</span> <span class="pl-en">require</span><span class="pl-kos">(</span><span class="pl-s">'is-stream'</span><span class="pl-kos">)</span><span class="pl-kos">;</span> <span class="pl-s1">isStream</span><span class="pl-kos">.</span><span class="pl-en">writable</span><span class="pl-kos">(</span><span class="pl-s1">…</span><span class="pl-kos">)</span><span class="pl-kos">;</span></pre></div> <p dir="auto">ESM (now):</p> <div class="highlight highlight-source-js" dir="auto"><pre><span class="pl-k">import</span> <span class="pl-kos">{</span><span class="pl-s1">isWritableStream</span><span class="pl-kos">}</span> <span class="pl-k">from</span> <span class="pl-s">'is-stream'</span><span class="pl-kos">;</span> <span class="pl-en">isWritableStream</span><span class="pl-kos">(</span><span class="pl-s1">…</span><span class="pl-kos">)</span><span class="pl-kos">;</span></pre></div> </article> </div> </div> </div> <a name="comments"></a> <div class="js-quote-selection-container" data-quote-markdown=".js-comment-body"> <div class="js-discussion " > <div class="ml-md-6 pl-md-3 ml-0 pl-0"> <div class="TimelineItem d-block js-comment-container"> <div class="avatar-parent-child TimelineItem-avatar d-none d-md-block"> <a class="d-inline-block" data-hovercard-type="user" data-hovercard-url="/users/jaydenseric/hovercard" data-octo-click="hovercard-link-click" data-octo-dimensions="link_type:self" href="/jaydenseric"><img class=" avatar-user" src="https://avatars.githubusercontent.com/u/1754873?s=80&amp;v=4" width="40" height="40" alt="@jaydenseric" /></a> </div> <div id="gistcomment-3850849" class="timeline-comment-group js-minimizable-comment-group js-targetable-element my-0 comment previewable-edit js-task-list-container js-comment timeline-comment timeline-comment--caret ml-n3 js-minimize-container unminimized-comment"> <div class="timeline-comment-header clearfix d-flex" data-morpheus-enabled="false"> <div class="timeline-comment-actions flex-shrink-0 d-flex flex-items-center"> <details class="details-overlay details-reset position-relative d-inline-block"> <summary data-view-component="true" class="timeline-comment-action Link--secondary Button--link Button--medium Button"> <span class="Button-content"> <span class="Button-label"><svg aria-label="Show options" role="img" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-kebab-horizontal"> <path d="M8 9a1.5 1.5 0 1 0 0-3 1.5 1.5 0 0 0 0 3ZM1.5 9a1.5 1.5 0 1 0 0-3 1.5 1.5 0 0 0 0 3Zm13 0a1.5 1.5 0 1 0 0-3 1.5 1.5 0 0 0 0 3Z"></path> </svg></span> </span> </summary> <details-menu class="dropdown-menu dropdown-menu-sw show-more-popover color-fg-default" style="width:185px" src="" preload > <span data-view-component="true"> <clipboard-copy aria-label="Copy link" for="gistcomment-3850849-permalink" role="menuitem" data-view-component="true" class="dropdown-item btn-link"> Copy link </clipboard-copy> <div aria-live="polite" aria-atomic="true" class="sr-only" data-clipboard-copy-feedback></div> </span> </details-menu> </details> </div> <div class="d-none d-sm-flex"> </div> <h3 class="f5 text-normal" style="flex: 1 1 auto"> <div> <strong> <a class="author Link--primary text-bold css-overflow-wrap-anywhere " data-hovercard-type="user" data-hovercard-url="/users/jaydenseric/hovercard" data-octo-click="hovercard-link-click" data-octo-dimensions="link_type:self" href="/jaydenseric">jaydenseric</a> </strong> commented <a href="/sindresorhus/a39789f98801d908bbc7ff3ecc99d99c?permalink_comment_id=3850849#gistcomment-3850849" id="gistcomment-3850849-permalink" class="Link--secondary js-timestamp"><relative-time datetime="2021-08-09T00:51:51Z" class="no-wrap">Aug 9, 2021</relative-time></a> </div> </h3> </div> <div class="edit-comment-hide"> <task-lists disabled sortable> <div class="comment-body markdown-body js-comment-body soft-wrap user-select-contain d-block"> <p dir="auto">Most people don't realize that their imagination of a package that perfectly supports both ESM (for Node.js, <a href="https://deno.land" rel="nofollow">Deno</a>/browsers, and bundlers) and CJS consumers is impossible.</p> <p dir="auto">To avoid the <a href="https://nodejs.org/api/packages.html#packages_dual_package_hazard" rel="nofollow">dual package hazard</a>, all the package's modules <em>must</em> be CJS with a single "default export" (<code class="notranslate">module.exports =</code>), with the exception of index files that are conditionally resolved for ESM consumers (via <a href="https://nodejs.org/api/packages.html#packages_conditional_exports" rel="nofollow">conditional exports</a>) to allow proper named exports. This setup means everyone is running and bundling the same code, regardless if it's imported or required. It's incorrect for a package to publish the same API built twice; once to ESM files, and another time to CJS files. <a class="user-mention notranslate" data-hovercard-type="user" data-hovercard-url="/users/StarpTech/hovercard" data-octo-click="hovercard-link-click" data-octo-dimensions="link_type:self" href="https://github.com/StarpTech">@StarpTech</a> it appears all of the "popular projects that use it successfully" <a href="https://gist.github.com/sindresorhus/a39789f98801d908bbc7ff3ecc99d99c#gistcomment-3850716">you listed</a> are incorrect. If part of your codebase requires from them, and another imports the same thing, duplicated code will run/bundle.</p> <p dir="auto">Here's a correct example:</p> <ul dir="auto"> <li><a href="https://github.com/jaydenseric/graphql-upload/blob/v12.0.0/package.json#L36-L39">https://github.com/jaydenseric/graphql-upload/blob/v12.0.0/package.json#L36-L39</a></li> <li><a href="https://unpkg.com/browse/graphql-upload@12.0.0/" rel="nofollow">https://unpkg.com/browse/graphql-upload@12.0.0/</a></li> </ul> <p dir="auto">The downsides are:</p> <ul dir="auto"> <li>Few people understand why it should be done this way, or how to do it correctly. The concepts are very abstract and package authors have a habit of publishing something that happens to work when they tested it locally for their particular projects, even if it's horribly broken for other kinds of projects. &gt; 80% of published dual ESM/CJS packages cause the <a href="https://nodejs.org/api/packages.html#packages_dual_package_hazard" rel="nofollow">dual package hazard</a> and most of the time the authors (doesn't really matter how famous they are) don't even know what that is.</li> <li>The package author has to write and maintain primarily CJS code. This sucks, because: <ul dir="auto"> <li>You need to make sure all your dev tools support ESM and CJS modules, and can tell what the mode should be for any given file. Which they largely fail at even though tool authors have had years to get it right. Linters, etc. still suck at detecting the module type without elaborate manual config. The TypeScript team have <em>purposefully</em> sabotaged <code class="notranslate">.mjs</code> support! Tooling that needs to parse the source code (e.g. via Babel) to work has to have double the complexity in some cases because the AST for a CJS module (<code class="notranslate">require</code> calls, etc.) is very different to an ESM module (<code class="notranslate">import</code> statements, etc.).</li> <li>You can't use any pure ESM dependencies, because your modules are CJS. This downside alone is a dealbreaker.</li> </ul> </li> <li>The package install size is slightly larger because index modules have to exist as both ESM and CJS files.</li> <li>Your packages are only ESM on the surface. <ul dir="auto"> <li>You can't import any of the code in a browser or <a href="https://deno.land" rel="nofollow">Deno</a>, because the modules are all either CJS, or ESM that imports CJS and these runtimes can't deal with CJS at all.</li> <li>CDN's that allow packages to be imported via URL for browsers or <a href="https://deno.land" rel="nofollow">Deno</a> have to do more fiddly work to convert all the CJS to serve pure ESM. This results in bugs and increases the barrier to entry for people that want to build or host their own.</li> </ul> </li> </ul> <p dir="auto">IMO the JavaScript community has had the priorities wrong for a long time; we need to prioritize technical elegance, simplicity, DX, and documentation for package authors over package consumers. Otherwise we are building our castles on top of a foundation of mud only pigs enjoy working in.</p> <p dir="auto">I remember wishing 5 years ago that Node.js would just deprecate CJS and support ESM from the next major version. If only that had happened when the npm ecosystem was much smaller; literally hundreds, perhaps thousands of hours of my life have been wasted on CJS issues.</p> <p dir="auto">There is never going to be a time that it's painless to switch to pure ESM. The faster we rip the bandaid off and focus on publishing simple, standards-aligned packages for us all to build on, the better. All the people complaining have no idea that <a href="https://deno.land" rel="nofollow">Deno</a> is going to disrupt their entire world soon anyway, a runtime that only works with <em><strong>real</strong></em> ESM; browser-like HTTP/S imports.</p> </div> </task-lists> </div> <!-- '"` --><!-- </textarea></xmp> --></option></form><form class="js-comment-update" data-type="json" data-turbo="false" action="/sindresorhus/a39789f98801d908bbc7ff3ecc99d99c/comments/3850849" accept-charset="UTF-8" method="post"><input type="hidden" name="_method" value="put" autocomplete="off" /><input type="hidden" name="authenticity_token" value="zWrXfMj8ITUPw670S-8K8lMevFyYe1ZDsAnTWOTk72_3hgmm7FlwyMZ2nI977fEFpYEi9PRl5zbi_53ZdDtFTA" autocomplete="off" /> <include-fragment loading="lazy" src="/sindresorhus/a39789f98801d908bbc7ff3ecc99d99c/comments/3850849/edit_form?textarea_id=gistcomment-3850849-body&amp;comment_context=discussion" class="previewable-comment-form js-comment-edit-form-deferred-include-fragment" > <p class="text-center mt-3" data-hide-on-error> <span data-view-component="true"> <svg aria-label="Loading..." style="box-sizing: content-box; color: var(--color-icon-primary);" width="32" height="32" viewBox="0 0 16 16" fill="none" role="img" data-view-component="true" class="anim-rotate"> <circle cx="8" cy="8" r="7" stroke="currentColor" stroke-opacity="0.25" stroke-width="2" vector-effect="non-scaling-stroke" fill="none" /> <path d="M15 8a7.002 7.002 0 00-7-7" stroke="currentColor" stroke-width="2" stroke-linecap="round" vector-effect="non-scaling-stroke" /> </svg></span> </p> <p class="ml-1 mb-2 mt-2" data-show-on-error hidden> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-alert"> <path d="M6.457 1.047c.659-1.234 2.427-1.234 3.086 0l6.082 11.378A1.75 1.75 0 0 1 14.082 15H1.918a1.75 1.75 0 0 1-1.543-2.575Zm1.763.707a.25.25 0 0 0-.44 0L1.698 13.132a.25.25 0 0 0 .22.368h12.164a.25.25 0 0 0 .22-.368Zm.53 3.996v2.5a.75.75 0 0 1-1.5 0v-2.5a.75.75 0 0 1 1.5 0ZM9 11a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z"></path> </svg> Sorry, something went wrong. </p> </include-fragment> </form> </div> </div> <div class="TimelineItem d-block js-comment-container"> <div class="avatar-parent-child TimelineItem-avatar d-none d-md-block"> <a class="d-inline-block" data-hovercard-type="user" data-hovercard-url="/users/jaydenseric/hovercard" data-octo-click="hovercard-link-click" data-octo-dimensions="link_type:self" href="/jaydenseric"><img class=" avatar-user" src="https://avatars.githubusercontent.com/u/1754873?s=80&amp;v=4" width="40" height="40" alt="@jaydenseric" /></a> </div> <div id="gistcomment-3850943" class="timeline-comment-group js-minimizable-comment-group js-targetable-element my-0 comment previewable-edit js-task-list-container js-comment timeline-comment timeline-comment--caret ml-n3 js-minimize-container unminimized-comment"> <div class="timeline-comment-header clearfix d-flex" data-morpheus-enabled="false"> <div class="timeline-comment-actions flex-shrink-0 d-flex flex-items-center"> <details class="details-overlay details-reset position-relative d-inline-block"> <summary data-view-component="true" class="timeline-comment-action Link--secondary Button--link Button--medium Button"> <span class="Button-content"> <span class="Button-label"><svg aria-label="Show options" role="img" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-kebab-horizontal"> <path d="M8 9a1.5 1.5 0 1 0 0-3 1.5 1.5 0 0 0 0 3ZM1.5 9a1.5 1.5 0 1 0 0-3 1.5 1.5 0 0 0 0 3Zm13 0a1.5 1.5 0 1 0 0-3 1.5 1.5 0 0 0 0 3Z"></path> </svg></span> </span> </summary> <details-menu class="dropdown-menu dropdown-menu-sw show-more-popover color-fg-default" style="width:185px" src="" preload > <span data-view-component="true"> <clipboard-copy aria-label="Copy link" for="gistcomment-3850943-permalink" role="menuitem" data-view-component="true" class="dropdown-item btn-link"> Copy link </clipboard-copy> <div aria-live="polite" aria-atomic="true" class="sr-only" data-clipboard-copy-feedback></div> </span> </details-menu> </details> </div> <div class="d-none d-sm-flex"> </div> <h3 class="f5 text-normal" style="flex: 1 1 auto"> <div> <strong> <a class="author Link--primary text-bold css-overflow-wrap-anywhere " data-hovercard-type="user" data-hovercard-url="/users/jaydenseric/hovercard" data-octo-click="hovercard-link-click" data-octo-dimensions="link_type:self" href="/jaydenseric">jaydenseric</a> </strong> commented <a href="/sindresorhus/a39789f98801d908bbc7ff3ecc99d99c?permalink_comment_id=3850943#gistcomment-3850943" id="gistcomment-3850943-permalink" class="Link--secondary js-timestamp"><relative-time datetime="2021-08-09T03:59:54Z" class="no-wrap">Aug 9, 2021</relative-time></a> <span class="js-comment-edit-history"> <span class="d-inline-block color-fg-muted">&#8226;</span> <details class="details-overlay details-reset d-inline-block dropdown hx_dropdown-fullscreen"> <summary class="btn-link no-underline color-fg-muted js-notice"> <div class="position-relative"> <span> edited </span> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-triangle-down v-align-middle"> <path d="m4.427 7.427 3.396 3.396a.25.25 0 0 0 .354 0l3.396-3.396A.25.25 0 0 0 11.396 7H4.604a.25.25 0 0 0-.177.427Z"></path> </svg> </div> </summary> <details-menu class="dropdown-menu dropdown-menu-s width-auto py-0 js-comment-edit-history-menu" style="max-width: 352px; z-index: 99;" src="/user_content_edits/show_edit_history_log/MDExOkdpc3RDb21tZW50YTM5Nzg5Zjk4ODAxZDkwOGJiYzdmZjNlY2M5OWQ5OWM6Mzg1MDk0Mw==" preload > <include-fragment class="my-3" style="min-width: 100px;" aria-label="Loading..."> <span data-view-component="true"> <svg style="box-sizing: content-box; color: var(--color-icon-primary);" width="32" height="32" viewBox="0 0 16 16" fill="none" aria-hidden="true" data-view-component="true" class="mx-auto d-block anim-rotate"> <circle cx="8" cy="8" r="7" stroke="currentColor" stroke-opacity="0.25" stroke-width="2" vector-effect="non-scaling-stroke" fill="none" /> <path d="M15 8a7.002 7.002 0 00-7-7" stroke="currentColor" stroke-width="2" stroke-linecap="round" vector-effect="non-scaling-stroke" /> </svg> <span class="sr-only">Loading</span> </span> </include-fragment> </details-menu> </details> </span> </div> </h3> </div> <div class="edit-comment-hide"> <task-lists disabled sortable> <div class="comment-body markdown-body js-comment-body soft-wrap user-select-contain d-block"> <p dir="auto"><a class="user-mention notranslate" data-hovercard-type="user" data-hovercard-url="/users/dlong500/hovercard" data-octo-click="hovercard-link-click" data-octo-dimensions="link_type:self" href="https://github.com/dlong500">@dlong500</a></p> <blockquote> <p dir="auto">it might be nice if some of the major players who want to push ESM usage forward could help with the tooling in the ecosystem and not just the libraries</p> </blockquote> <p dir="auto">I used to think that we should wait for tools to be ready before republishing everything as pure ESM. But in reality, some of us have spent years attempting to raise issues and PRs fixing native ESM compat for big mainstream packages, to be met with a total lack of urgency or even outright hostility by project owners. We've been pushing Next.js for over 3 years to support native ESM (both in project code, and for dependencies) and there was zero prioritization until <a class="user-mention notranslate" data-hovercard-type="user" data-hovercard-url="/users/sindresorhus/hovercard" data-octo-click="hovercard-link-click" data-octo-dimensions="link_type:self" href="https://github.com/sindresorhus">@sindresorhus</a> lead the wave of publishing pure ESM anyway, forcing them to make some progress in canary releases in just the last few weeks. <a href="https://github.com/vercel/styled-jsx/pull/641" data-hovercard-type="pull_request" data-hovercard-url="/vercel/styled-jsx/pull/641/hovercard">Here is a <code class="notranslate">styled-jsx</code> PR</a> I raised 15 months ago to support Node.js ESM that still hasn't been merged.</p> <p dir="auto">Unfortunately the npm ecosystem doesn't prioritize the right kinds of things. Big budget brands build and market huge, monolithic frameworks with no separations of concerns that lock users in. Normies just install things based off of brand recognition, stars, and install counts so it's a vicious cycle that gets worse and worse.</p> <p dir="auto">If you're willing to look for lightweight, standards-aligned dev tools that have narrow focus (separation of concerns, so no lock-in) you will be pleasantly surprised that you can do almost anything you need with support for native ESM. For example, Jest (currently a <a href="https://packagephobia.com/result?p=jest@27.0.6" rel="nofollow">24.9 MB install size</a>!) for years has been plagued with <a href="https://github.com/facebook/jest/issues/9430" data-hovercard-type="issue" data-hovercard-url="/jestjs/jest/issues/9430/hovercard">native ESM issues</a>, along with all the other 10k+ star alternatives. So long ago I took months off work to publish a set of tiny standalone tools that have worked flawlessly to test all my own packages (that get millions of installs, so not toys):</p> <ul dir="auto"> <li><a href="https://github.com/jaydenseric/coverage-node">https://github.com/jaydenseric/coverage-node</a></li> <li><a href="https://github.com/jaydenseric/test-director">https://github.com/jaydenseric/test-director</a></li> <li><a href="https://github.com/jaydenseric/snapshot-assertion">https://github.com/jaydenseric/snapshot-assertion</a></li> </ul> <p dir="auto">After all these years they've only accumulated 21 stars combined. As they say; "you can lead a horse to water, but you can't make it drink". I even experienced cyber-bullying (since deleted and apologized for) for creating <a href="https://github.com/jaydenseric/coverage-node"><code class="notranslate">coverage-node</code></a>, because it threatened the status quo for packages overlapping in purpose.</p> <p dir="auto">It's a bit like the Internet Explorer situation. If we support it because lazy orgs still use it, then said orgs won't update from it. Ad infinitum.</p> </div> </task-lists> </div> <!-- '"` --><!-- </textarea></xmp> --></option></form><form class="js-comment-update" data-type="json" data-turbo="false" action="/sindresorhus/a39789f98801d908bbc7ff3ecc99d99c/comments/3850943" accept-charset="UTF-8" method="post"><input type="hidden" name="_method" value="put" autocomplete="off" /><input type="hidden" name="authenticity_token" value="d9O7grg6_IaOyOB11IOibbfVUSWCyaZ9_V0tJQ7j3uzugE49whxXEjTHYEDkqsQdnq9kT04xP5rfEp6DKIYYkw" autocomplete="off" /> <include-fragment loading="lazy" src="/sindresorhus/a39789f98801d908bbc7ff3ecc99d99c/comments/3850943/edit_form?textarea_id=gistcomment-3850943-body&amp;comment_context=discussion" class="previewable-comment-form js-comment-edit-form-deferred-include-fragment" > <p class="text-center mt-3" data-hide-on-error> <span data-view-component="true"> <svg aria-label="Loading..." style="box-sizing: content-box; color: var(--color-icon-primary);" width="32" height="32" viewBox="0 0 16 16" fill="none" role="img" data-view-component="true" class="anim-rotate"> <circle cx="8" cy="8" r="7" stroke="currentColor" stroke-opacity="0.25" stroke-width="2" vector-effect="non-scaling-stroke" fill="none" /> <path d="M15 8a7.002 7.002 0 00-7-7" stroke="currentColor" stroke-width="2" stroke-linecap="round" vector-effect="non-scaling-stroke" /> </svg></span> </p> <p class="ml-1 mb-2 mt-2" data-show-on-error hidden> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-alert"> <path d="M6.457 1.047c.659-1.234 2.427-1.234 3.086 0l6.082 11.378A1.75 1.75 0 0 1 14.082 15H1.918a1.75 1.75 0 0 1-1.543-2.575Zm1.763.707a.25.25 0 0 0-.44 0L1.698 13.132a.25.25 0 0 0 .22.368h12.164a.25.25 0 0 0 .22-.368Zm.53 3.996v2.5a.75.75 0 0 1-1.5 0v-2.5a.75.75 0 0 1 1.5 0ZM9 11a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z"></path> </svg> Sorry, something went wrong. </p> </include-fragment> </form> </div> </div> <div class="TimelineItem d-block js-comment-container"> <div class="avatar-parent-child TimelineItem-avatar d-none d-md-block"> <a class="d-inline-block" data-hovercard-type="user" data-hovercard-url="/users/jaydenseric/hovercard" data-octo-click="hovercard-link-click" data-octo-dimensions="link_type:self" href="/jaydenseric"><img class=" avatar-user" src="https://avatars.githubusercontent.com/u/1754873?s=80&amp;v=4" width="40" height="40" alt="@jaydenseric" /></a> </div> <div id="gistcomment-3992076" class="timeline-comment-group js-minimizable-comment-group js-targetable-element my-0 comment previewable-edit js-task-list-container js-comment timeline-comment timeline-comment--caret ml-n3 js-minimize-container unminimized-comment"> <div class="timeline-comment-header clearfix d-flex" data-morpheus-enabled="false"> <div class="timeline-comment-actions flex-shrink-0 d-flex flex-items-center"> <details class="details-overlay details-reset position-relative d-inline-block"> <summary data-view-component="true" class="timeline-comment-action Link--secondary Button--link Button--medium Button"> <span class="Button-content"> <span class="Button-label"><svg aria-label="Show options" role="img" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-kebab-horizontal"> <path d="M8 9a1.5 1.5 0 1 0 0-3 1.5 1.5 0 0 0 0 3ZM1.5 9a1.5 1.5 0 1 0 0-3 1.5 1.5 0 0 0 0 3Zm13 0a1.5 1.5 0 1 0 0-3 1.5 1.5 0 0 0 0 3Z"></path> </svg></span> </span> </summary> <details-menu class="dropdown-menu dropdown-menu-sw show-more-popover color-fg-default" style="width:185px" src="" preload > <span data-view-component="true"> <clipboard-copy aria-label="Copy link" for="gistcomment-3992076-permalink" role="menuitem" data-view-component="true" class="dropdown-item btn-link"> Copy link </clipboard-copy> <div aria-live="polite" aria-atomic="true" class="sr-only" data-clipboard-copy-feedback></div> </span> </details-menu> </details> </div> <div class="d-none d-sm-flex"> </div> <h3 class="f5 text-normal" style="flex: 1 1 auto"> <div> <strong> <a class="author Link--primary text-bold css-overflow-wrap-anywhere " data-hovercard-type="user" data-hovercard-url="/users/jaydenseric/hovercard" data-octo-click="hovercard-link-click" data-octo-dimensions="link_type:self" href="/jaydenseric">jaydenseric</a> </strong> commented <a href="/sindresorhus/a39789f98801d908bbc7ff3ecc99d99c?permalink_comment_id=3992076#gistcomment-3992076" id="gistcomment-3992076-permalink" class="Link--secondary js-timestamp"><relative-time datetime="2021-12-12T01:49:38Z" class="no-wrap">Dec 12, 2021</relative-time></a> <span class="js-comment-edit-history"> <span class="d-inline-block color-fg-muted">&#8226;</span> <details class="details-overlay details-reset d-inline-block dropdown hx_dropdown-fullscreen"> <summary class="btn-link no-underline color-fg-muted js-notice"> <div class="position-relative"> <span> edited </span> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-triangle-down v-align-middle"> <path d="m4.427 7.427 3.396 3.396a.25.25 0 0 0 .354 0l3.396-3.396A.25.25 0 0 0 11.396 7H4.604a.25.25 0 0 0-.177.427Z"></path> </svg> </div> </summary> <details-menu class="dropdown-menu dropdown-menu-s width-auto py-0 js-comment-edit-history-menu" style="max-width: 352px; z-index: 99;" src="/user_content_edits/show_edit_history_log/GC_lADOABrG-doAIGEzOTc4OWY5ODgwMWQ5MDhiYmM3ZmYzZWNjOTlkOTljzgA86gw" preload > <include-fragment class="my-3" style="min-width: 100px;" aria-label="Loading..."> <span data-view-component="true"> <svg style="box-sizing: content-box; color: var(--color-icon-primary);" width="32" height="32" viewBox="0 0 16 16" fill="none" aria-hidden="true" data-view-component="true" class="mx-auto d-block anim-rotate"> <circle cx="8" cy="8" r="7" stroke="currentColor" stroke-opacity="0.25" stroke-width="2" vector-effect="non-scaling-stroke" fill="none" /> <path d="M15 8a7.002 7.002 0 00-7-7" stroke="currentColor" stroke-width="2" stroke-linecap="round" vector-effect="non-scaling-stroke" /> </svg> <span class="sr-only">Loading</span> </span> </include-fragment> </details-menu> </details> </span> </div> </h3> </div> <div class="edit-comment-hide"> <task-lists disabled sortable> <div class="comment-body markdown-body js-comment-body soft-wrap user-select-contain d-block"> <p dir="auto">Betting on CJS is like betting on Adobe Flash a few years ago. At the time people couldn't imagine Flash would be abandoned by every website and wouldn't even be installable in browsers. Flash devs made a lot of salty arguments, some similar to comments made here. In the end, proper web standards that are supported by browser runtimes win every time.</p> <blockquote> <p dir="auto">It is not deprecated in any sense</p> </blockquote> <p dir="auto">It most certainly is, in many common senses. Sure, the Node.js team have not declared the format deprecated by the runtime (<em>yet</em>). Deprecating the format isn't solely in the hands of the Node.js team though, individual package authors can also deprecate support for CJS consumers one a per-package basis when they republish as pure ESM. CJS "deprecation" is also decided by the entire JS community, which includes runtimes other than Node.js. CJS is garbage in the eyes of the Deno community, and even if they get Node.js CJS compatibility layers working it will still be considered a second-class format to standard ESM.</p> <blockquote> <p dir="auto">It's fine - and helpful! - to make dual packages.</p> </blockquote> <p dir="auto">With the huge caveat <a href="https://gist.github.com/sindresorhus/a39789f98801d908bbc7ff3ecc99d99c#gistcomment-3850849">discussed here</a>; the "dual" packages must avoid the <a href="https://nodejs.org/api/packages.html#dual-package-hazard" rel="nofollow">dual package hazard</a>. Barely any of the "dual" packages today successfully do so. Most people have a naive impression that dual packages ship all the code as both ESM and CJS, which is probably worse all things considered that just picking pure CJS or ESM.</p> <blockquote> <p dir="auto">the vast majority of the planet still uses CJS, and is likely to for the foreseeable future</p> </blockquote> <p dir="auto">Hard disagree.</p> <p dir="auto">Most developers are so dependant on build tooling they don't actually know how to write a CJS module; millions of developers have their source as ESM. To them, CJS is an implementation detail of Babel, Next.js and Node.js. Most of the installs on npm flow from a few popular libraries/frameworks that suck in an ungodly amount of dependencies on install. If one or two switch to pure ESM and update their dependencies to newer pure ESM versions, overnight millions of CJS installations evaporate.</p> <p dir="auto">There is a network effect where once packages start flipping to pure ESM, CJS packages that consume it also have to flip. The only reason this hasn't spread like wildfire already is because a few dev tools (namely TypeScript, Next.js, and Jest) have refused or delayed Node.js ESM support, and once they support ESM properly we'll be unblocked from a mad scramble to ESM over the next year or so. In 2 years, we might have an ecosystem of maintained packages that are almost entirely pure ESM.</p> <p dir="auto">It's frustrating to see people defend lazy billion dollar corporations (Microsoft, Vercel (<a href="https://vercel.com/blog/vercel-funding-series-d-and-valuation" rel="nofollow">$2.5 billion in funding</a>), Facebook) who throw their weight around by either spreading FUD or inaction, instead of supporting the passionate open source package authors that want to publish, promulgate, and use the best technology possible. Once these corporations have been forced to take standard ESM seriously, the fixes don't take that long in the scheme of things to work out. They could have gone to the same effort years earlier and saved the ecosystem so much grief. It's like getting mega corporations off fossil fuels; imagine if everyone waited for the worlds richest corporations to change their policy first before everyone else follows and invests in and uses renewables. Progress would never happen. People need to stop putting big brand names on a pedestal; their policies are not always the best either for the world or for you. Sometimes you have to publicly challenge the narrative, lead by example, and inspire positive change. In this regard, <a class="user-mention notranslate" data-hovercard-type="user" data-hovercard-url="/users/sindresorhus/hovercard" data-octo-click="hovercard-link-click" data-octo-dimensions="link_type:self" href="https://github.com/sindresorhus">@sindresorhus</a> has the respect of many of us.</p> <p dir="auto">TypeScript have mostly figured out ESM/<code class="notranslate">.mjs</code>/<code class="notranslate">.cjs</code> compat but got <a href="https://github.com/microsoft/TypeScript/issues/46452" data-hovercard-type="issue" data-hovercard-url="/microsoft/TypeScript/issues/46452/hovercard">cold feet</a> and dropped most of it for the TS v4.5 release; they <a href="https://github.com/microsoft/TypeScript/issues/46452#issuecomment-978371550" data-hovercard-type="issue" data-hovercard-url="/microsoft/TypeScript/issues/46452/hovercard">plan to publish the fixes in v4.6</a> which is <a href="https://github.com/microsoft/TypeScript/issues/46858" data-hovercard-type="issue" data-hovercard-url="/microsoft/TypeScript/issues/46858/hovercard">scheduled for February 22, 2022</a>. It's outrageous that Microsoft isn't treating blatant Node.js incompatibilities as emergencies to be patched sooner, but being Christmas the next 2 months will zoom by.</p> <p dir="auto">Next.js and their inability to process pure ESM dependencies was the reason I didn't migrate a few of my own Next.js / front end related packages to pure ESM. They still haven't fixed bugs relating to ESM project modules (e.g. <a class="issue-link js-issue-link" data-error-text="Failed to load title" data-id="719000807" data-permission-text="Title is private" data-url="https://github.com/vercel/next.js/issues/17806" data-hovercard-type="issue" data-hovercard-url="/vercel/next.js/issues/17806/hovercard" href="https://github.com/vercel/next.js/issues/17806">vercel/next.js#17806</a>), but they have fixed support for pure ESM dependencies which was the main problem. Accordingly, I've gone ahead the past few weeks and converted several more packages to pure ESM. In time, others will do the same too.</p> <p dir="auto">I've got zero sympathy for people that were relying on Jest's ability to transpile source on the fly and screw around with concerns of the runtime by hacking the imports, instead of testing the actual distribution code properly via tests that are regular JS modules that don't need a special engine other than Node.js to run. Regardless, one way or another Jest will resolve all the Node.js ESM compat issues as it's an existential issue for the viability for the tool, or people can rewrite their tests.</p> <p dir="auto">The ESM flippening has already begun, but in a few months there will be no brakes on the train.</p> </div> </task-lists> </div> <!-- '"` --><!-- </textarea></xmp> --></option></form><form class="js-comment-update" data-type="json" data-turbo="false" action="/sindresorhus/a39789f98801d908bbc7ff3ecc99d99c/comments/3992076" accept-charset="UTF-8" method="post"><input type="hidden" name="_method" value="put" autocomplete="off" /><input type="hidden" name="authenticity_token" value="BcCgkWzjV7FRCzOkptw0o5vOGp4uKDuafwSjYV3Bg89xDvbfpR-mDFL5vjySAVDIB6ausYP2ZQa5erWSDWyYqQ" autocomplete="off" /> <include-fragment loading="lazy" src="/sindresorhus/a39789f98801d908bbc7ff3ecc99d99c/comments/3992076/edit_form?textarea_id=gistcomment-3992076-body&amp;comment_context=discussion" class="previewable-comment-form js-comment-edit-form-deferred-include-fragment" > <p class="text-center mt-3" data-hide-on-error> <span data-view-component="true"> <svg aria-label="Loading..." style="box-sizing: content-box; color: var(--color-icon-primary);" width="32" height="32" viewBox="0 0 16 16" fill="none" role="img" data-view-component="true" class="anim-rotate"> <circle cx="8" cy="8" r="7" stroke="currentColor" stroke-opacity="0.25" stroke-width="2" vector-effect="non-scaling-stroke" fill="none" /> <path d="M15 8a7.002 7.002 0 00-7-7" stroke="currentColor" stroke-width="2" stroke-linecap="round" vector-effect="non-scaling-stroke" /> </svg></span> </p> <p class="ml-1 mb-2 mt-2" data-show-on-error hidden> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-alert"> <path d="M6.457 1.047c.659-1.234 2.427-1.234 3.086 0l6.082 11.378A1.75 1.75 0 0 1 14.082 15H1.918a1.75 1.75 0 0 1-1.543-2.575Zm1.763.707a.25.25 0 0 0-.44 0L1.698 13.132a.25.25 0 0 0 .22.368h12.164a.25.25 0 0 0 .22-.368Zm.53 3.996v2.5a.75.75 0 0 1-1.5 0v-2.5a.75.75 0 0 1 1.5 0ZM9 11a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z"></path> </svg> Sorry, something went wrong. </p> </include-fragment> </form> </div> </div> <div class="TimelineItem d-block js-comment-container"> <div class="avatar-parent-child TimelineItem-avatar d-none d-md-block"> <a class="d-inline-block" data-hovercard-type="user" data-hovercard-url="/users/jimmywarting/hovercard" data-octo-click="hovercard-link-click" data-octo-dimensions="link_type:self" href="/jimmywarting"><img class=" avatar-user" src="https://avatars.githubusercontent.com/u/1148376?s=80&amp;v=4" width="40" height="40" alt="@jimmywarting" /></a> </div> <div id="gistcomment-3992692" class="timeline-comment-group js-minimizable-comment-group js-targetable-element my-0 comment previewable-edit js-task-list-container js-comment timeline-comment timeline-comment--caret ml-n3 js-minimize-container unminimized-comment"> <div class="timeline-comment-header clearfix d-flex" data-morpheus-enabled="false"> <div class="timeline-comment-actions flex-shrink-0 d-flex flex-items-center"> <details class="details-overlay details-reset position-relative d-inline-block"> <summary data-view-component="true" class="timeline-comment-action Link--secondary Button--link Button--medium Button"> <span class="Button-content"> <span class="Button-label"><svg aria-label="Show options" role="img" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-kebab-horizontal"> <path d="M8 9a1.5 1.5 0 1 0 0-3 1.5 1.5 0 0 0 0 3ZM1.5 9a1.5 1.5 0 1 0 0-3 1.5 1.5 0 0 0 0 3Zm13 0a1.5 1.5 0 1 0 0-3 1.5 1.5 0 0 0 0 3Z"></path> </svg></span> </span> </summary> <details-menu class="dropdown-menu dropdown-menu-sw show-more-popover color-fg-default" style="width:185px" src="" preload > <span data-view-component="true"> <clipboard-copy aria-label="Copy link" for="gistcomment-3992692-permalink" role="menuitem" data-view-component="true" class="dropdown-item btn-link"> Copy link </clipboard-copy> <div aria-live="polite" aria-atomic="true" class="sr-only" data-clipboard-copy-feedback></div> </span> </details-menu> </details> </div> <div class="d-none d-sm-flex"> </div> <h3 class="f5 text-normal" style="flex: 1 1 auto"> <div> <strong> <a class="author Link--primary text-bold css-overflow-wrap-anywhere " data-hovercard-type="user" data-hovercard-url="/users/jimmywarting/hovercard" data-octo-click="hovercard-link-click" data-octo-dimensions="link_type:self" href="/jimmywarting">jimmywarting</a> </strong> commented <a href="/sindresorhus/a39789f98801d908bbc7ff3ecc99d99c?permalink_comment_id=3992692#gistcomment-3992692" id="gistcomment-3992692-permalink" class="Link--secondary js-timestamp"><relative-time datetime="2021-12-12T18:05:34Z" class="no-wrap">Dec 12, 2021</relative-time></a> <span class="js-comment-edit-history"> <span class="d-inline-block color-fg-muted">&#8226;</span> <details class="details-overlay details-reset d-inline-block dropdown hx_dropdown-fullscreen"> <summary class="btn-link no-underline color-fg-muted js-notice"> <div class="position-relative"> <span> edited </span> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-triangle-down v-align-middle"> <path d="m4.427 7.427 3.396 3.396a.25.25 0 0 0 .354 0l3.396-3.396A.25.25 0 0 0 11.396 7H4.604a.25.25 0 0 0-.177.427Z"></path> </svg> </div> </summary> <details-menu class="dropdown-menu dropdown-menu-s width-auto py-0 js-comment-edit-history-menu" style="max-width: 352px; z-index: 99;" src="/user_content_edits/show_edit_history_log/GC_lADOABGF2NoAIGEzOTc4OWY5ODgwMWQ5MDhiYmM3ZmYzZWNjOTlkOTljzgA87HQ" preload > <include-fragment class="my-3" style="min-width: 100px;" aria-label="Loading..."> <span data-view-component="true"> <svg style="box-sizing: content-box; color: var(--color-icon-primary);" width="32" height="32" viewBox="0 0 16 16" fill="none" aria-hidden="true" data-view-component="true" class="mx-auto d-block anim-rotate"> <circle cx="8" cy="8" r="7" stroke="currentColor" stroke-opacity="0.25" stroke-width="2" vector-effect="non-scaling-stroke" fill="none" /> <path d="M15 8a7.002 7.002 0 00-7-7" stroke="currentColor" stroke-width="2" stroke-linecap="round" vector-effect="non-scaling-stroke" /> </svg> <span class="sr-only">Loading</span> </span> </include-fragment> </details-menu> </details> </span> </div> </h3> </div> <div class="edit-comment-hide"> <task-lists disabled sortable> <div class="comment-body markdown-body js-comment-body soft-wrap user-select-contain d-block"> <p dir="auto">I agree with you <a class="user-mention notranslate" data-hovercard-type="user" data-hovercard-url="/users/jaydenseric/hovercard" data-octo-click="hovercard-link-click" data-octo-dimensions="link_type:self" href="https://github.com/jaydenseric">@jaydenseric</a>... some typescript user think they use esm while in fact they are transpiling to cjs without even knowing it.</p> <p dir="auto">I would not call cjs depricated... legacy is a more correct word for it... it will likely never go away for a foreseeable future but new code should start to using esm by default now...</p> <p dir="auto">From my own experiences we at node-fetch fist wanted to use import and if we wanted to have dual support then it meant that we would have to convert everything back to cjs (even sup dependencies), which we didn't want to do anymore. We didn't want to duplicate all our code. and we didn't want to reintroduce a compiler. And We now also depend on other esm only packages. if we wanted to have dual support at this stage now then it meant that we would have to embed our sub dependencies into node-fetch and transpile them to cjs as well to keep a own copy for our self, which would duplicate all the code and classes and interfere with instances.<br> If someone where to depend on the same version of any of the public classes or sup packages (formdata, header, blob, file, abortsignal whatwg streams) or whatever then it would just be conflicting with <code class="notranslate">instanceof</code> checks and node-fetch would be stuck on one internal version of one package while you might depend on some newer version.</p> <p dir="auto">dual support is just a hazard that i want to avoid. cjs don't work in any other env other than NodeJS and NodeJS supports ESM now so why would one want to use cjs still? NodeJS is not the only platform, developers want their code to work cross other env too, even if you built something in cjs that was solo built to run in NodeJS, then there will always be that one guy who are going to wish that you built it as ESM so they can import it without the need of npm or any bundler for Deno or the Browaser.</p> <p dir="auto">Someone must start converting to pure ESM at some point. We can't sitt around and wait for all 23k packages who depend on node-fetch to switch to esm first. Or the other way around. We can't sitt around and wait for sub dependencies or build tools to all be ESM first. And we can't control how gulp, webpack, jest, rollup, typescript, babel, etc all deal with cjs and esm. then we would be stuck with cjs/dual packages forever.</p> <p dir="auto">It's just a chicken and the egg paradox of who should convert to ESM first... typescript and other have long stick there head in the sand about extension less paths and depend on cjs to resolve the path. This can't continue like this when we have remote path resolver that are dynamic lazy imported</p> <p dir="auto">i fear that ppl will start using the experimental-specifier-resolution flag and hope that it stays implicit for remote http path resolvers sakes<br> i wish experimental-specifier-resolution was never introduced into NodeJS, it's considered a bad practices now to depend on index and extensionless paths.</p> <p dir="auto">I don't have much sympathy for typescript user either. typescript isn't javascript... i work with javascript, nothing else.</p> <p dir="auto">sindre have my respect and esm is the feature, weather you like it or not. it's time to switch</p> </div> </task-lists> </div> <!-- '"` --><!-- </textarea></xmp> --></option></form><form class="js-comment-update" data-type="json" data-turbo="false" action="/sindresorhus/a39789f98801d908bbc7ff3ecc99d99c/comments/3992692" accept-charset="UTF-8" method="post"><input type="hidden" name="_method" value="put" autocomplete="off" /><input type="hidden" name="authenticity_token" value="VUTZFZSwJqBabMk2ck39uqHG2cdTFp1Ujg70QSABMKgY6hDKkbmnZtGBDdoI2D-obUaU2kuyTfj4dd7NzrrT-A" autocomplete="off" /> <include-fragment loading="lazy" src="/sindresorhus/a39789f98801d908bbc7ff3ecc99d99c/comments/3992692/edit_form?textarea_id=gistcomment-3992692-body&amp;comment_context=discussion" class="previewable-comment-form js-comment-edit-form-deferred-include-fragment" > <p class="text-center mt-3" data-hide-on-error> <span data-view-component="true"> <svg aria-label="Loading..." style="box-sizing: content-box; color: var(--color-icon-primary);" width="32" height="32" viewBox="0 0 16 16" fill="none" role="img" data-view-component="true" class="anim-rotate"> <circle cx="8" cy="8" r="7" stroke="currentColor" stroke-opacity="0.25" stroke-width="2" vector-effect="non-scaling-stroke" fill="none" /> <path d="M15 8a7.002 7.002 0 00-7-7" stroke="currentColor" stroke-width="2" stroke-linecap="round" vector-effect="non-scaling-stroke" /> </svg></span> </p> <p class="ml-1 mb-2 mt-2" data-show-on-error hidden> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-alert"> <path d="M6.457 1.047c.659-1.234 2.427-1.234 3.086 0l6.082 11.378A1.75 1.75 0 0 1 14.082 15H1.918a1.75 1.75 0 0 1-1.543-2.575Zm1.763.707a.25.25 0 0 0-.44 0L1.698 13.132a.25.25 0 0 0 .22.368h12.164a.25.25 0 0 0 .22-.368Zm.53 3.996v2.5a.75.75 0 0 1-1.5 0v-2.5a.75.75 0 0 1 1.5 0ZM9 11a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z"></path> </svg> Sorry, something went wrong. </p> </include-fragment> </form> </div> </div> <div class="TimelineItem d-block js-comment-container"> <div class="avatar-parent-child TimelineItem-avatar d-none d-md-block"> <a class="d-inline-block" data-hovercard-type="user" data-hovercard-url="/users/jaydenseric/hovercard" data-octo-click="hovercard-link-click" data-octo-dimensions="link_type:self" href="/jaydenseric"><img class=" avatar-user" src="https://avatars.githubusercontent.com/u/1754873?s=80&amp;v=4" width="40" height="40" alt="@jaydenseric" /></a> </div> <div id="gistcomment-3992942" class="timeline-comment-group js-minimizable-comment-group js-targetable-element my-0 comment previewable-edit js-task-list-container js-comment timeline-comment timeline-comment--caret ml-n3 js-minimize-container unminimized-comment"> <div class="timeline-comment-header clearfix d-flex" data-morpheus-enabled="false"> <div class="timeline-comment-actions flex-shrink-0 d-flex flex-items-center"> <details class="details-overlay details-reset position-relative d-inline-block"> <summary data-view-component="true" class="timeline-comment-action Link--secondary Button--link Button--medium Button"> <span class="Button-content"> <span class="Button-label"><svg aria-label="Show options" role="img" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-kebab-horizontal"> <path d="M8 9a1.5 1.5 0 1 0 0-3 1.5 1.5 0 0 0 0 3ZM1.5 9a1.5 1.5 0 1 0 0-3 1.5 1.5 0 0 0 0 3Zm13 0a1.5 1.5 0 1 0 0-3 1.5 1.5 0 0 0 0 3Z"></path> </svg></span> </span> </summary> <details-menu class="dropdown-menu dropdown-menu-sw show-more-popover color-fg-default" style="width:185px" src="" preload > <span data-view-component="true"> <clipboard-copy aria-label="Copy link" for="gistcomment-3992942-permalink" role="menuitem" data-view-component="true" class="dropdown-item btn-link"> Copy link </clipboard-copy> <div aria-live="polite" aria-atomic="true" class="sr-only" data-clipboard-copy-feedback></div> </span> </details-menu> </details> </div> <div class="d-none d-sm-flex"> </div> <h3 class="f5 text-normal" style="flex: 1 1 auto"> <div> <strong> <a class="author Link--primary text-bold css-overflow-wrap-anywhere " data-hovercard-type="user" data-hovercard-url="/users/jaydenseric/hovercard" data-octo-click="hovercard-link-click" data-octo-dimensions="link_type:self" href="/jaydenseric">jaydenseric</a> </strong> commented <a href="/sindresorhus/a39789f98801d908bbc7ff3ecc99d99c?permalink_comment_id=3992942#gistcomment-3992942" id="gistcomment-3992942-permalink" class="Link--secondary js-timestamp"><relative-time datetime="2021-12-13T01:14:46Z" class="no-wrap">Dec 13, 2021</relative-time></a> </div> </h3> </div> <div class="edit-comment-hide"> <task-lists disabled sortable> <div class="comment-body markdown-body js-comment-body soft-wrap user-select-contain d-block"> <p dir="auto"><a class="user-mention notranslate" data-hovercard-type="user" data-hovercard-url="/users/ljharb/hovercard" data-octo-click="hovercard-link-click" data-octo-dimensions="link_type:self" href="https://github.com/ljharb">@ljharb</a></p> <blockquote> <p dir="auto">The dual package "hazard" exists <strong>if and only if</strong> your package is stateful, or relies on identity. The vast majority of packages don't, and thus, for the vast majority of packages, there is no such thing as a dual package hazard.</p> </blockquote> <p dir="auto">This is simply untrue. Runtime identity issues are just one symptom of the dual package hazard. If you are bundling, consuming the ESM and CJS formats of the same code in different parts of your code base / dependency graph result in the same code being bundled twice, which slows your builds, and increases the download and parse times for users loading the web app. If you are not bundling, loading and parsing more code still has a performance cost.</p> <p dir="auto">Technically not the dual package hazard, but another downside regardless, is if every package in <code class="notranslate">node_modules</code> duplicated it's API in seperate ESM and CJS files, <code class="notranslate">node_modules</code> takes up considerably more disk space. <code class="notranslate">node_modules</code> install size is a serious problem the industry is facing; it slows installations in CI or for deployments, and increases disk space usage increasing costs or exceeding environment limits (particularly for serverless).</p> <p dir="auto"><a class="user-mention notranslate" data-hovercard-type="user" data-hovercard-url="/users/OmgImAlexis/hovercard" data-octo-click="hovercard-link-click" data-octo-dimensions="link_type:self" href="https://github.com/OmgImAlexis">@OmgImAlexis</a></p> <blockquote> <p dir="auto">you can check the existence of all of those files at the same time and then choose which to use. It's not going to take any noticeable difference in time.</p> </blockquote> <p dir="auto">There are good reasons automatic file extension resolution was dropped from the final Node.js ESM system, and it isn't a thing in Deno or browsers either. It's a bad idea. Looking up all the possible resolutions is prohibitive if the modules are imported using HTTP imports over network; either in a server environment (Deno) or in browsers for apps using ESM for real on the client. It also significantly complicates and slows a lot of dev tooling that statically analyses imports. For an example of just one tool, look at all the extra complexity supporting it added to <a href="https://github.com/jaydenseric/find-unused-exports"><code class="notranslate">find-unused-exports</code></a>:</p> <ul dir="auto"> <li>CLI option <code class="notranslate">--resolve-file-extensions</code></li> <li>CLI option <code class="notranslate">--resolve-index-files</code></li> <li>JS API option <code class="notranslate">resolveFileExtensions</code></li> <li>JS API option <code class="notranslate">resolveIndexFiles</code></li> <li>Extra implementation code: <ul dir="auto"> <li><a href="https://github.com/jaydenseric/find-unused-exports/blob/75ad2badf064012b636189874e3c784c192f2414/public/findUnusedExports.mjs#L16-L17">https://github.com/jaydenseric/find-unused-exports/blob/75ad2badf064012b636189874e3c784c192f2414/public/findUnusedExports.mjs#L16-L17</a></li> <li><a href="https://github.com/jaydenseric/find-unused-exports/blob/75ad2badf064012b636189874e3c784c192f2414/public/findUnusedExports.mjs#L31-L32">https://github.com/jaydenseric/find-unused-exports/blob/75ad2badf064012b636189874e3c784c192f2414/public/findUnusedExports.mjs#L31-L32</a></li> <li><a href="https://github.com/jaydenseric/find-unused-exports/blob/75ad2badf064012b636189874e3c784c192f2414/public/findUnusedExports.mjs#L43-L59">https://github.com/jaydenseric/find-unused-exports/blob/75ad2badf064012b636189874e3c784c192f2414/public/findUnusedExports.mjs#L43-L59</a></li> <li><a href="https://github.com/jaydenseric/find-unused-exports/blob/75ad2badf064012b636189874e3c784c192f2414/public/findUnusedExports.mjs#L92-L104">https://github.com/jaydenseric/find-unused-exports/blob/75ad2badf064012b636189874e3c784c192f2414/public/findUnusedExports.mjs#L92-L104</a></li> <li><a href="https://github.com/jaydenseric/find-unused-exports/blob/75ad2badf064012b636189874e3c784c192f2414/cli/find-unused-exports.mjs#L22-L23">https://github.com/jaydenseric/find-unused-exports/blob/75ad2badf064012b636189874e3c784c192f2414/cli/find-unused-exports.mjs#L22-L23</a></li> <li><a href="https://github.com/jaydenseric/find-unused-exports/blob/75ad2badf064012b636189874e3c784c192f2414/cli/find-unused-exports.mjs#L26-L27">https://github.com/jaydenseric/find-unused-exports/blob/75ad2badf064012b636189874e3c784c192f2414/cli/find-unused-exports.mjs#L26-L27</a></li> <li><a href="https://github.com/jaydenseric/find-unused-exports/blob/75ad2badf064012b636189874e3c784c192f2414/cli/find-unused-exports.mjs#L30-L33">https://github.com/jaydenseric/find-unused-exports/blob/75ad2badf064012b636189874e3c784c192f2414/cli/find-unused-exports.mjs#L30-L33</a></li> <li><a href="https://github.com/jaydenseric/find-unused-exports/blob/75ad2badf064012b636189874e3c784c192f2414/cli/find-unused-exports.mjs#L37-L40">https://github.com/jaydenseric/find-unused-exports/blob/75ad2badf064012b636189874e3c784c192f2414/cli/find-unused-exports.mjs#L37-L40</a></li> </ul> </li> <li>Extra test code: <ul dir="auto"> <li><a href="https://github.com/jaydenseric/find-unused-exports/blob/75ad2badf064012b636189874e3c784c192f2414/test/public/findUnusedExports.test.mjs#L168-L208">https://github.com/jaydenseric/find-unused-exports/blob/75ad2badf064012b636189874e3c784c192f2414/test/public/findUnusedExports.test.mjs#L168-L208</a></li> <li><a href="https://github.com/jaydenseric/find-unused-exports/blob/75ad2badf064012b636189874e3c784c192f2414/test/public/findUnusedExports.test.mjs#L239-L298">https://github.com/jaydenseric/find-unused-exports/blob/75ad2badf064012b636189874e3c784c192f2414/test/public/findUnusedExports.test.mjs#L239-L298</a></li> <li><a href="https://github.com/jaydenseric/find-unused-exports/blob/75ad2badf064012b636189874e3c784c192f2414/test/cli/find-unused-exports.test.mjs#L94-L203">https://github.com/jaydenseric/find-unused-exports/blob/75ad2badf064012b636189874e3c784c192f2414/test/cli/find-unused-exports.test.mjs#L94-L203</a></li> </ul> </li> </ul> </div> </task-lists> </div> <!-- '"` --><!-- </textarea></xmp> --></option></form><form class="js-comment-update" data-type="json" data-turbo="false" action="/sindresorhus/a39789f98801d908bbc7ff3ecc99d99c/comments/3992942" accept-charset="UTF-8" method="post"><input type="hidden" name="_method" value="put" autocomplete="off" /><input type="hidden" name="authenticity_token" value="zE-MOAWl-JuG8r_luenU4_AJGDdTiFr_wDQ8KIRz34fcK-uqxsbUysXVyd0ilZIhpC5jW-ZxcSLtSBUPgZHnvw" autocomplete="off" /> <include-fragment loading="lazy" src="/sindresorhus/a39789f98801d908bbc7ff3ecc99d99c/comments/3992942/edit_form?textarea_id=gistcomment-3992942-body&amp;comment_context=discussion" class="previewable-comment-form js-comment-edit-form-deferred-include-fragment" > <p class="text-center mt-3" data-hide-on-error> <span data-view-component="true"> <svg aria-label="Loading..." style="box-sizing: content-box; color: var(--color-icon-primary);" width="32" height="32" viewBox="0 0 16 16" fill="none" role="img" data-view-component="true" class="anim-rotate"> <circle cx="8" cy="8" r="7" stroke="currentColor" stroke-opacity="0.25" stroke-width="2" vector-effect="non-scaling-stroke" fill="none" /> <path d="M15 8a7.002 7.002 0 00-7-7" stroke="currentColor" stroke-width="2" stroke-linecap="round" vector-effect="non-scaling-stroke" /> </svg></span> </p> <p class="ml-1 mb-2 mt-2" data-show-on-error hidden> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-alert"> <path d="M6.457 1.047c.659-1.234 2.427-1.234 3.086 0l6.082 11.378A1.75 1.75 0 0 1 14.082 15H1.918a1.75 1.75 0 0 1-1.543-2.575Zm1.763.707a.25.25 0 0 0-.44 0L1.698 13.132a.25.25 0 0 0 .22.368h12.164a.25.25 0 0 0 .22-.368Zm.53 3.996v2.5a.75.75 0 0 1-1.5 0v-2.5a.75.75 0 0 1 1.5 0ZM9 11a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z"></path> </svg> Sorry, something went wrong. </p> </include-fragment> </form> </div> </div> <div class="TimelineItem d-block js-comment-container"> <div class="avatar-parent-child TimelineItem-avatar d-none d-md-block"> <a class="d-inline-block" data-hovercard-type="user" data-hovercard-url="/users/sindresorhus/hovercard" data-octo-click="hovercard-link-click" data-octo-dimensions="link_type:self" href="/sindresorhus"><img class=" avatar-user" src="https://avatars.githubusercontent.com/u/170270?s=80&amp;v=4" width="40" height="40" alt="@sindresorhus" /></a> </div> <div id="gistcomment-4053054" class="timeline-comment-group js-minimizable-comment-group js-targetable-element my-0 comment previewable-edit js-task-list-container js-comment timeline-comment timeline-comment--caret ml-n3 js-minimize-container unminimized-comment"> <div class="timeline-comment-header clearfix d-flex" data-morpheus-enabled="false"> <div class="timeline-comment-actions flex-shrink-0 d-flex flex-items-center"> <details class="details-overlay details-reset position-relative d-inline-block"> <summary data-view-component="true" class="timeline-comment-action Link--secondary Button--link Button--medium Button"> <span class="Button-content"> <span class="Button-label"><svg aria-label="Show options" role="img" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-kebab-horizontal"> <path d="M8 9a1.5 1.5 0 1 0 0-3 1.5 1.5 0 0 0 0 3ZM1.5 9a1.5 1.5 0 1 0 0-3 1.5 1.5 0 0 0 0 3Zm13 0a1.5 1.5 0 1 0 0-3 1.5 1.5 0 0 0 0 3Z"></path> </svg></span> </span> </summary> <details-menu class="dropdown-menu dropdown-menu-sw show-more-popover color-fg-default" style="width:185px" src="" preload > <span data-view-component="true"> <clipboard-copy aria-label="Copy link" for="gistcomment-4053054-permalink" role="menuitem" data-view-component="true" class="dropdown-item btn-link"> Copy link </clipboard-copy> <div aria-live="polite" aria-atomic="true" class="sr-only" data-clipboard-copy-feedback></div> </span> </details-menu> </details> </div> <div class="d-none d-sm-flex"> <span aria-label="This user is the author of this ." data-view-component="true" class="tooltipped tooltipped-n"> <span data-view-component="true" class="Label ml-1">Author</span> </span> </div> <h3 class="f5 text-normal" style="flex: 1 1 auto"> <div> <strong> <a class="author Link--primary text-bold css-overflow-wrap-anywhere " data-hovercard-type="user" data-hovercard-url="/users/sindresorhus/hovercard" data-octo-click="hovercard-link-click" data-octo-dimensions="link_type:self" href="/sindresorhus">sindresorhus</a> </strong> commented <a href="/sindresorhus/a39789f98801d908bbc7ff3ecc99d99c?permalink_comment_id=4053054#gistcomment-4053054" id="gistcomment-4053054-permalink" class="Link--secondary js-timestamp"><relative-time datetime="2022-02-04T04:08:33Z" class="no-wrap">Feb 4, 2022</relative-time></a> <span class="js-comment-edit-history"> <span class="d-inline-block color-fg-muted">&#8226;</span> <details class="details-overlay details-reset d-inline-block dropdown hx_dropdown-fullscreen"> <summary class="btn-link no-underline color-fg-muted js-notice"> <div class="position-relative"> <span> edited </span> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-triangle-down v-align-middle"> <path d="m4.427 7.427 3.396 3.396a.25.25 0 0 0 .354 0l3.396-3.396A.25.25 0 0 0 11.396 7H4.604a.25.25 0 0 0-.177.427Z"></path> </svg> </div> </summary> <details-menu class="dropdown-menu dropdown-menu-s width-auto py-0 js-comment-edit-history-menu" style="max-width: 352px; z-index: 99;" src="/user_content_edits/show_edit_history_log/GC_lADOAAKZHtoAIGEzOTc4OWY5ODgwMWQ5MDhiYmM3ZmYzZWNjOTlkOTljzgA92D4" preload > <include-fragment class="my-3" style="min-width: 100px;" aria-label="Loading..."> <span data-view-component="true"> <svg style="box-sizing: content-box; color: var(--color-icon-primary);" width="32" height="32" viewBox="0 0 16 16" fill="none" aria-hidden="true" data-view-component="true" class="mx-auto d-block anim-rotate"> <circle cx="8" cy="8" r="7" stroke="currentColor" stroke-opacity="0.25" stroke-width="2" vector-effect="non-scaling-stroke" fill="none" /> <path d="M15 8a7.002 7.002 0 00-7-7" stroke="currentColor" stroke-width="2" stroke-linecap="round" vector-effect="non-scaling-stroke" /> </svg> <span class="sr-only">Loading</span> </span> </include-fragment> </details-menu> </details> </span> </div> </h3> </div> <div class="edit-comment-hide"> <task-lists disabled sortable> <div class="comment-body markdown-body js-comment-body soft-wrap user-select-contain d-block"> <p dir="auto">This discussion thread is not productive and I never meant for this gist to be a place for everyone to vent about ESM.</p> <h1 dir="auto">CONSIDER THIS THREAD LOCKED</h1> <h2 dir="auto">ANY COMMENTS AFTER THIS ONE WILL BE DELETED</h2> </div> </task-lists> </div> <!-- '"` --><!-- </textarea></xmp> --></option></form><form class="js-comment-update" data-type="json" data-turbo="false" action="/sindresorhus/a39789f98801d908bbc7ff3ecc99d99c/comments/4053054" accept-charset="UTF-8" method="post"><input type="hidden" name="_method" value="put" autocomplete="off" /><input type="hidden" name="authenticity_token" value="k_NVZEyQCO8GOfCBHng1Ov3lbm5yemxBITzkCRgufpkpxbOBEbaTs5SxA7rIPrshZVbOSeKOMsmMcWJiCoSULw" autocomplete="off" /> <include-fragment loading="lazy" src="/sindresorhus/a39789f98801d908bbc7ff3ecc99d99c/comments/4053054/edit_form?textarea_id=gistcomment-4053054-body&amp;comment_context=discussion" class="previewable-comment-form js-comment-edit-form-deferred-include-fragment" > <p class="text-center mt-3" data-hide-on-error> <span data-view-component="true"> <svg aria-label="Loading..." style="box-sizing: content-box; color: var(--color-icon-primary);" width="32" height="32" viewBox="0 0 16 16" fill="none" role="img" data-view-component="true" class="anim-rotate"> <circle cx="8" cy="8" r="7" stroke="currentColor" stroke-opacity="0.25" stroke-width="2" vector-effect="non-scaling-stroke" fill="none" /> <path d="M15 8a7.002 7.002 0 00-7-7" stroke="currentColor" stroke-width="2" stroke-linecap="round" vector-effect="non-scaling-stroke" /> </svg></span> </p> <p class="ml-1 mb-2 mt-2" data-show-on-error hidden> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-alert"> <path d="M6.457 1.047c.659-1.234 2.427-1.234 3.086 0l6.082 11.378A1.75 1.75 0 0 1 14.082 15H1.918a1.75 1.75 0 0 1-1.543-2.575Zm1.763.707a.25.25 0 0 0-.44 0L1.698 13.132a.25.25 0 0 0 .22.368h12.164a.25.25 0 0 0 .22-.368Zm.53 3.996v2.5a.75.75 0 0 1-1.5 0v-2.5a.75.75 0 0 1 1.5 0ZM9 11a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z"></path> </svg> Sorry, something went wrong. </p> </include-fragment> </form> </div> </div> <!-- Rendered timeline since 2024-11-23 03:11:41 --> <div id="partial-timeline-marker" class="js-timeline-marker js-updatable-content" data-last-modified="Sat, 23 Nov 2024 11:11:41 GMT" > </div> </div> <div class="discussion-timeline-actions"> <div data-view-component="true" class="flash flash-warn mt-3"> <a rel="nofollow" class="btn btn-primary" data-hydro-click="{&quot;event_type&quot;:&quot;authentication.click&quot;,&quot;payload&quot;:{&quot;location_in_page&quot;:&quot;signed out comment&quot;,&quot;repository_id&quot;:null,&quot;auth_type&quot;:&quot;SIGN_UP&quot;,&quot;originating_url&quot;:&quot;https://gist.github.com/sindresorhus/a39789f98801d908bbc7ff3ecc99d99c&quot;,&quot;user_id&quot;:null}}" data-hydro-click-hmac="0731cbe894f946d4cd47a3cd7997af803b101de16f363a7ce0470ff2117eeff8" href="/join?source=comment-gist">Sign up for free</a> <strong>to join this conversation on GitHub</strong>. Already have an account? <a rel="nofollow" class="Link--inTextBlock" data-hydro-click="{&quot;event_type&quot;:&quot;authentication.click&quot;,&quot;payload&quot;:{&quot;location_in_page&quot;:&quot;signed out comment&quot;,&quot;repository_id&quot;:null,&quot;auth_type&quot;:&quot;LOG_IN&quot;,&quot;originating_url&quot;:&quot;https://gist.github.com/sindresorhus/a39789f98801d908bbc7ff3ecc99d99c&quot;,&quot;user_id&quot;:null}}" data-hydro-click-hmac="72846ac1bba8ff05ca7b6c29b8ac441229a4ff626455876436a73639987e173d" data-test-selector="comments-sign-in-link" href="/login?return_to=https%3A%2F%2Fgist.github.com%2Fsindresorhus%2Fa39789f98801d908bbc7ff3ecc99d99c">Sign in to comment</a> </div> </div> </div> </div> </div> </div> </div><!-- /.container --> </main> </div> </div> <footer class="footer pt-8 pb-6 f6 color-fg-muted p-responsive" role="contentinfo" > <h2 class='sr-only'>Footer</h2> <div class="d-flex flex-justify-center flex-items-center flex-column-reverse flex-lg-row flex-wrap flex-lg-nowrap"> <div class="d-flex flex-items-center flex-shrink-0 mx-2"> <a aria-label="Homepage" title="GitHub" class="footer-octicon mr-2" href="https://github.com"> <svg aria-hidden="true" height="24" viewBox="0 0 24 24" version="1.1" width="24" data-view-component="true" class="octicon octicon-mark-github"> <path d="M12.5.75C6.146.75 1 5.896 1 12.25c0 5.089 3.292 9.387 7.863 10.91.575.101.79-.244.79-.546 0-.273-.014-1.178-.014-2.142-2.889.532-3.636-.704-3.866-1.35-.13-.331-.69-1.352-1.18-1.625-.402-.216-.977-.748-.014-.762.906-.014 1.553.834 1.769 1.179 1.035 1.74 2.688 1.25 3.349.948.1-.747.402-1.25.733-1.538-2.559-.287-5.232-1.279-5.232-5.678 0-1.25.445-2.285 1.178-3.09-.115-.288-.517-1.467.115-3.048 0 0 .963-.302 3.163 1.179.92-.259 1.897-.388 2.875-.388.977 0 1.955.13 2.875.388 2.2-1.495 3.162-1.179 3.162-1.179.633 1.581.23 2.76.115 3.048.733.805 1.179 1.825 1.179 3.09 0 4.413-2.688 5.39-5.247 5.678.417.36.776 1.05.776 2.128 0 1.538-.014 2.774-.014 3.162 0 .302.216.662.79.547C20.709 21.637 24 17.324 24 12.25 24 5.896 18.854.75 12.5.75Z"></path> </svg> </a> <span> &copy; 2024 GitHub,&nbsp;Inc. </span> </div> <nav aria-label="Footer"> <h3 class="sr-only" id="sr-footer-heading">Footer navigation</h3> <ul class="list-style-none d-flex flex-justify-center flex-wrap mb-2 mb-lg-0" aria-labelledby="sr-footer-heading"> <li class="mx-2"> <a data-analytics-event="{&quot;category&quot;:&quot;Footer&quot;,&quot;action&quot;:&quot;go to Terms&quot;,&quot;label&quot;:&quot;text:terms&quot;}" href="https://docs.github.com/site-policy/github-terms/github-terms-of-service" data-view-component="true" class="Link--secondary Link">Terms</a> </li> <li class="mx-2"> <a data-analytics-event="{&quot;category&quot;:&quot;Footer&quot;,&quot;action&quot;:&quot;go to privacy&quot;,&quot;label&quot;:&quot;text:privacy&quot;}" href="https://docs.github.com/site-policy/privacy-policies/github-privacy-statement" data-view-component="true" class="Link--secondary Link">Privacy</a> </li> <li class="mx-2"> <a data-analytics-event="{&quot;category&quot;:&quot;Footer&quot;,&quot;action&quot;:&quot;go to security&quot;,&quot;label&quot;:&quot;text:security&quot;}" href="https://github.com/security" data-view-component="true" class="Link--secondary Link">Security</a> </li> <li class="mx-2"> <a data-analytics-event="{&quot;category&quot;:&quot;Footer&quot;,&quot;action&quot;:&quot;go to status&quot;,&quot;label&quot;:&quot;text:status&quot;}" href="https://www.githubstatus.com/" data-view-component="true" class="Link--secondary Link">Status</a> </li> <li class="mx-2"> <a data-analytics-event="{&quot;category&quot;:&quot;Footer&quot;,&quot;action&quot;:&quot;go to docs&quot;,&quot;label&quot;:&quot;text:docs&quot;}" href="https://docs.github.com/" data-view-component="true" class="Link--secondary Link">Docs</a> </li> <li class="mx-2"> <a data-analytics-event="{&quot;category&quot;:&quot;Footer&quot;,&quot;action&quot;:&quot;go to contact&quot;,&quot;label&quot;:&quot;text:contact&quot;}" href="https://support.github.com?tags=dotcom-footer" data-view-component="true" class="Link--secondary Link">Contact</a> </li> <li class="mx-2" > <cookie-consent-link> <button type="button" class="Link--secondary underline-on-hover border-0 p-0 color-bg-transparent" data-action="click:cookie-consent-link#showConsentManagement" data-analytics-event="{&quot;location&quot;:&quot;footer&quot;,&quot;action&quot;:&quot;cookies&quot;,&quot;context&quot;:&quot;subfooter&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;label&quot;:&quot;cookies_link_subfooter_footer&quot;}" > Manage cookies </button> </cookie-consent-link> </li> <li class="mx-2"> <cookie-consent-link> <button type="button" class="Link--secondary underline-on-hover border-0 p-0 color-bg-transparent" data-action="click:cookie-consent-link#showConsentManagement" data-analytics-event="{&quot;location&quot;:&quot;footer&quot;,&quot;action&quot;:&quot;dont_share_info&quot;,&quot;context&quot;:&quot;subfooter&quot;,&quot;tag&quot;:&quot;link&quot;,&quot;label&quot;:&quot;dont_share_info_link_subfooter_footer&quot;}" > Do not share my personal information </button> </cookie-consent-link> </li> </ul> </nav> </div> </footer> <ghcc-consent id="ghcc" class="position-fixed bottom-0 left-0" style="z-index: 999999" data-initial-cookie-consent-allowed="" data-cookie-consent-required="false"></ghcc-consent> <div id="ajax-error-message" class="ajax-error-message flash flash-error" hidden> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-alert"> <path d="M6.457 1.047c.659-1.234 2.427-1.234 3.086 0l6.082 11.378A1.75 1.75 0 0 1 14.082 15H1.918a1.75 1.75 0 0 1-1.543-2.575Zm1.763.707a.25.25 0 0 0-.44 0L1.698 13.132a.25.25 0 0 0 .22.368h12.164a.25.25 0 0 0 .22-.368Zm.53 3.996v2.5a.75.75 0 0 1-1.5 0v-2.5a.75.75 0 0 1 1.5 0ZM9 11a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z"></path> </svg> <button type="button" class="flash-close js-ajax-error-dismiss" aria-label="Dismiss error"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-x"> <path d="M3.72 3.72a.75.75 0 0 1 1.06 0L8 6.94l3.22-3.22a.749.749 0 0 1 1.275.326.749.749 0 0 1-.215.734L9.06 8l3.22 3.22a.749.749 0 0 1-.326 1.275.749.749 0 0 1-.734-.215L8 9.06l-3.22 3.22a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042L6.94 8 3.72 4.78a.75.75 0 0 1 0-1.06Z"></path> </svg> </button> You can’t perform that action at this time. </div> <template id="site-details-dialog"> <details class="details-reset details-overlay details-overlay-dark lh-default color-fg-default hx_rsm" open> <summary role="button" aria-label="Close dialog"></summary> <details-dialog class="Box Box--overlay d-flex flex-column anim-fade-in fast hx_rsm-dialog hx_rsm-modal"> <button class="Box-btn-octicon m-0 btn-octicon position-absolute right-0 top-0" type="button" aria-label="Close dialog" data-close-dialog> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-x"> <path d="M3.72 3.72a.75.75 0 0 1 1.06 0L8 6.94l3.22-3.22a.749.749 0 0 1 1.275.326.749.749 0 0 1-.215.734L9.06 8l3.22 3.22a.749.749 0 0 1-.326 1.275.749.749 0 0 1-.734-.215L8 9.06l-3.22 3.22a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042L6.94 8 3.72 4.78a.75.75 0 0 1 0-1.06Z"></path> </svg> </button> <div class="octocat-spinner my-6 js-details-dialog-spinner"></div> </details-dialog> </details> </template> <div class="Popover js-hovercard-content position-absolute" style="display: none; outline: none;"> <div class="Popover-message Popover-message--bottom-left Popover-message--large Box color-shadow-large" style="width:360px;"> </div> </div> <template id="snippet-clipboard-copy-button"> <div class="zeroclipboard-container position-absolute right-0 top-0"> <clipboard-copy aria-label="Copy" class="ClipboardButton btn js-clipboard-copy m-2 p-0" data-copy-feedback="Copied!" data-tooltip-direction="w"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-copy js-clipboard-copy-icon m-2"> <path d="M0 6.75C0 5.784.784 5 1.75 5h1.5a.75.75 0 0 1 0 1.5h-1.5a.25.25 0 0 0-.25.25v7.5c0 .138.112.25.25.25h7.5a.25.25 0 0 0 .25-.25v-1.5a.75.75 0 0 1 1.5 0v1.5A1.75 1.75 0 0 1 9.25 16h-7.5A1.75 1.75 0 0 1 0 14.25Z"></path><path d="M5 1.75C5 .784 5.784 0 6.75 0h7.5C15.216 0 16 .784 16 1.75v7.5A1.75 1.75 0 0 1 14.25 11h-7.5A1.75 1.75 0 0 1 5 9.25Zm1.75-.25a.25.25 0 0 0-.25.25v7.5c0 .138.112.25.25.25h7.5a.25.25 0 0 0 .25-.25v-7.5a.25.25 0 0 0-.25-.25Z"></path> </svg> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-check js-clipboard-check-icon color-fg-success d-none m-2"> <path d="M13.78 4.22a.75.75 0 0 1 0 1.06l-7.25 7.25a.75.75 0 0 1-1.06 0L2.22 9.28a.751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018L6 10.94l6.72-6.72a.75.75 0 0 1 1.06 0Z"></path> </svg> </clipboard-copy> </div> </template> <template id="snippet-clipboard-copy-button-unpositioned"> <div class="zeroclipboard-container"> <clipboard-copy aria-label="Copy" class="ClipboardButton btn btn-invisible js-clipboard-copy m-2 p-0 d-flex flex-justify-center flex-items-center" data-copy-feedback="Copied!" data-tooltip-direction="w"> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-copy js-clipboard-copy-icon"> <path d="M0 6.75C0 5.784.784 5 1.75 5h1.5a.75.75 0 0 1 0 1.5h-1.5a.25.25 0 0 0-.25.25v7.5c0 .138.112.25.25.25h7.5a.25.25 0 0 0 .25-.25v-1.5a.75.75 0 0 1 1.5 0v1.5A1.75 1.75 0 0 1 9.25 16h-7.5A1.75 1.75 0 0 1 0 14.25Z"></path><path d="M5 1.75C5 .784 5.784 0 6.75 0h7.5C15.216 0 16 .784 16 1.75v7.5A1.75 1.75 0 0 1 14.25 11h-7.5A1.75 1.75 0 0 1 5 9.25Zm1.75-.25a.25.25 0 0 0-.25.25v7.5c0 .138.112.25.25.25h7.5a.25.25 0 0 0 .25-.25v-7.5a.25.25 0 0 0-.25-.25Z"></path> </svg> <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-check js-clipboard-check-icon color-fg-success d-none"> <path d="M13.78 4.22a.75.75 0 0 1 0 1.06l-7.25 7.25a.75.75 0 0 1-1.06 0L2.22 9.28a.751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018L6 10.94l6.72-6.72a.75.75 0 0 1 1.06 0Z"></path> </svg> </clipboard-copy> </div> </template> </div> <div id="js-global-screen-reader-notice" class="sr-only mt-n1" aria-live="polite" aria-atomic="true" ></div> <div id="js-global-screen-reader-notice-assertive" class="sr-only mt-n1" aria-live="assertive" aria-atomic="true"></div> </body> </html>

Pages: 1 2 3 4 5 6 7 8 9 10