I'm splitting these off into separate changes that could be made to Remix that I think would make it more flexible and provide more value.
Remix (any many other tools right now) contains what I'll call "magic exports":
<picture size-hint="100% 550px"> | |
<source src="/images/hero~640x550@1x.jpg" width="640" height="550" resolution="1x"/> | |
<source src="/images/hero~640x550@2x.jpg" width="1280" height="1100" resolution="2x"/> | |
<source src="/images/hero~768x550@1x.jpg" width="768" height="550" resolution="1x"/> | |
<source src="/images/hero~768x550@2x.jpg" width="1536" height="1100" resolution="2x"/> | |
<source src="/images/hero~1024x550@1x.jpg" width="1024" height="550" resolution="1x"/> | |
<source src="/images/hero~1024x550@2x.jpg" width="2048" height="1100" resolution="2x"/> | |
<source src="/images/hero~1280x550@1x.jpg" width="1280" height="550" resolution="1x"/> | |
<source src="/images/hero~1280x550@2x.jpg" width="2560" height="1100" resolution="2x"/> | |
<source src="/images/hero~1536x550@1x.jpg" width="1536" height="550" resolution="1x"/> |
Personally I've never liked how tools like Remix or NextJS have mapped a nested file system to routes. Simple things like "I want to put this component in its own file" become annoying tasks.
I've always been a fan of "flatter" file systems, my files often look like this:
/App/
function t(){let t=new Set;return{listen:e=>(t.add(e),()=>{t.delete(e)}),emit(){t.forEach((t=>t()))}}}function e(){return Math.random().toString(36).substring(2,8)}function n(t,e,n){return Math.min(Math.max(t,e),n)}function r(t,e){return(t.startsWith(e)?"":e)+t}function a({pathname:t,search:e,hash:n}){return{pathname:r(t,"/"),search:r(e,"?"),hash:r(n,"#")}}function s({pathname:t,search:e,hash:n}){return t+("?"===e?"":e)+("#"===n?"":n)}function h(t){return s(a(t))}function u(t){let[e,n=""]=t.split("#"),[r,s=""]=e.split("?");return a({pathname:r,search:s,hash:n})}function i(t){return s(u(t.substring(1)))}function o(t){if("string"==typeof t)return t;{let{pathname:e="",search:n="",hash:r=""}=t;return h({pathname:e,search:n,hash:r})}}function l(t){return{location(){return e=t.path(),n=t.state(),r=t.key(),{...u(e),state:n,key:r};var e,n,r},push(e,n){let r=o(e);t.push(r,n)},replace(e,n){let r=o(e);t.push(r,n)},go(e){t.go(e)},back(){t.go(-1)},forward(){t.go(1)},listen:e=>t.listen(e)}}function p(n){let r=n.history,a=t |
function capitalize(locale, string) { | |
let segmenter = new Intl.Segmenter(locale, { granularity: "grapheme" }) | |
let result = "" | |
for (let item of segmenter.segment(string)) { | |
if (item.index === 0) { | |
result += item.segment.toLocaleUpperCase(locale) | |
} else { | |
result += item.segment | |
} |
I asked on twitter which symbols are hardest to type on non-US keyboards.
I didn't get a ton of responses, but I think it was clear which ones were most problematic.
char | count | visual | notes |
---|---|---|---|
& |
4 | #### | |
^ |
10 | ########## | Swedish: Dead Key, German: Typing vowels after becomes â |
// Destructuring works on arrays, sets, object, but not maps. | |
// | |
// Today [array, destructuring] works on sets because it | |
// uses [Symbol.iterator] | |
// | |
// But {object, destructuring} *can't* call and iterator | |
// because it doesn't have an order to work with. | |
// | |
// But this difference can lead to confusion for beginners, | |
// and makes maps less usable for everyone. |
// Synchronously check if a promise has already been fulfilled | |
Promise.isFulfilled(promise) | |
// >> true | false | |
// This allow you to make decisions synchronously | |
if (Promise.isFulfilled(promise)) { | |
// We know we're not taking a "risk" awaiting this promise | |
await promise | |
} else { | |
// i.e. Avoid "flash of loading spinner" |
// Syntax proposal: | |
spawn { | |
await somethingAsync() | |
} | |
// `spawn` would be available wherever `await` is available | |
async function fn() { | |
await somethingAsync() | |
spawn { /* ... */ } | |
} |
This has been moved to https://github.com/jamiebuilds/proposal-object-has