Repository: halfnelson/svelte-it-will-scale
Branch: master
Commit: 4df4c2af6ac2
Files: 10
Total size: 14.8 KB
Directory structure:
gitextract_8fw9pmo2/
├── .gitignore
├── README.md
├── build-chart.js
├── build-chart.preact.js
├── build-chart.react.js
├── makeindexs-react.js
├── makeindexs.js
├── package.json
├── rollup.config.js
└── rollup.config.react.js
================================================
FILE CONTENTS
================================================
================================================
FILE: .gitignore
================================================
/node_modules/
/public/build/
.DS_Store
index-1.js
index-5.js
index-10.js
index-20.js
index-30.js
index-40.js
index-50.js
index-60.js
index-70.js
index-1-react.js
index-5-react.js
index-10-react.js
index-20-react.js
index-30-react.js
index-40-react.js
index-50-react.js
================================================
FILE: README.md
================================================
# Will it Scale? - Finding Svelte's Inflection Point
from [#2546](https://github.com/sveltejs/svelte/issues/2546)
> Theoretically, yes there is an inflection point. Where that inflection point is is the only thing that really matters. In practice, you're unlikely to hit that inflection point on any given page of your app, as long as you're using code-splitting (which Sapper gives you OOTB)
We can work out this inflection point given sufficient data.
**TLDR: Inflection is at 120 KB of component source (for react 16)**
## Finding the Svelte Bundle Size Formula
To find the inflection point, we need to determine the relationship between a projects svelte component source, and its generated bundle size.
We use the components from:
* [Svelte Website](https://github.com/sveltejs/svelte/tree/master/site/src)
* [Svelte Realworld](https://github.com/sveltejs/realworld/)
* [Svelte HN](https://github.com/sveltejs/hn.svelte.dev)
After removing the style tags, and bundling and minification we get a graph:

The yellow line is our final zipped and minified bundle, each data point is a bundle built with rollup by the scripts in this repository.
We can see the relationship is mostly linear, and a linear regression gives
`Svelte Bundle Bytes = 0.493 * Source_Size + 2811`
## Finding the React Bundle Size Formula
We will compare our Svelte bundle size formula with reacts.
We will use the react components from:
* [React Native Website](https://github.com/facebook/react-native-website/)
* [React Redux Realworld](https://github.com/gothinkster/react-redux-realworld-example-app)
* [Builder Book](https://github.com/builderbook/builderbook)
After ensuring that we only include react components and not util/library code, we end up with the following graph:

The lines certainly look flatter than Svelte's, so we have a good chance of finding an inflection point. Linear regression on our data determines the relationship between React component source code and gzipped minified bundle size to be:
`React Bundle Bytes = 0.153 * Source_Size + 43503`
## Calculating the Inflection Point
With our two bundle size formulas, we are able to find an inflection point using basic algebra.... but that isn't as pretty as graphs:

Examining the graph shows __the inflection point is about 120KB of component source__.
## What does it mean?
It would seem that at about 120KB, the size advantage of going with a compiler over a runtime has vanished.
Should this be a concern?
from [#2546](https://github.com/sveltejs/svelte/issues/2546)
> In practice, you're unlikely to hit that inflection point on any given page of your app,
as long as you're using code-splitting (which Sapper gives you OOTB)
We should be able to check this assertion by looking at the amount of svelte code in each of the projects we used:

It turns out that svelte projects tend to be lean already. None of the projects we used came close to the inflection point, even all three projects combined falls short (we get just over half way there).
If these projects didn't come close, the odds are most projects won't. Indeed, even the figures above ignore code splitting, which would reduce the first payload significantly.
## Summary
It is good to have an answer to "Will it Scale", and we can be assured that yes "It Will Scale"
================================================
FILE: build-chart.js
================================================
const childProcess = require('child_process')
const fs = require('fs')
const component_counts = [1,5,10,20,30,40,50,60,70]
// build the bundles
console.log("building bundles....");
childProcess.execSync('npx rollup -c');
console.log("performing gzips...")
// build the gzips
component_counts.forEach(c =>
childProcess.execSync(`gzip -c public/build/bundle-${c}--lib-min.js > public/build/bundle-${c}--lib-min.js.gz`)
);
function getTotalScriptSize(index) {
const content = fs.readFileSync(index, 'utf-8');
let size = 0;
content.replace(/from '(.*?)'/gmi, (match, fname) => {
const content = fs.readFileSync(fname, 'utf-8');
let non_style_content = content.replace(/<style>.*?<\/style>/mgis, sub => {
return '';
})
size = size + non_style_content.length;
return match;
})
return size;
}
// print the stats
function fileSize(fname) {
return fs.statSync(fname).size
}
console.log('count original lib-nomin nolib-nomin lib-min nolib-min lib-min-gz')
component_counts.forEach(c => {
const bp = `public/build/bundle-${c}-`
console.log([c,
getTotalScriptSize(`index-${c}.js`),
fileSize(`${bp}-lib-nomin.js`),
fileSize(`${bp}-nolib-nomin.js`),
fileSize(`${bp}-lib-min.js`),
fileSize(`${bp}-nolib-min.js`),
fileSize(`${bp}-lib-min.js.gz`)
].join(' '));
})
================================================
FILE: build-chart.preact.js
================================================
const childProcess = require('child_process')
const fs = require('fs')
const component_counts = [1,5,10,20,30,40,50]
// build the bundles
console.log("building bundles....");
childProcess.execSync('npx rollup -c rollup.config.react.js');
console.log("performing gzips...")
// build the gzips
component_counts.forEach(c =>
childProcess.execSync(`tar -czvf public/build/bundle-react-${c}--lib-min.tar.gz public/build/bundle-react-${c}--min.js node_modules/preact/hooks/dist/hooks.umd.js node_modules/preact/dist/preact.umd.js`)
);
function getTotalScriptSize(index) {
let size = 0;
content = fs.readFileSync(index, "utf-8")
content.replace(/from '(.*?)'/gmi, (match, fname) => {
size = size + fileSize(fname)
return match;
})
return size;
}
// print the stats
function fileSize(fname) {
return fs.statSync(fname).size
}
console.log('count original lib-nomin nolib-nomin lib-min nolib-min lib-min-gz')
react_lib_size = fileSize('node_modules/preact/hooks/dist/hooks.umd.js') + fileSize('node_modules/preact/dist/preact.umd.js')
component_counts.forEach(c => {
const bp = `public/build/bundle-react-${c}-`
console.log([c,
getTotalScriptSize(`index-${c}-react.js`),
fileSize(`${bp}-nomin.js`) + react_lib_size,
fileSize(`${bp}-nomin.js`),
fileSize(`${bp}-min.js`) + react_lib_size,
fileSize(`${bp}-min.js`),
fileSize(`${bp}-lib-min.tar.gz`)
].join(' '));
})
================================================
FILE: build-chart.react.js
================================================
const childProcess = require('child_process')
const fs = require('fs')
const component_counts = [1,5,10,20,30,40,50]
// build the bundles
console.log("building bundles....");
childProcess.execSync('npx rollup -c rollup.config.react.js');
console.log("performing gzips...")
// build the gzips
component_counts.forEach(c =>
childProcess.execSync(`tar -czvf public/build/bundle-react-${c}--lib-min.tar.gz public/build/bundle-react-${c}--min.js node_modules/react/umd/react.production.min.js node_modules/react-dom/umd/react-dom.production.min.js`)
);
function getTotalScriptSize(index) {
let size = 0;
content = fs.readFileSync(index, "utf-8")
content.replace(/from '(.*?)'/gmi, (match, fname) => {
size = size + fileSize(fname)
return match;
})
return size;
}
// print the stats
function fileSize(fname) {
return fs.statSync(fname).size
}
console.log('count original lib-nomin nolib-nomin lib-min nolib-min lib-min-gz')
react_lib_size = fileSize('node_modules/react/umd/react.production.min.js') + fileSize('node_modules/react-dom/umd/react-dom.production.min.js')
component_counts.forEach(c => {
const bp = `public/build/bundle-react-${c}-`
console.log([c,
getTotalScriptSize(`index-${c}-react.js`),
fileSize(`${bp}-nomin.js`) + react_lib_size,
fileSize(`${bp}-nomin.js`),
fileSize(`${bp}-min.js`) + react_lib_size,
fileSize(`${bp}-min.js`),
fileSize(`${bp}-lib-min.tar.gz`)
].join(' '));
})
================================================
FILE: makeindexs-react.js
================================================
const fg = require('fast-glob')
const fs = require('fs')
const sizes = [1,5,10,20,30,40,50,60,70]
const dirs = ['../react-realworld/src/components', '../react-native-website/website/core', '../react-native-website/website/pages/en', '../builderbook/pages', '../builderbook/components']
let entries = fg.sync(dirs.map(dir => dir+'/**/*.js'))
function shuffleArray(array) {
for (var i = array.length - 1; i > 0; i--) {
var j = Math.floor(Math.random() * (i + 1));
var temp = array[i];
array[i] = array[j];
array[j] = temp;
}
}
function fileAsComponentName(fname) {
return fname.replace('.js','').replace(/[\[\]\/\.\-@]/g, '_')
}
let out = []
shuffleArray(entries);
console.log('entries', entries)
for (let entry of entries) {
out.push(`export { default as ${fileAsComponentName(entry)} } from '${entry}'`)
}
for (let count of sizes) {
if (count > out.length) break;
fs.writeFileSync(`index-${count}-react.js`, out.slice(0,count).join('\n'))
}
================================================
FILE: makeindexs.js
================================================
const fg = require('fast-glob')
const fs = require('fs')
const sizes = [1,5,10,20,30,40,50,60,70]
const dirs = ['../svelte/site/src', '../realworld', '../svelte-hn']
let entries = fg.sync(dirs.map(dir => dir+'/**/*.svelte'))
function shuffleArray(array) {
for (var i = array.length - 1; i > 0; i--) {
var j = Math.floor(Math.random() * (i + 1));
var temp = array[i];
array[i] = array[j];
array[j] = temp;
}
}
function fileAsComponentName(fname) {
return fname.replace('.svelte','').replace(/[\[\]\/\.\-@]/g, '_')
}
let out = []
shuffleArray(entries);
for (let entry of entries) {
out.push(`export { default as ${fileAsComponentName(entry)} } from '${entry}'`)
}
for (let count of sizes) {
if (count > out.length) break;
fs.writeFileSync(`index-${count}.js`, out.slice(0,count).join('\n'))
}
================================================
FILE: package.json
================================================
{
"name": "svelte-app",
"version": "1.0.0",
"scripts": {
"build": "rollup -c",
"dev": "rollup -c -w",
"start": "sirv public"
},
"devDependencies": {
"@rollup/plugin-commonjs": "^14.0.0",
"@rollup/plugin-node-resolve": "^8.0.0",
"rollup": "^2.3.4",
"rollup-plugin-svelte": "^5.0.3",
"rollup-plugin-terser": "^7.0.0",
"svelte": "^3.0.0"
},
"dependencies": {
"@babel/core": "^7.11.4",
"@babel/plugin-syntax-class-properties": "^7.10.4",
"@babel/plugin-transform-react-jsx": "^7.10.4",
"@babel/plugin-transform-runtime": "^7.11.0",
"@babel/preset-react": "^7.10.4",
"@rollup/plugin-babel": "^5.2.0",
"fast-glob": "^3.2.4",
"preact": "^10.4.7",
"react": "^16.13.1",
"react-dom": "^16.13.1",
"sirv-cli": "^1.0.0"
}
}
================================================
FILE: rollup.config.js
================================================
import svelte from 'rollup-plugin-svelte';
import resolve from '@rollup/plugin-node-resolve';
import commonjs from '@rollup/plugin-commonjs';
import { terser } from 'rollup-plugin-terser';
const fs = require('fs')
const path = require('path')
function genConfig(size, include_svelte_lib, minify) {
let inp = `index-${size}.js`
//ensure only the components specified are included.
var content = fs.readFileSync(inp, 'utf-8');
let components = []
content.replace(/from '(.*?)'/gmi, (match, fname) => {
components.push(path.resolve(__dirname, fname));
return ''
})
return {
input: inp,
output: {
format: 'esm',
name: 'app',
file: `public/build/bundle-${size}-${include_svelte_lib ? '-lib' : '-nolib'}${minify ? '-min' : '-nomin'}.js`
},
external: (id, parent, isResolved) => {
if (id == 'svelte') return !include_svelte_lib;
if (id.startsWith('svelte/')) return !include_svelte_lib;
if (id.includes('svelte/internal')) return !include_svelte_lib;
if (!id.startsWith('.')) return true;
let abs = path.resolve(path.dirname(parent), id)
return components.indexOf(abs) < 0;
},
plugins: [
svelte({
// enable run-time checks when not in production
dev: false,
// we'll extract any component CSS out into
// a separate file - better for performance
css: css => {
css.write(`public/build/bundle-${size}.css`);
}
}),
// If you have external dependencies installed from
// npm, you'll most likely need these plugins. In
// some cases you'll need additional configuration -
// consult the documentation for details:
// https://github.com/rollup/plugins/tree/master/packages/commonjs
resolve({
browser: true,
dedupe: ['svelte']
}),
commonjs(),
minify && terser()
]
};
}
let configs = []
let sizes = [1,5,10,20,30,40,50,60,70]
sizes.forEach(size => {
configs = configs.concat([
genConfig(size, false, false),
genConfig(size, false, true),
genConfig(size, true, false),
genConfig(size, true, true)
]);
});
export default configs
================================================
FILE: rollup.config.react.js
================================================
import resolve from '@rollup/plugin-node-resolve';
import commonjs from '@rollup/plugin-commonjs';
import babel from '@rollup/plugin-babel';
import { terser } from 'rollup-plugin-terser';
const fs = require('fs')
const path = require('path')
function genReactConfig(size, minify) {
let inp = `index-${size}-react.js`
//ensure only the components specified are included.
var content = fs.readFileSync(inp, 'utf-8');
let components = []
content.replace(/from '(.*?)'/gmi, (match, fname) => {
components.push(path.resolve(__dirname, fname));
return ''
})
return {
input: inp,
output: {
format: 'esm',
name: 'app',
file: `public/build/bundle-react-${size}-${minify ? '-min' : '-nomin'}.js`
},
external: (id, parent, isResolved) => {
if (!id.startsWith('.')) return true;
if (id.includes('@babel/runtime')) return true;
let abs = path.resolve(path.dirname(parent), id)
return components.indexOf(abs) < 0;
},
plugins: [
babel({
babelHelpers: "runtime",
plugins:
["@babel/plugin-transform-runtime", "@babel/plugin-transform-react-jsx", "@babel/plugin-syntax-class-properties"]
}),
// If you have external dependencies installed from
// npm, you'll most likely need these plugins. In
// some cases you'll need additional configuration -
// consult the documentation for details:
// https://github.com/rollup/plugins/tree/master/packages/commonjs
resolve({
browser: true
}),
commonjs(),
minify && terser()
]
};
}
let configs = []
let reactSizes = [1,5,10,20,30,40,50]
reactSizes.forEach(size => {
configs = configs.concat([
genReactConfig(size, false),
genReactConfig(size, true),
]);
});
export default configs
gitextract_8fw9pmo2/ ├── .gitignore ├── README.md ├── build-chart.js ├── build-chart.preact.js ├── build-chart.react.js ├── makeindexs-react.js ├── makeindexs.js ├── package.json ├── rollup.config.js └── rollup.config.react.js
SYMBOL INDEX (12 symbols across 7 files)
FILE: build-chart.js
function getTotalScriptSize (line 18) | function getTotalScriptSize(index) {
function fileSize (line 35) | function fileSize(fname) {
FILE: build-chart.preact.js
function getTotalScriptSize (line 19) | function getTotalScriptSize(index) {
function fileSize (line 30) | function fileSize(fname) {
FILE: build-chart.react.js
function getTotalScriptSize (line 19) | function getTotalScriptSize(index) {
function fileSize (line 30) | function fileSize(fname) {
FILE: makeindexs-react.js
function shuffleArray (line 8) | function shuffleArray(array) {
function fileAsComponentName (line 16) | function fileAsComponentName(fname) {
FILE: makeindexs.js
function shuffleArray (line 8) | function shuffleArray(array) {
function fileAsComponentName (line 16) | function fileAsComponentName(fname) {
FILE: rollup.config.js
function genConfig (line 8) | function genConfig(size, include_svelte_lib, minify) {
FILE: rollup.config.react.js
function genReactConfig (line 8) | function genReactConfig(size, minify) {
Condensed preview — 10 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (16K chars).
[
{
"path": ".gitignore",
"chars": 271,
"preview": "/node_modules/\n/public/build/\n\n.DS_Store\nindex-1.js\nindex-5.js\nindex-10.js\nindex-20.js\nindex-30.js\nindex-40.js\nindex-50."
},
{
"path": "README.md",
"chars": 3958,
"preview": "# Will it Scale? - Finding Svelte's Inflection Point\n\nfrom [#2546](https://github.com/sveltejs/svelte/issues/2546)\n> The"
},
{
"path": "build-chart.js",
"chars": 1418,
"preview": "\nconst childProcess = require('child_process')\nconst fs = require('fs')\n\nconst component_counts = [1,5,10,20,30,40,50,60"
},
{
"path": "build-chart.preact.js",
"chars": 1487,
"preview": "\nconst childProcess = require('child_process')\nconst fs = require('fs')\n\nconst component_counts = [1,5,10,20,30,40,50]\n\n"
},
{
"path": "build-chart.react.js",
"chars": 1525,
"preview": "\nconst childProcess = require('child_process')\nconst fs = require('fs')\n\nconst component_counts = [1,5,10,20,30,40,50]\n\n"
},
{
"path": "makeindexs-react.js",
"chars": 1004,
"preview": "const fg = require('fast-glob')\nconst fs = require('fs')\nconst sizes = [1,5,10,20,30,40,50,60,70]\nconst dirs = ['../reac"
},
{
"path": "makeindexs.js",
"chars": 854,
"preview": "const fg = require('fast-glob')\nconst fs = require('fs')\nconst sizes = [1,5,10,20,30,40,50,60,70]\nconst dirs = ['../svel"
},
{
"path": "package.json",
"chars": 807,
"preview": "{\n \"name\": \"svelte-app\",\n \"version\": \"1.0.0\",\n \"scripts\": {\n \"build\": \"rollup -c\",\n \"dev\": \"rollup -c -w\",\n "
},
{
"path": "rollup.config.js",
"chars": 2064,
"preview": "import svelte from 'rollup-plugin-svelte';\nimport resolve from '@rollup/plugin-node-resolve';\nimport commonjs from '@rol"
},
{
"path": "rollup.config.react.js",
"chars": 1732,
"preview": "import resolve from '@rollup/plugin-node-resolve';\nimport commonjs from '@rollup/plugin-commonjs';\nimport babel from '@r"
}
]
About this extraction
This page contains the full source code of the halfnelson/svelte-it-will-scale GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 10 files (14.8 KB), approximately 4.3k tokens, and a symbol index with 12 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.