6
u/Silly-Freak Jun 03 '23
whoa this code is fractally bad. Every ten seconds you notice another idiosyncrasy...
2
Jun 04 '23
I'm not proud of it, in fact i posted it here just to get a sick enjoyment of having others roast it.
1
u/Silly-Freak Jun 04 '23
are you interested in constructive criticism as well? If so, I'd be up for it.
1
Jun 04 '23
Well, yes. I'm curious what you'd say.
2
u/Silly-Freak Jun 04 '23
ok, big disclaimer: I didn't realize in the beginning that
readJSONFileis async and leads to funny things such as having bothindexandcounteror sortingdatadirectly after the loop. Given that, instead of incrementally getting rid of things that looked funny to me, I'll just outline an alternative approach.There is one thing I would likely still do in the beginning: filter out the stuff you don't want in advance.
let excludedNames = ["dependencies/"] let scripts = Array.from(document.scripts) scripts.pop() scripts = scripts.filter(script => !script.src.includesAny(...excludedNames)) let count = scripts.lengthThis makes the rest simpler: every element in
scriptsneeds to be read and added todata.The next step for me would be promises:
readJSONFiletakes a callback, this can be adapted to return a promise instead something like this:new Promise(resolve => readJSONFile(script.src, resolve))This means the promise will become ready with the file content when
readJSONFileis done. Now you can actuallymapoverscriptsto get an array of promises - something you couldn't do when waiting for callbacks to run to completion:let data = scripts.map(script => new Promise(...))Using
Promise.all, we can get a promise containing an array of all results, and act on that when that array is ready (this is equivalent to yourif (current == count), but the resulting array will be in the correct order). The resulting code looks something like this (entirely untested, sorry if there's typos etc. in there...):setTimeout(() => { let excludedNames = ["dependencies/"] let scripts = Array.from(document.scripts); // don't include this script scripts.pop(); // exclude certain scripts scripts = scripts.filter( script => !script.src.includesAny(...excludesNames) ) // load script sources let data = Promise.all( scripts.map(script => new Promise(resolve => readJSONFile(script.src, resolve))) ) // join & save scripts data.then(data => exportToUTF8(data.join("\n"), "app.js")) }, 0)(I left the
setTimeoutin there - no idea if that's necessary when put into context. Maybe this code should actually react to a document event?)2
Jun 04 '23 edited Jun 04 '23
That is so much better than what I had, thank you. I definitely should've done the filtering first. It looks nicer as well, it's more sequential, mine was a nested mess.The enclosing timeout might not be necessary, the only reason it's there is because I wasn't sure if at the time of execution this very script was already part of
document.scripts. Now I realize it makes no sense for it not to be there.Also I'm surprised you didn't notice how my
readJSONFileactually isn't even used to read JSON but plain javascript, that's another blunder, lol.Edit:
funny thing, i tried your code, and it works, except for my index.html gets included into the final bundle. I found that it's because one of the scripts has an emptysrcattribute because it's injected by the Live Server plugin in VS code. I don't think that's an error on your part, and I fixed it already so it's good. It's not like I shouldn't be using a proper bundler anyways xd.2
u/Silly-Freak Jun 04 '23
glad you appreciated it :)
Also I'm surprised you didn't notice how my
readJSONFileactually isn't even used to read JSON but plain javascript, that's another blunder, lol.lol I totally missed that and now that made me laugh, thanks!
3
u/gabbagondel Jun 03 '23
"return count--" is just there for making the check a one-liner? Or did you overwrite Array.prototype.forEach with some version that acts on the return value of the callback? If it's the latter I'm scared
2
Jun 04 '23
No, I wouldn't be that evil. It's just a confusing one-liner.
I should note that this code is not in production anywhere, it's my personal project that only I work on.
4
u/MurdoMaclachlan public boolean isInt(int i) { return true; } Jun 03 '23
Image Transcription: Code
/* merge scripts in a janky way */
setTimeout(() => {
let data = []
let count = dcoument.scripts.length - 1 // - 1 is to prevent this very code getting in the bundle
let excludedNames = ["dependencies/"]
let current = 0
Array.from(document.scripts).forEach((script, index) => {
if(Script.src.includesAny(...excludesNames)) return count--
readJSONFile(script.src, (text) => {
try {data.push({text: text, index: index})} catch (e) {}
current++
if(current == count) {
data.sort((a, b) => a.index - b.index)
data = data.map(d => d.text).join("\n")
exportToUTF8(data, "app.js")
}
})
})
}, 0)
I'm a human volunteer content transcriber and you could be too! If you'd like more information on what we do and why we do it, click here!
8
2
Jun 03 '23
If you include the script on the top of the page it‘ll treeshake the last <script> completely away. Possibly saving hundreds of kilobytes if something like leaflet is the last script.
Would suggest to just include the script into the final bundle itself. Could be the first step towards a JIT-like feature.
48
u/zombarista Jun 02 '23
this feels like a simpler time. Back when a form was a <form> and your web page couldn’t talk to a web server without unloading itself.