Skip to content

Instantly share code, notes, and snippets.

@timostamm
Created November 8, 2023 14:56
Show Gist options
  • Save timostamm/8f4ba7b08a1cf429c80fac4fa44fa2cd to your computer and use it in GitHub Desktop.
Save timostamm/8f4ba7b08a1cf429c80fac4fa44fa2cd to your computer and use it in GitHub Desktop.
Analyze "module" exports of high-impact npm packages
$ node check.mjs
High-impact npm packages: 7007
Packages with exports: 1126
Packages with "module" exports: 44
- tslib
- uuid
- @emotion/memoize
- es-module-lexer
- @emotion/unitless
- @emotion/hash
- underscore
- @emotion/is-prop-valid
- @emotion/utils
- @emotion/serialize
- @emotion/cache
- @emotion/sheet
- @emotion/weak-memoize
- react-select
- @emotion/react
- @emotion/babel-plugin
- @emotion/use-insertion-effect-with-fallbacks
- idb
- @emotion/styled
- @floating-ui/dom
- @floating-ui/core
- @emotion/css
- @azure/msal-common
- react-error-boundary
- mitt
- @floating-ui/react-dom
- react-textarea-autosize
- react-i18next
- @azure/msal-browser
- zustand
- @azure/msal-node
- @floating-ui/utils
- vuex
- @fortawesome/fontawesome-svg-core
- @firebase/messaging
- swr
- use-debounce
- i18next-browser-languagedetector
- redux-saga
- react-virtualized-auto-sizer
- dexie
- @emotion/babel-preset-css-prop
- @polkadot/util
- @polkadot/api
Packages with "module" export before "import": 34
Packages with "module" export before "default": 5
import {npmHighImpact} from 'npm-high-impact'
import {readFileSync, existsSync, writeFileSync} from "node:fs";
void main();
async function main() {
const pkgs = await getPackages();
const exports = pkgs.filter(pkg =>
hasExports(pkg, (obj => {
return true;
}))
);
const moduleExport = pkgs.filter(pkg =>
hasExports(pkg, (obj => {
return "module" in obj;
}))
);
const moduleBeforeImport = pkgs.filter(pkg =>
hasExports(pkg, (obj => {
const keys = Object.keys(obj);
const moduleIndex = keys.indexOf("module");
const importIndex = keys.indexOf("import");
if (moduleIndex >= 0 && importIndex >= 0) {
return moduleIndex < importIndex;
}
return false;
}))
);
const moduleBeforeDefault = pkgs.filter(pkg =>
pkg.type === "module" &&
hasExports(pkg, (obj => {
const keys = Object.keys(obj);
const moduleIndex = keys.indexOf("module");
const defaultIndex = keys.indexOf("default");
if (moduleIndex >= 0 && defaultIndex >= 0) {
return moduleIndex < defaultIndex;
}
return false;
}))
);
console.log(`High-impact npm packages: ${npmHighImpact.length}`);
console.log(`Packages with exports: ${exports.length}`);
console.log(`Packages with "module" exports: ${moduleExport.length}`);
for (const pkg of moduleExport) {
console.log(`- ${pkg.name}`);
}
console.log(`Packages with "module" export before "import": ${moduleBeforeImport.length}`);
console.log(`Packages with "module" export before "default": ${moduleBeforeDefault.length}`);
}
/**
* @return {Promise<object[]>}
*/
async function getPackages() {
const pkgsFile = "pkgs.json";
let pkgs = {};
if (existsSync(pkgsFile)) {
pkgs = JSON.parse(readFileSync(pkgsFile, "utf-8"));
}
for (const name of npmHighImpact) {
if (name in pkgs) {
continue;
}
console.log(`fetching ${name}`);
const res = await fetch(`https://registry.npmjs.com/${name}/latest`);
pkgs[name] = await res.json();
writeFileSync(pkgsFile, JSON.stringify(pkgs));
}
return Object.values(pkgs);
}
/**
* @callback hasExports~fn
* @param {object} obj
* @return {boolean}
*/
/**
* @param {object} pkg
* @param {hasExports~fn} fn
* @return {boolean}
*/
function hasExports(pkg, fn) {
if (!("exports" in pkg)) {
return false;
}
function recurse(obj) {
if (obj === null) {
return false;
}
if (typeof obj !== "object") {
return false;
}
const r = fn(obj);
if (r) {
return true;
}
for (const val of Object.values(obj)) {
if (recurse(val)) {
return true;
}
}
return false;
}
return recurse(pkg.exports);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment