[{"data":1,"prerenderedAt":507},["ShallowReactive",2],{"project-39815976":3},{"id":4,"name":5,"line":6,"line_source":7,"title":8,"url":9,"domain":10,"maker":11,"posted_at":12,"year":13,"points":14,"comments":15,"rank_in_year":16,"shown_in_year":17,"top":18,"tier":19,"category":20,"subcategory":21,"format":22,"keywords":23,"reception":28,"sentiment":29,"stance_mix":30,"scored_comments":35,"aspects":36,"strip":43,"post_text":45,"what":46,"said":65,"maker_in_thread":158,"shape":171,"grid":175,"attempts":469,"same_week":470,"maker_shows":31,"maker_hidden":499,"reader_version":500,"card":501},"39815976","Nano-web","a low latency one binary webserver designed for serving SPAs","title","Show HN: Nano-web – a low latency one binary webserver designed for serving SPAs","https:\u002F\u002Fgithub.com\u002Fradiosilence\u002Fnano-web","github.com","antihero",1711373024,2024,157,115,533,3515,16,"notable","infrastructure","web server","other",[24,25,26,27],"spa webserver","single binary server","static file server","runtime config injection","mixed",-0.354,{"positive":31,"neutral":32,"mixed":33,"critical":34},3,14,0,13,30,{"idea":37,"performance":39,"execution":42},{"positive":38,"critical":31},2,{"positive":40,"critical":41},1,6,{"positive":33,"critical":31},[33,31,40,33,33,31,40,33,33,33,40,40,40,40,33,31,31,33,33,31,33,33,33,33,40,40,40,33,44,40,40,33,33,31,44,44,33,31,33,40],5,"I'd found that whilst there's a lot of good options out there for webservers, I was looking for something that is a single deployable binary for usage with containers or unikernels and solves some of the problems that you get with other setups like nginx.\n\nIt uses a single compiled binary, it's going to have extremely low latency on account of caching all files in memory at runtime, and also the fun feature and really useful that's good for SPAs (e.g. Vite) or things like Astro is that you can inject configuration variables into it at runtime and access them from within your frontend code, so ",{"problem":47,"audience":57,"pricing":57,"motivation":58,"time_to_build":57,"stack":62,"openness":63,"stage":64,"team_size":64},{"value":48,"source":49,"evidence":50},"Serving SPAs from containers or unikernels with runtime config and client-side routing support","maker",[51,53],{"id":52},"post",{"id":54,"by":55,"text":56},"39820972","__jonas","> So like, if you're on my-spa.com, and click a link to a post, the JS loads the post and updates the URL, but doesn't perform a full page load. So while you might be on…",null,{"value":59,"source":49,"evidence":60},"Wanted a single deployable binary for containers or unikernels that avoids nginx setup problems",[61],{"id":52},[],"open_source","unknown",{"praise":66,"objections":75,"requests":104,"questions":112,"alternatives":129},[67],{"value":68,"source":69,"evidence":70},"Readable C code","commenter",[71],{"id":72,"by":73,"text":74},"39817925","cdaringe","actually readable C. kudos",[76,91,97],{"value":77,"source":69,"evidence":78},"SPA mode returns 200 for missing routes, which breaks 404 semantics and DAST scans",[79,83,87],{"id":80,"by":81,"text":82},"39818480","Sohcahtoa82","> SPA_MODE when set to 1 404 request will return \u002Fpublic\u002Findex.html as a 200. oof, as someone who frequently has to run DAST tools, returning a 200 for something that should be a…",{"id":84,"by":85,"text":86},"39819642","eddd-ddde","If I make a typo and get a 200 for some url that doesn't actually exist, my browser will now happily suggest that url when I'm typing something in the future. Is there a benefit…",{"id":88,"by":89,"text":90},"39820278","shkkmo","You only have to serve a 200 and the index for valid routes to have frontend routing working. The complaint is serving a 200 for invalid routes, which breaks all kinds of things…",{"value":92,"source":69,"evidence":93},"Returning 200 for every route is poor practice for SPAs",[94],{"id":95,"by":89,"text":96},"39820486","> What's available now that superceds them? The mostly same stuff as before, but slightly better. SPAs were a fad that got very popular, but they were generally a poor solution…",{"value":98,"source":69,"evidence":99},"Binary size and image size larger than minimal alternatives",[100],{"id":101,"by":102,"text":103},"39820586","lipanski","If this is the nano version then let me share the pico alternatives with you: * BusyBox httpd [1] * thttpd [2] * Lwan Web Server [3] * gatling [4] I built and maintain a super…",[105],{"value":106,"source":69,"evidence":107},"Add an option to return 404 for unknown routes",[108],{"id":109,"by":110,"text":111},"39817337","gwbas1c","> SPA mode to service 404s as index (200) to support client side routing. Be careful: SPAs can handle 404s client-side. All you need to do is continue to return the 404 result…",[113,119],{"value":114,"source":69,"evidence":115},"How the server knows which SPA routes are valid",[116],{"id":117,"by":55,"text":118},"39818548","But if it's an SPA, how else would you handle this case? How is the webserver supposed to know in advance which URLs the SPA is able to handle?",{"value":120,"source":69,"evidence":121},"Whether CloudFront really lacks index page support in subdirectories",[122,126],{"id":123,"by":124,"text":125},"39817149","Brajeshwar","Can you elaborate \"CloudFront doesn't support index pages in subdirectories\" and how does it not work? I'm not much into them these days but if I remember correctly in the 4-5…",{"id":127,"by":11,"text":128},"39817954","When was this added? I recall several years ago having to do this with edge lambdas. IE the it would happily resolve \u002F to \u002Findex.html would be fine, but if you wanted to do…",[130,141,145,152],{"value":131,"source":69,"evidence":132},"nginx",[133,137],{"id":134,"by":135,"text":136},"39819527","synergy20","how about civetweb? or lighttpd? both are well known and field tested, light weight and as portable as you need. what are the different features needed for serving SPA comparing…",{"id":138,"by":139,"text":140},"39817351","jazzjazz","Neat idea! We did a blog post around just using nginx for something similar. Which is to say NGINX serving SPA.…",{"value":142,"source":69,"evidence":143},"BusyBox httpd, thttpd, lwan, gatling",[144],{"id":101,"by":102,"text":103},{"value":146,"source":69,"evidence":147},"redbean",[148],{"id":149,"by":150,"text":151},"39816916","EGreg","I like the idea! Have you seen redbean, which is a universal binary and serves static files from a zipfile? How does this compare to that? Honestly, I think that the current Web…",{"value":153,"source":69,"evidence":154},"Caddy",[155],{"id":156,"by":55,"text":157},"39820323","> How are you implementing SPAs in a way that you can't return a 404? Not specifically me, but a lot of SPAs have their own routing. So you would go to ```…",{"comments":159,"answered":160,"key":161},18,9,[162,165,168],{"id":163,"text":164},"39819089","This is an opinionated approach that is out of scope really I think. Though if it works for you, awesome!",{"id":166,"text":167},"39820840","Yeah I mean SPAs still make lots of sense for web based applications, of which there are many. They make bugger all sense for websites, of course. I wouldn’t say they are…",{"id":169,"text":170},"39819966","Well client side routing is fundamentally broken unless you do serve a 200 and the index",{"commenters":172,"max_depth":160,"maker_replies":159,"first_comment_mins":173,"lifespan_hours":174},63,77,72,[176,178,180,184,187,189,192,195,198,201,203,204,207,210,211,213,215,216,219,222,223,226,227,228,232,234,236,238,241,243,245,249,252,254,256,259,262,265,268,270,272,274,276,279,282,286,288,291,294,297,300,303,306,308,310,314,316,319,321,324,327,329,332,335,338,340,343,346,349,351,355,357,360,362,365,368,370,372,375,378,381,383,387,389,392,395,397,400,402,404,405,408,409,411,413,416,419,420,424,428,430,432,435,437,439,442,446,449,453,457,459,460,463,465,467],[80,33,33,177,81,33],"commenter\u002Fcritical\u002Fexecution",[117,33,33,179,55,33],"commenter\u002Fneutral\u002Fidea",[181,33,31,182,183,33],"39818901","project\u002Fneutral\u002Fidea","phanimahesh",[185,33,31,182,186,33],"39818943","ch_sm",[163,33,33,188,11,40],"maker\u002Fneutral\u002Fnone",[190,33,33,191,89,33],"39820321","commenter\u002Fneutral\u002Fnone",[193,33,40,194,55,33],"39821246","project\u002Fcritical\u002Fidea",[196,33,33,191,197,33],"39821740","withinboredom",[199,33,33,191,200,33],"39823287","boredtofears",[202,33,33,191,81,33],"39820002",[156,33,33,179,55,33],[205,33,33,191,206,33],"39820339","fragmede",[208,33,33,209,55,33],"39820480","other\u002Fneutral\u002Fidea",[95,33,33,209,89,33],[212,33,33,179,81,33],"39820513",[54,33,31,214,55,33],"maker\u002Fneutral\u002Fidea",[166,33,33,214,11,40],[217,33,33,209,218,33],"39820466","MrJohz",[220,33,33,179,221,33],"39818581","hombre_fatal",[84,33,40,194,85,33],[224,33,33,179,225,33],"39819885","shawabawa3",[169,33,33,214,11,40],[88,33,33,179,89,33],[229,33,33,230,231,33],"39820330","commenter\u002Fcritical\u002Fidea","egeozcan",[233,33,33,214,11,40],"39820802",[235,33,33,209,85,33],"39821199",[237,33,33,182,11,40],"39837330",[239,33,33,240,81,33],"39820442","other\u002Fneutral\u002Fnone",[242,33,33,214,11,40],"39819120",[101,40,40,244,102,33],"project\u002Fcritical\u002Fperformance",[246,40,31,247,248,33],"39821027","project\u002Fneutral\u002Fperformance","Solvency",[250,40,31,182,251,33],"39821138","joekrill",[109,38,40,253,110,33],"project\u002Fcritical\u002Fexecution",[255,38,33,214,11,40],"39817904",[257,38,40,253,258,33],"39817914","kijin",[260,38,33,179,261,33],"39819325","leptons",[263,38,40,253,264,33],"39819798","traverseda",[266,38,33,191,267,33],"39819916","treve",[269,38,40,194,89,33],"39820364",[271,38,33,179,261,33],"39822457",[273,38,33,230,89,33],"39823612",[275,38,33,191,261,33],"39830471",[277,38,33,240,278,33],"39821892","floydnoel",[280,31,31,182,281,33],"39817180","qwerty456127",[283,31,31,284,285,33],"39817292","project\u002Fneutral\u002Fnone","supriyo-biswas",[287,31,31,284,281,33],"39817343",[289,31,31,284,290,33],"39817301","ricardobeat",[292,31,33,240,293,33],"39819365","busfahrer",[295,31,33,240,296,33],"39820502","rmbyrro",[298,31,33,299,231,33],"39820414","other\u002Fpositive\u002Fnone",[301,31,33,302,281,33],"39835763","commenter\u002Fcritical\u002Fnone",[304,31,33,240,305,33],"39817367","rkeene2",[72,31,33,307,73,33],"other\u002Fpositive\u002Fexecution",[309,31,33,240,305,33],"39819483",[311,31,31,312,313,33],"39820061","project\u002Fneutral\u002Fexecution","xprueg",[315,31,33,240,305,33],"39821073",[317,31,33,240,318,33],"39817539","beklein",[320,31,33,299,85,33],"39820298",[322,31,33,209,323,33],"39817571","kragen",[325,31,33,240,326,33],"39817699","Alifatisk",[328,31,33,284,11,40],"39817898",[330,31,33,191,331,33],"39818716","PhilippGille",[333,31,33,191,334,33],"39818757","dclowd9901",[336,31,33,191,337,33],"39818985","KomoD",[339,31,33,191,334,33],"39851141",[341,31,33,240,342,33],"39819470","Borg3",[344,31,33,191,345,33],"39819543","adrianlv512",[347,31,33,191,348,33],"39821152","dns_snek",[350,31,33,191,345,33],"39822353",[352,353,40,244,354,33],"39817916",4,"ngrilly",[356,353,33,247,11,40],"39818010",[358,353,40,244,359,33],"39818298","pvg",[361,353,33,247,11,40],"39819168",[363,353,33,364,359,33],"39819334","commenter\u002Fneutral\u002Fperformance",[366,353,33,367,354,33],"39824879","other\u002Fneutral\u002Fperformance",[369,353,40,244,264,33],"39819844",[371,353,33,364,11,40],"39820871",[373,353,33,367,374,33],"39818141","andai",[376,353,33,191,377,33],"39818158","binary132",[379,353,33,364,380,33],"39818363","MR4D",[382,353,33,367,374,33],"39827027",[384,353,44,385,386,33],"39818264","project\u002Fpositive\u002Fperformance","tempnow987",[388,353,33,364,354,33],"39818568",[390,353,40,244,391,33],"39818559","fabrice_d",[393,353,31,247,394,33],"39818729","dspillett",[396,353,33,182,11,40],"39819194",[398,353,40,244,399,33],"39823647","pier25",[401,353,33,364,354,33],"39824932",[403,353,33,364,399,33],"39829113",[123,44,33,240,124,33],[406,44,33,240,407,33],"39817439","VWWHFSfQ",[127,44,33,240,11,40],[410,44,33,240,124,33],"39818047",[412,44,33,385,11,40],"39818071",[414,44,33,240,415,33],"39817596","lukevp",[417,44,33,240,418,33],"39818730","somethingAlex",[138,41,31,182,139,33],[421,422,33,240,423,33],"39819619",7,"RiverCrochet",[425,426,44,427,326,33],"39817738",8,"project\u002Fpositive\u002Fidea",[429,426,33,284,11,40],"39817929",[431,426,31,188,326,33],"39817990",[433,426,33,434,11,40],"39818036","project\u002Fneutral\u002Fdocs",[436,426,44,427,326,33],"39818366",[438,426,33,240,11,40],"39820904",[440,160,33,240,441,33],"39817637","varbhat",[443,444,33,240,445,33],"39816964",10,"i_have_to_speak",[447,444,33,240,448,33],"39818222","todotask",[450,451,33,240,452,33],"39819578",11,"debarshri",[454,455,31,247,456,33],"39820160",12,"password4321",[458,455,33,284,11,40],"39820891",[149,34,33,240,150,33],[461,34,33,240,462,33],"39818768","vundercind",[464,34,33,240,150,33],"39819314",[466,34,33,240,462,33],"39820461",[134,32,40,468,135,33],"project\u002Fcritical\u002Fnone",[],[471,476,481,486,491,495],{"id":472,"name":473,"points":474,"category":475},"39783223","Memories",797,"productivity",{"id":477,"name":478,"points":479,"category":480},"39778570","Dropflow",404,"dev_tools",{"id":482,"name":483,"points":484,"category":485},"39836630","Explanations",391,"learning_science",{"id":487,"name":488,"points":489,"category":490},"39807912","Glossarie",363,"languages",{"id":492,"name":493,"points":494,"category":480},"39816836","Jampack",328,{"id":496,"name":497,"points":498,"category":480},"39793513","magick.css",305,false,"v2",{"id":502,"name":5,"line":6,"ai":499,"cat":20,"year":13,"points":14,"comments":15,"rec":28,"s":503,"top":18,"kw":504,"maker":11,"domain":10,"tier":19,"attempts":33,"strip":505,"url":9,"mix":506,"praise":68,"objection":77,"sub":21},39815976,-0.35,[24,25,26,27],"0310031000111103300300001110511003550301",[31,32,33,34],1793991087377]