8,037 Matching Annotations
  1. Mar 2023
    1. ```js var name = 'Alfred'; var age = 47;

      function greet(){ console.log(arguments[0]); console.log(arguments[1]); console.log(arguments[2]); } greetI'm ${name}. I'm ${age} years old.; ```

    1. ```js // Set up some pub/sub on the server

      import { EventEmitter } from "events"; export let emitter = new EventEmitter();

      // Set up an event stream with cleanup and queues // and stuff that subscribes to it and streams the // events when new stuff comes through:

      import { emitter } from "../some-emitter.server";

      type InitFunction = (send: SendFunction) => CleanupFunction; type SendFunction = (event: string, data: string) => void; type CleanupFunction = () => void;

      export function eventStream(request: Request, init: InitFunction) { let stream = new ReadableStream({ start(controller) { let encoder = new TextEncoder(); let send = (event: string, data: string) => { controller.enqueue(encoder.encode(event: ${event}\n)); controller.enqueue(encoder.encode(data: ${data}\n\n)); }; let cleanup = init(send);

        let closed = false;
        let close = () => {
          if (closed) return;
          cleanup();
          closed = true;
          request.signal.removeEventListener("abort", close);
          controller.close();
        };
      
        request.signal.addEventListener("abort", close);
        if (request.signal.aborted) {
          close();
          return;
        }
      },
      

      });

      return new Response(stream, { headers: { "Content-Type": "text/event-stream" }, }); }

      // Return the event stream from a loader in // a resource route:

      import { eventStream } from "./event-stream";

      export let loader: LoaderFunction = ({ request }) => { return eventStream(request, send => { emitter.addListener("messageReceived", handleChatMessage);

      function handleChatMessage(chatMessage: string) {
        send("message", chatMessage);
      }
      
      return () => {
        emitter.removeListener("messageReceived", handleChatMessage);
      };
      

      }); };

      // Push into the event emitter in actions:

      import { emitter } from "./some-emitter.server";

      export let action: ActionFunction = async ({ request }) => { let formData = await request.formData(); emitter.emit("messageReceived", formData.get("something"); return { ok: true }; };

      // And finally, set up an EventSource in the browser

      function useEventSource(href: string) { let [data, setData] = useState("");

      useEffect(() => { let eventSource = new EventSource(href); eventSource.addEventListener("message", handler);

      function handler(event: MessageEvent) {
        setData(event.data || "unknown");
      }
      
      return () => {
        eventSource.removeEventListener("message", handler);
      };
      

      }, []);

      return data; } ```

    1. ```js

      window.onSpotifyIframeApiReady = (IFrameAPI) => { let element = document.getElementById('embed-iframe'); let options = { uri: 'spotify:episode:7makk4oTQel546B0PZlDM5' }; let callback = (EmbedController) => {}; IFrameAPI.createController(element, options, callback); }; ```

    1. ```js // Adds an entry to the event log on the page, optionally applying a specified // CSS class.

      let currentTransport, streamNumber, currentTransportDatagramWriter;

      // "Connect" button handler. async function connect() { const url = document.getElementById('url').value; try { var transport = new WebTransport(url); addToEventLog('Initiating connection...'); } catch (e) { addToEventLog('Failed to create connection object. ' + e, 'error'); return; }

      try { await transport.ready; addToEventLog('Connection ready.'); } catch (e) { addToEventLog('Connection failed. ' + e, 'error'); return; }

      transport.closed .then(() => { addToEventLog('Connection closed normally.'); }) .catch(() => { addToEventLog('Connection closed abruptly.', 'error'); });

      currentTransport = transport; streamNumber = 1; try { currentTransportDatagramWriter = transport.datagrams.writable.getWriter(); addToEventLog('Datagram writer ready.'); } catch (e) { addToEventLog('Sending datagrams not supported: ' + e, 'error'); return; } readDatagrams(transport); acceptUnidirectionalStreams(transport); document.forms.sending.elements.send.disabled = false; document.getElementById('connect').disabled = true; }

      // "Send data" button handler. async function sendData() { let form = document.forms.sending.elements; let encoder = new TextEncoder('utf-8'); let rawData = sending.data.value; let data = encoder.encode(rawData); let transport = currentTransport; try { switch (form.sendtype.value) { case 'datagram': await currentTransportDatagramWriter.write(data); addToEventLog('Sent datagram: ' + rawData); break; case 'unidi': { let stream = await transport.createUnidirectionalStream(); let writer = stream.getWriter(); await writer.write(data); await writer.close(); addToEventLog('Sent a unidirectional stream with data: ' + rawData); break; } case 'bidi': { let stream = await transport.createBidirectionalStream(); let number = streamNumber++; readFromIncomingStream(stream, number);

          let writer = stream.writable.getWriter();
          await writer.write(data);
          await writer.close();
          addToEventLog(
              'Opened bidirectional stream #' + number +
              ' with data: ' + rawData);
          break;
        }
      }
      

      } catch (e) { addToEventLog('Error while sending data: ' + e, 'error'); } }

      // Reads datagrams from |transport| into the event log until EOF is reached. async function readDatagrams(transport) { try { var reader = transport.datagrams.readable.getReader(); addToEventLog('Datagram reader ready.'); } catch (e) { addToEventLog('Receiving datagrams not supported: ' + e, 'error'); return; } let decoder = new TextDecoder('utf-8'); try { while (true) { const { value, done } = await reader.read(); if (done) { addToEventLog('Done reading datagrams!'); return; } let data = decoder.decode(value); addToEventLog('Datagram received: ' + data); } } catch (e) { addToEventLog('Error while reading datagrams: ' + e, 'error'); } }

      async function acceptUnidirectionalStreams(transport) { let reader = transport.incomingUnidirectionalStreams.getReader(); try { while (true) { const { value, done } = await reader.read(); if (done) { addToEventLog('Done accepting unidirectional streams!'); return; } let stream = value; let number = streamNumber++; addToEventLog('New incoming unidirectional stream #' + number); readFromIncomingStream(stream, number); } } catch (e) { addToEventLog('Error while accepting streams: ' + e, 'error'); } }

      async function readFromIncomingStream(stream, number) { let decoder = new TextDecoderStream('utf-8'); let reader = stream.pipeThrough(decoder).getReader(); try { while (true) { const { value, done } = await reader.read(); if (done) { addToEventLog('Stream #' + number + ' closed'); return; } let data = value; addToEventLog('Received data on stream #' + number + ': ' + data); } } catch (e) { addToEventLog( 'Error while reading from stream #' + number + ': ' + e, 'error'); addToEventLog(' ' + e.message); } }

      function addToEventLog(text, severity = 'info') { let log = document.getElementById('event-log'); let mostRecentEntry = log.lastElementChild; let entry = document.createElement('li'); entry.innerText = text; entry.className = 'log-' + severity; log.appendChild(entry);

      // If the most recent entry in the log was visible, scroll the log to the // newly added element. if (mostRecentEntry != null && mostRecentEntry.getBoundingClientRect().top < log.getBoundingClientRect().bottom) { entry.scrollIntoView(); } } ```

    1. Put that TS code in a file your app imports, for example, in remix.env.d.ts, and now the type of name will be the expected one.

      ts declare module "@remix-run/server-runtime" { export interface AppLoadContext { name: string; } }

    1. ```js /! devtools-detect https://github.com/sindresorhus/devtools-detect By Sindre Sorhus MIT License / const devtools = { isOpen: false, orientation: undefined, };

      const threshold = 170;

      const emitEvent = (isOpen, orientation) => { globalThis.dispatchEvent(new globalThis.CustomEvent('devtoolschange', { detail: { isOpen, orientation, }, })); };

      const main = ({ emitEvents = true } = {}) => { const widthThreshold = globalThis.outerWidth - globalThis.innerWidth > threshold; const heightThreshold = globalThis.outerHeight - globalThis.innerHeight > threshold; const orientation = widthThreshold ? 'vertical' : 'horizontal';

      if ( !(heightThreshold && widthThreshold) && ((globalThis.Firebug && globalThis.Firebug.chrome && globalThis.Firebug.chrome.isInitialized) || widthThreshold || heightThreshold) ) { if ((!devtools.isOpen || devtools.orientation !== orientation) && emitEvents) { emitEvent(true, orientation); }

      devtools.isOpen = true;
      devtools.orientation = orientation;
      

      } else { if (devtools.isOpen && emitEvents) { emitEvent(false, undefined); }

      devtools.isOpen = false;
      devtools.orientation = undefined;
      

      } };

      main({ emitEvents: false }); setInterval(main, 500);

      export default devtools; ```

    1. Thanks to a collaboration with Bloomberg, Babel now supports transforming the "Records and Tuples" stage 2 proposal.The Babel plugin transforms records and tuples syntax using the global Record and Tuple functions:
      Records and Tuples support (#12145)
      <table><tbody style="width:100%;display:table;table-layout:fixed"><tr><th>Input</th><th>Output</th></tr><tr><td><div class="language-js codeBlockContainer_mQmQ theme-code-block" style="--prism-color: #4d4d4c; --prism-background-color: #fdfaeb;"><div class="codeBlockTitle_x_ju">JavaScript</div><div class="codeBlockContent_D5yF">
      <span class="token-line" style="color: rgb(77, 77, 76);"><span class="token keyword" style="color: rgb(137, 89, 168);">let</span><span class="token plain"> data </span><span class="token operator">=</span><span class="token plain"> #</span><span class="token punctuation">{</span><span class="token plain"></span><br></span><span class="token-line" style="color: rgb(77, 77, 76);"><span class="token plain">  </span><span class="token literal-property property">name</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string" style="color: rgb(113, 140, 0);">"Babel"</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line" style="color: rgb(77, 77, 76);"><span class="token plain">  </span><span class="token literal-property property">ids</span><span class="token operator">:</span><span class="token plain"> #</span><span class="token punctuation">[</span><span class="token number" style="color: rgb(245, 135, 31);">1</span><span class="token punctuation">,</span><span class="token plain"> </span><span class="token number" style="color: rgb(245, 135, 31);">2</span><span class="token punctuation">,</span><span class="token plain"> </span><span class="token number" style="color: rgb(245, 135, 31);">3</span><span class="token punctuation">]</span><span class="token plain"></span><br></span><span class="token-line" style="color: rgb(77, 77, 76);"><span class="token plain"></span><span class="token punctuation">}</span><span class="token punctuation">;</span><br></span>
      <div class="buttonGroup_aaMX"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_z5j7" aria-hidden="true"><svg class="copyButtonIcon_FoOz" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_L0B6" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div></td><td><div class="language-js codeBlockContainer_mQmQ theme-code-block" style="--prism-color: #4d4d4c; --prism-background-color: #fdfaeb;"><div class="codeBlockTitle_x_ju">JavaScript</div><div class="codeBlockContent_D5yF">
      <span class="token-line" style="color: rgb(77, 77, 76);"><span class="token keyword" style="color: rgb(137, 89, 168);">let</span><span class="token plain"> data </span><span class="token operator">=</span><span class="token plain"> </span><span class="token function maybe-class-name" style="color: rgb(66, 113, 174);">Record</span><span class="token punctuation">(</span><span class="token punctuation">{</span><span class="token plain"></span><br></span><span class="token-line" style="color: rgb(77, 77, 76);"><span class="token plain">  </span><span class="token literal-property property">name</span><span class="token operator">:</span><span class="token plain"> </span><span class="token string" style="color: rgb(113, 140, 0);">"Babel"</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line" style="color: rgb(77, 77, 76);"><span class="token plain">  </span><span class="token literal-property property">ids</span><span class="token operator">:</span><span class="token plain"> </span><span class="token function maybe-class-name" style="color: rgb(66, 113, 174);">Tuple</span><span class="token punctuation">(</span><span class="token number" style="color: rgb(245, 135, 31);">1</span><span class="token punctuation">,</span><span class="token plain"> </span><span class="token number" style="color: rgb(245, 135, 31);">2</span><span class="token punctuation">,</span><span class="token plain"> </span><span class="token number" style="color: rgb(245, 135, 31);">3</span><span class="token punctuation">)</span><span class="token punctuation">,</span><span class="token plain"></span><br></span><span class="token-line" style="color: rgb(77, 77, 76);"><span class="token plain"></span><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span><br></span>
      <div class="buttonGroup_aaMX"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_z5j7" aria-hidden="true"><svg class="copyButtonIcon_FoOz" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_L0B6" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div></td></tr></tbody></table>
    1. If we want to create an immutable, read only Tuple in Typescript, we can use the readonly keyword when defining our Tuple.

      ts const myArray:readonly[number, string] = [10, 'test'];

    2. Unlike the tuple type in vanilla Javascript, Typescript Tuples by default are mutable - so they can be changed. As such, we can update a Tuple by simply referring to the element we want to update, and redefining it, assuming it isn't a constant:
      Mutating a Typescript Tuple

      ```ts let myTuple:[ string, number ] = [ "some", 15 ]

      myTuple[1] = 20; ```

    3. We can also define an array of Tuples in Typescript. This is done by adding [] to the end of our Tuple type definition:

      ts let myTuple:[ string, number ][] = [ [ "some", 15 ], [ "other", 20 ], [ "tuple", 50 ] ];

    4. ts const myTuple:[ string, number ] = [ "some", 15 ]

    1. The Records & Tuples proposal will enforce immutability, and prevent common state mutation mistakes:

      ```js const Hello = ({ profile }) => { // prop mutation: throws TypeError profile.name = 'Sebastien updated';

      return

      Hello {profile.name}

      ; };

      function App() { const [profile, setProfile] = React.useState(#{ name: 'Sebastien', });

      // state mutation: throws TypeError profile.name = 'Sebastien updated';

      return <Hello profile={profile} />; } ```

    1. Record

      ``js const proposal = #{ id: 1234, title: "Record & Tuple proposal", contents:...`, // tuples are primitive types so you can put them in records: keywords: #["ecma", "tc39", "proposal", "record", "tuple"], };

      // Accessing keys like you would with objects! console.log(proposal.title); // Record & Tuple proposal console.log(proposal.keywords[1]); // tc39

      // Spread like objects! const proposal2 = #{ ...proposal, title: "Stage 2: Record & Tuple", }; console.log(proposal2.title); // Stage 2: Record & Tuple console.log(proposal2.keywords[1]); // tc39

      // Object functions work on Records: console.log(Object.keys(proposal)); // ["contents", "id", "keywords", "title"] ```

      Tuple

      ```js const measures = #[42, 12, 67, "measure error: foo happened"];

      // Accessing indices like you would with arrays! console.log(measures[0]); // 42 console.log(measures[3]); // measure error: foo happened

      // Slice and spread like arrays! const correctedMeasures = #[ ...measures.slice(0, measures.length - 1), -1 ]; console.log(correctedMeasures[0]); // 42 console.log(correctedMeasures[3]); // -1

      // or use the .with() shorthand for the same result: const correctedMeasures2 = measures.with(3, -1); console.log(correctedMeasures2[0]); // 42 console.log(correctedMeasures2[3]); // -1

      // Tuples support methods similar to Arrays console.log(correctedMeasures2.map(x => x + 1)); // #[43, 13, 68, 0] ```

    1. <table><tbody><tr><th colspan="4" rowspan="1">Status</th><th colspan="4" rowspan="1">Description</th></tr><tr><td colspan="5" rowspan="1">HIT</td><td colspan="5" rowspan="1">The resource was found in Cloudflare’s cache.</td></tr><tr><td colspan="5" rowspan="1">MISS</td><td colspan="5" rowspan="1">The resource was not found in Cloudflare’s cache and was served from the origin web server.</td></tr><tr><td colspan="5" rowspan="1">NONE/UNKNOWN</td><td colspan="5" rowspan="1">Cloudflare generated a response that denotes the asset is not eligible for caching. This may have happened because:
    2. A Worker generated a response without sending any subrequests. In this case, the response did not come from cache, so the cache status will be none/unknown.
    3. A Worker request made a subrequest (fetch). In this case, the subrequest will be logged with a cache status, while the main request will be logged with none/unknown status (the main request did not hit cache, since Workers sits in front of cache).
    4. A Firewall rule was triggered to block a request. The response will come from the edge network before it hits cache. Since there is no cache status, Cloudflare will log as none/unknown.
    5. A redirect page rule caused the edge network to respond with a redirect to another asset/URL. This redirect response happens before the request reaches cache, so the cache status is none/unknown.
    6. </td></tr><tr><td colspan="5" rowspan="1">EXPIRED</td><td colspan="5" rowspan="1">The resource was found in Cloudflare’s cache but was expired and served from the origin web server.</td></tr><tr><td colspan="5" rowspan="1">STALE</td><td colspan="5" rowspan="1">The resource was served from Cloudflare’s cache but was expired. Cloudflare could not contact the origin to retrieve an updated resource.</td></tr><tr><td colspan="5" rowspan="1">BYPASS</td><td colspan="5" rowspan="1">The origin server instructed Cloudflare to bypass cache via a Cache-Control header set to no-cache,private, or max-age=0 even though Cloudflare originally preferred to cache the asset. BYPASS is returned when enabling Origin Cache-Control. Cloudflare also sets BYPASS when your origin web server sends cookies in the response header.</td></tr><tr><td colspan="5" rowspan="1">REVALIDATED</td><td colspan="5" rowspan="1">The resource is served from Cloudflare’s cache but is stale. The resource was revalidated by either an If-Modified-Since header or an If-None-Match header.</td></tr><tr><td colspan="5" rowspan="1">UPDATING</td><td colspan="5" rowspan="1">The resource was served from Cloudflare’s cache and was expired, but the origin web server is updating the resource. UPDATING is typically only seen for very popular cached resources.</td></tr><tr><td colspan="5" rowspan="1">DYNAMIC</td><td colspan="5" rowspan="1">Cloudflare does not consider the asset eligible to cache and your Cloudflare settings do not explicitly instruct Cloudflare to cache the asset. Instead, the asset was requested from the origin web server. Use Page Rules to implement custom caching options.</td></tr></tbody></table>
    1. Streaming allows you to break down the page's HTML into smaller chunks and progressively send those chunks from the server to the client.

    1. HTML templating and streaming response library for Worker Runtimes such as Cloudflare Workers.

      js function handleRequest(event: FetchEvent) { return new HTMLResponse(pageLayout('Hello World!', html` <h1>Hello World!</h1> ${async () => { const timeStamp = new Date( await fetch('https://time.api/now').then(r => r.text()) ); return html`<p>The current time is ${timeEl(timeStamp)}.</p>` }} `)); }

    1. js const arr = ["a", "b", "c", "d", "e"]; const arrIter = arr[Symbol.iterator](); console.log(arrIter.next().value); // a console.log(arrIter.next().value); // b console.log(arrIter.next().value); // c console.log(arrIter.next().value); // d console.log(arrIter.next().value); // e