javascript ecosystem is a meme.
how can anyone take the javascript ecosystem seriously at this point?
this is the size of node_modules of a barebones nextjs project with typescript and turbopack:
$ du -sh node_modules
502M node_modules
this is the list of packages installed in an astro “minimal (empty) template”:
$ bun pm ls --all
├── @astrojs/compiler@2.13.0
├── @astrojs/internal-helpers@0.7.4
├── @astrojs/markdown-remark@6.3.8
├── @astrojs/prism@3.3.0
├── @astrojs/telemetry@3.3.0
├── @babel/helper-string-parser@7.27.1
├── @babel/helper-validator-identifier@7.27.1
├── @babel/parser@7.28.4
├── @babel/types@7.28.4
├── @capsizecss/unpack@3.0.0
├── @emnapi/runtime@1.5.0
├── @esbuild/aix-ppc64@0.25.10
├── @esbuild/android-arm@0.25.10
├── @esbuild/android-arm64@0.25.10
├── @esbuild/android-x64@0.25.10
├── @esbuild/darwin-arm64@0.25.10
├── @esbuild/darwin-x64@0.25.10
├── @esbuild/freebsd-arm64@0.25.10
├── @esbuild/freebsd-x64@0.25.10
├── @esbuild/linux-arm@0.25.10
├── @esbuild/linux-arm64@0.25.10
├── @esbuild/linux-ia32@0.25.10
├── @esbuild/linux-loong64@0.25.10
├── @esbuild/linux-mips64el@0.25.10
├── @esbuild/linux-ppc64@0.25.10
├── @esbuild/linux-riscv64@0.25.10
├── @esbuild/linux-s390x@0.25.10
├── @esbuild/linux-x64@0.25.10
├── @esbuild/netbsd-arm64@0.25.10
├── @esbuild/netbsd-x64@0.25.10
├── @esbuild/openbsd-arm64@0.25.10
├── @esbuild/openbsd-x64@0.25.10
├── @esbuild/openharmony-arm64@0.25.10
├── @esbuild/sunos-x64@0.25.10
├── @esbuild/win32-arm64@0.25.10
├── @esbuild/win32-ia32@0.25.10
├── @esbuild/win32-x64@0.25.10
├── @img/colour@1.0.0
├── @img/sharp-darwin-arm64@0.34.4
├── @img/sharp-darwin-x64@0.34.4
├── @img/sharp-libvips-darwin-arm64@1.2.3
├── @img/sharp-libvips-darwin-x64@1.2.3
├── @img/sharp-libvips-linux-arm@1.2.3
├── @img/sharp-libvips-linux-arm64@1.2.3
├── @img/sharp-libvips-linux-ppc64@1.2.3
├── @img/sharp-libvips-linux-s390x@1.2.3
├── @img/sharp-libvips-linux-x64@1.2.3
├── @img/sharp-libvips-linuxmusl-arm64@1.2.3
├── @img/sharp-libvips-linuxmusl-x64@1.2.3
├── @img/sharp-linux-arm@0.34.4
├── @img/sharp-linux-arm64@0.34.4
├── @img/sharp-linux-ppc64@0.34.4
├── @img/sharp-linux-s390x@0.34.4
├── @img/sharp-linux-x64@0.34.4
├── @img/sharp-linuxmusl-arm64@0.34.4
├── @img/sharp-linuxmusl-x64@0.34.4
├── @img/sharp-wasm32@0.34.4
├── @img/sharp-win32-arm64@0.34.4
├── @img/sharp-win32-ia32@0.34.4
├── @img/sharp-win32-x64@0.34.4
├── @jridgewell/sourcemap-codec@1.5.5
├── @oslojs/encoding@1.1.0
├── @rollup/pluginutils@5.3.0
│ └── estree-walker@2.0.2
├── @rollup/rollup-android-arm-eabi@4.52.4
├── @rollup/rollup-android-arm64@4.52.4
├── @rollup/rollup-darwin-arm64@4.52.4
├── @rollup/rollup-darwin-x64@4.52.4
├── @rollup/rollup-freebsd-arm64@4.52.4
├── @rollup/rollup-freebsd-x64@4.52.4
├── @rollup/rollup-linux-arm-gnueabihf@4.52.4
├── @rollup/rollup-linux-arm-musleabihf@4.52.4
├── @rollup/rollup-linux-arm64-gnu@4.52.4
├── @rollup/rollup-linux-arm64-musl@4.52.4
├── @rollup/rollup-linux-loong64-gnu@4.52.4
├── @rollup/rollup-linux-ppc64-gnu@4.52.4
├── @rollup/rollup-linux-riscv64-gnu@4.52.4
├── @rollup/rollup-linux-riscv64-musl@4.52.4
├── @rollup/rollup-linux-s390x-gnu@4.52.4
├── @rollup/rollup-linux-x64-gnu@4.52.4
├── @rollup/rollup-linux-x64-musl@4.52.4
├── @rollup/rollup-openharmony-arm64@4.52.4
├── @rollup/rollup-win32-arm64-msvc@4.52.4
├── @rollup/rollup-win32-ia32-msvc@4.52.4
├── @rollup/rollup-win32-x64-gnu@4.52.4
├── @rollup/rollup-win32-x64-msvc@4.52.4
├── @shikijs/core@3.13.0
├── @shikijs/engine-javascript@3.13.0
├── @shikijs/engine-oniguruma@3.13.0
├── @shikijs/langs@3.13.0
├── @shikijs/themes@3.13.0
├── @shikijs/types@3.13.0
├── @shikijs/vscode-textmate@10.0.2
├── @swc/helpers@0.5.17
├── @types/debug@4.1.12
├── @types/estree@1.0.8
├── @types/fontkit@2.0.8
├── @types/hast@3.0.4
├── @types/mdast@4.0.4
├── @types/ms@2.1.0
├── @types/nlcst@2.0.3
├── @types/node@24.7.2
├── @types/unist@3.0.3
├── @ungap/structured-clone@1.3.0
├── acorn@8.15.0
├── ansi-align@3.0.1
│ └── string-width@4.2.3
│ ├── emoji-regex@8.0.0
│ └── strip-ansi@6.0.1
│ └── ansi-regex@5.0.1
├── ansi-regex@6.2.2
├── ansi-styles@6.2.3
├── anymatch@3.1.3
│ └── picomatch@2.3.1
├── argparse@2.0.1
├── aria-query@5.3.2
├── array-iterate@2.0.1
├── astro@5.14.4
├── axobject-query@4.1.0
├── bail@2.0.2
├── base-64@1.0.0
├── base64-js@1.5.1
├── boxen@8.0.1
├── brotli@1.3.3
├── camelcase@8.0.0
├── ccount@2.0.1
├── chalk@5.6.2
├── character-entities@2.0.2
├── character-entities-html4@2.1.0
├── character-entities-legacy@3.0.0
├── chokidar@4.0.3
├── ci-info@4.3.1
├── cli-boxes@3.0.0
├── clone@2.1.2
├── clsx@2.1.1
├── comma-separated-tokens@2.0.3
├── common-ancestor-path@1.0.1
├── cookie@1.0.2
├── cookie-es@1.2.2
├── crossws@0.3.5
├── css-tree@3.1.0
├── cssesc@3.0.0
├── debug@4.4.3
├── decode-named-character-reference@1.2.0
├── defu@6.1.4
├── dequal@2.0.3
├── destr@2.0.5
├── detect-libc@2.1.2
├── deterministic-object-hash@2.0.2
├── devalue@5.3.2
├── devlop@1.1.0
├── dfa@1.2.0
├── diff@5.2.0
├── dlv@1.1.3
├── dset@3.1.4
├── emoji-regex@10.5.0
├── entities@6.0.1
├── es-module-lexer@1.7.0
├── esbuild@0.25.10
├── escape-string-regexp@5.0.0
├── estree-walker@3.0.3
├── eventemitter3@5.0.1
├── extend@3.0.2
├── fast-deep-equal@3.1.3
├── fdir@6.5.0
├── flattie@1.1.1
├── fontace@0.3.1
├── fontkit@2.0.4
├── fsevents@2.3.3
├── get-east-asian-width@1.4.0
├── github-slugger@2.0.0
├── h3@1.15.4
├── hast-util-from-html@2.0.3
├── hast-util-from-parse5@8.0.3
├── hast-util-is-element@3.0.0
├── hast-util-parse-selector@4.0.0
├── hast-util-raw@9.1.0
├── hast-util-to-html@9.0.5
├── hast-util-to-parse5@8.0.0
│ └── property-information@6.5.0
├── hast-util-to-text@4.0.2
├── hast-util-whitespace@3.0.0
├── hastscript@9.0.1
├── html-escaper@3.0.3
├── html-void-elements@3.0.0
├── http-cache-semantics@4.2.0
├── import-meta-resolve@4.2.0
├── iron-webcrypto@1.2.1
├── is-docker@3.0.0
├── is-fullwidth-code-point@3.0.0
├── is-inside-container@1.0.0
├── is-plain-obj@4.1.0
├── is-wsl@3.1.0
├── js-yaml@4.1.0
├── kleur@4.1.5
├── longest-streak@3.1.0
├── lru-cache@10.4.3
├── magic-string@0.30.19
├── magicast@0.3.5
├── markdown-table@3.0.4
├── mdast-util-definitions@6.0.0
├── mdast-util-find-and-replace@3.0.2
├── mdast-util-from-markdown@2.0.2
├── mdast-util-gfm@3.1.0
├── mdast-util-gfm-autolink-literal@2.0.1
├── mdast-util-gfm-footnote@2.1.0
├── mdast-util-gfm-strikethrough@2.0.0
├── mdast-util-gfm-table@2.0.0
├── mdast-util-gfm-task-list-item@2.0.0
├── mdast-util-phrasing@4.1.0
├── mdast-util-to-hast@13.2.0
├── mdast-util-to-markdown@2.1.2
├── mdast-util-to-string@4.0.0
├── mdn-data@2.12.2
├── micromark@4.0.2
├── micromark-core-commonmark@2.0.3
├── micromark-extension-gfm@3.0.0
├── micromark-extension-gfm-autolink-literal@2.1.0
├── micromark-extension-gfm-footnote@2.1.0
├── micromark-extension-gfm-strikethrough@2.1.0
├── micromark-extension-gfm-table@2.1.1
├── micromark-extension-gfm-tagfilter@2.0.0
├── micromark-extension-gfm-task-list-item@2.1.0
├── micromark-factory-destination@2.0.1
├── micromark-factory-label@2.0.1
├── micromark-factory-space@2.0.1
├── micromark-factory-title@2.0.1
├── micromark-factory-whitespace@2.0.1
├── micromark-util-character@2.1.1
├── micromark-util-chunked@2.0.1
├── micromark-util-classify-character@2.0.1
├── micromark-util-combine-extensions@2.0.1
├── micromark-util-decode-numeric-character-reference@2.0.2
├── micromark-util-decode-string@2.0.1
├── micromark-util-encode@2.0.1
├── micromark-util-html-tag-name@2.0.1
├── micromark-util-normalize-identifier@2.0.1
├── micromark-util-resolve-all@2.0.1
├── micromark-util-sanitize-uri@2.0.1
├── micromark-util-subtokenize@2.1.0
├── micromark-util-symbol@2.0.1
├── micromark-util-types@2.0.2
├── mrmime@2.0.1
├── ms@2.1.3
├── nanoid@3.3.11
├── neotraverse@0.6.18
├── nlcst-to-string@4.0.0
├── node-fetch-native@1.6.7
├── node-mock-http@1.0.3
├── normalize-path@3.0.0
├── ofetch@1.4.1
├── ohash@2.0.11
├── oniguruma-parser@0.12.1
├── oniguruma-to-es@4.3.3
├── p-limit@6.2.0
├── p-queue@8.1.1
├── p-timeout@6.1.4
├── package-manager-detector@1.4.0
├── pako@0.2.9
├── parse-latin@7.0.0
├── parse5@7.3.0
├── picocolors@1.1.1
├── picomatch@4.0.3
├── postcss@8.5.6
├── prismjs@1.30.0
├── prompts@2.4.2
│ └── kleur@3.0.3
├── property-information@7.1.0
├── radix3@1.1.2
├── readdirp@4.1.2
├── regex@6.0.1
├── regex-recursion@6.0.2
├── regex-utilities@2.3.0
├── rehype@13.0.2
├── rehype-parse@9.0.1
├── rehype-raw@7.0.0
├── rehype-stringify@10.0.1
├── remark-gfm@4.0.1
├── remark-parse@11.0.0
├── remark-rehype@11.1.2
├── remark-smartypants@3.0.2
├── remark-stringify@11.0.0
├── restructure@3.0.2
├── retext@9.0.0
├── retext-latin@4.0.0
├── retext-smartypants@6.2.0
├── retext-stringify@4.0.0
├── rollup@4.52.4
├── semver@7.7.3
├── sharp@0.34.4
├── shiki@3.13.0
├── sisteransi@1.0.5
├── smol-toml@1.4.2
├── source-map-js@1.2.1
├── space-separated-tokens@2.0.2
├── string-width@7.2.0
├── stringify-entities@4.0.4
├── strip-ansi@7.1.2
├── tiny-inflate@1.0.3
├── tinyexec@1.0.1
├── tinyglobby@0.2.15
├── trim-lines@3.0.1
├── trough@2.2.0
├── tsconfck@3.1.6
├── tslib@2.8.1
├── type-fest@4.41.0
├── typescript@5.9.3
├── ufo@1.6.1
├── ultrahtml@1.6.0
├── uncrypto@0.1.3
├── undici-types@7.14.0
├── unicode-properties@1.4.1
├── unicode-trie@2.0.0
├── unified@11.0.5
├── unifont@0.6.0
├── unist-util-find-after@5.0.0
├── unist-util-is@6.0.0
├── unist-util-modify-children@4.0.0
├── unist-util-position@5.0.0
├── unist-util-remove-position@5.0.0
├── unist-util-stringify-position@4.0.0
├── unist-util-visit@5.0.0
├── unist-util-visit-children@3.0.0
├── unist-util-visit-parents@6.0.1
├── unstorage@1.17.1
├── vfile@6.0.3
├── vfile-location@5.0.3
├── vfile-message@4.0.3
├── vite@6.3.6
├── vitefu@1.1.1
├── web-namespaces@2.0.1
├── which-pm-runs@1.1.0
├── widest-line@5.0.0
├── wrap-ansi@9.0.2
├── xxhash-wasm@1.1.0
├── yargs-parser@21.1.1
├── yocto-queue@1.2.1
├── yocto-spinner@0.2.3
├── yoctocolors@2.1.2
├── zod@3.25.76
├── zod-to-json-schema@3.24.6
├── zod-to-ts@1.2.0
└── zwitch@2.0.4
need i say more?
sure, one could argue that it’s all actually required. but as far as i know, none of these frameworks ship with database support, auth etc out of the box. and setting em up requires manual intervention and more storage. when you run bun run dev, you’re greeted with a cutesy logo, and a counter app which isn’t all that useful. and things keep on changing. svelte switching to runes and older svelte projects breaking once you update packages was the final nail in the coffin for me.
anyways. theo out.