why do people use typescript in web development

so i saw a youtube video about js engines – https://www.youtube.com/watch?v=p-iiEDtpy6I&t=301s, it was a seminar recording, presented by one of the team members behind the v8 engine itself. One of the topics she discussed about was the dynamic type system of js, and how the particular choice of it is beneficial in web scripting as opposed to in statically typed languages like c, java etc. For example it particularly is advantageous in working with json files, and in scenarios where one may not exactly know the type of the data one is working with beforehand…..

And my doubt is that – like you know we have statically typed variants of js like typescript, and if dynamic typing is actually advantageous then why would people use typed languages like typescript in the first place, and that too when at the end its going to be interpreted as js anyways, atleast in web development…. the only reason i could think of is that typescript is relevant only in general programming tasks…. like i node environments….

Zustand store doesn’t work in monorepo (external package)

We have a set of different webViews they are all independent react apps that can have a shared codebase, but run in an isolated manner (not a microfrontend). We started to build a lerna monorepo repository and split the codebase into different reusable packages.
We have multiple reusable infra zustand stores that will be placed in the shared package and be imported from different applications. Here, we encounter issues. After moving the store into the package, the app stopped loading. I built a test repo to reproduce the issue from the clean repository.
https://github.com/roman-rookout/zustand-package-test

Very basic – a package with a store:

const useTestStore = create<Store>((set) => ({
      count: 0,
    increment: () => set((state) => ({ count: state.count + 1 })),
    decrement: () => set((state) => ({ count: state.count - 1 })),
}));

And usage in the main component

function App() {
     const { count, increment, decrement } = useTestStore();
     ...
     <p>{count}</p>
      <button onClick={() => increment()}>
    ...

What I see, is a warning about “InvalidHooks usage outside of react component” which is weird and “TypeError: Cannot read properties of null (reading ‘useRef’)”.
It points to the row – const { count, increment, decrement } = useTestStore();

Error in console

So any usage of hook will fail also useTestStore((state) => state.count).
Only “non hook” method like useTestStore.getState().count will work.

I would appreciate any input. Maybe we should reconsider the way we bundle the library in Vite.

Things I tried so far:

From research it points out what it could be a duplicate React issue:

  • I have a peer dependency only in the library/package and only one reference to react and zustand from the application itself. I’ve been playing with bundling for a while to make sure I don’t have duplicate versions of packages. Also here is the output of npm list react which shows I am not referencing anything excessive, same applies to zustand and react-dom
    Config in vite

  • I updated vite.config with additional resolvers. Weirdly it changed the error to
    Uncaught TypeError: Cannot read properties of null (reading 'useSyncExternalStore')
    config in vite

  • Tried to install use-sync-external-store package, didn’t help even after playing with adding alias in Vite.

I bet what I am missing is something simple, but literally being stuck for now and it prevents us from moving forward with monorepo. I couldn’t find much information on the internet as well of people using zustand in monorepo which should be a pretty common and trivial thing.

Using the ‘integrity’ attribute for script tags while avoiding CORS errors over the file-uri protocol

I want to build a lightweight single-page app that people can use locally over the file:// protocol (i.e. simply by downloading the project archive file, unpacking it and double clicking on index.html), as well as on the web (https://).

All my dependencies are stored within my project (e.g. in a /js folder), including the third-party libraries I use (namely, AlpineJs and JSZip).

So far so good, it works in both scenarios (file and https).

I also want to use the integrity attribute on the <script> elements, so that users can verify that I did not temper with the code of those libraries. This gives me something like:

<script
  src="js/jszip.min.js"
  integrity="sha512-XMVd28F1oH/O71fzwBnV7HucLxVwtxf26XV8P4wPk26EDxuGZ91N8bsOttmnomcCD3CS5ZMRL50H0GgOHvegtg=="
  crossorigin="anonymous"
  referrerpolicy="no-referrer"
></script>
<script
  src="js/alpinejs.min.js"
  defer
  integrity="sha512-FUaEyIgi9bspXaH6hUadCwBLxKwdH7CW24riiOqA5p8hTNR/RCLv9UpAILKwqs2AN5WtKB52CqbiePBei3qjKg=="
  crossorigin="anonymous"
  referrerpolicy="no-referrer"
></script>

However, as soon as I start using those attributes, the browser throws a CORS error and refuses to load the files, when accessing the app over the file:// protocol:

Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at file:///…/js/jszip.min.js. (Reason: CORS request not http). [Learn More]

I’m not entirely familiar with the crossorigin and referrerpolicy attributes. Reading the doc about them, I didn’t find anything that helped me in this regard. I’m don’t think they are needed. However if I remove them, I get a different error:

“file:///…/js/alpinejs.min.js” is not eligible for integrity checks since it’s neither CORS-enabled nor same-origin.

Is there a way to set it up so that it works both over https:// and file://, while keeping the integrity attribute?

Resolving Unexpected Identifier ‘assert’ SyntaxError in Node.jswhile Importing JSON with ES Modules

I am encountering a SyntaxError: Unexpected identifier 'assert' when attempting to import a JSON file using the assert { type: "json" } syntax in a Node.js project. The issue occurs with the following line of code:

import skiTerms from "./ski-terms.json" assert { type: "json" };

The full error message is:

SyntaxError: Unexpected identifier 'assert'
    at compileSourceTextModule (node:internal/modules/esm/utils:338:16)
    at ModuleLoader.moduleStrategy (node:internal/modules/esm/translators:103:18)
    at #translate (node:internal/modules/esm/loader:437:12)
    at ModuleLoader.loadAndTranslate (node:internal/modules/esm/loader:484:27)
    at async ModuleJob._link (node:internal/modules/esm/module_job:115:19)

I have already set up my project to use ES modules by adding "type": "module" to my package.json, but the error persists. I am using Node.js v23.2.0.

Capacitor Plugin Unable to Communicate Between Bridge to Vue App

I am looking to add the ability for communication between my Main App (ios App) and my Vue/JS code. I want to pass a token from my iOS app to the Vue code. I believe a Custom Plugin would enable me to do this (in reading the documentation here: https://capacitorjs.com/docs/plugins/creating-plugins). I followed the documentation and created a separate repo for the custom plugin.

The Plugin’s logic is to contain a simple get and set method and expose that between the App (Swift codespace) and the Vue App.

Unfortunately every time I attempt to fetch the plugin to grab the token/information stored I get the error in my IOS App (Xcode Debug): Error getting VoIP token: {“code”:”UNIMPLEMENTED”}

Here’s my code:

ios/sources/QuillCapacitorPluginPlugin/QuillCapacitorPlugin.swift:

import Foundation

@objc public class QuillCapacitorPlugin: NSObject {
    // Singleton instance
    @objc public static let shared = QuillCapacitorPlugin()
    
    // Stored variable
    var storedValue: String?
    
    // Method to set the stored value
    @objc public func setStoredValue(_ value: String) {
        self.storedValue = value
    }
    
    // Method to get the stored value
    @objc public func getStoredValue() -> String? {
        return self.storedValue
    }
    
    // Existing echo method
    @objc public func echo(_ value: String) -> String {
        print(value)
        return value
    }
}

ios/sources/QuillCapacitorPluginPlugin/QuillCapacitorPluginPlugin.swift:

import Foundation
import Capacitor

@objc(QuillCapacitorPluginPlugin)
public class QuillCapacitorPluginPlugin: CAPPlugin {
    // Use the shared instance
    private let implementation = QuillCapacitorPlugin.shared
    
    // MARK: - Plugin Methods
    
    @objc func echo(_ call: CAPPluginCall) {
        let value = call.getString("value") ?? ""
        call.resolve([
            "value": implementation.echo(value)
        ])
    }
    
    @objc func setStoredValue(_ call: CAPPluginCall) {
        let value = call.getString("value") ?? ""
        implementation.setStoredValue(value)
        call.resolve()
    }
    
    @objc func getStoredValue(_ call: CAPPluginCall) {
        if let value = implementation.getStoredValue() {
            call.resolve([
                "value": value
            ])
        } else {
            call.reject("No value stored")
        }
    }
}

My index.ts:

import { registerPlugin } from '@capacitor/core';

import type { QuillCapacitorPluginPlugin } from './definitions';

const QuillCapacitorPlugin = registerPlugin<QuillCapacitorPluginPlugin>('QuillCapacitorPlugin', {
  web: () => import('./web').then((m) => new m.QuillCapacitorPluginWeb()),
});

export * from './definitions';
export { QuillCapacitorPlugin };

My definition.ts:

export interface QuillCapacitorPluginPlugin {
  echo(options: { value: string }): Promise<{ value: string }>;
  setStoredValue(options: { value: string }): Promise<void>;
  getStoredValue(): Promise<{ value: string }>;
}

My Appdelegate.swift:


    
    func pushRegistry(_ registry: PKPushRegistry, didUpdate pushCredentials: PKPushCredentials, for type: PKPushType) {
        let voipToken = pushCredentials.token.map { String(format: "%02x", $0) }.joined()
        print("PushKit Token: (voipToken)")
        
        // Store the token
        QuillCapacitorPlugin.shared.setStoredValue(voipToken)
    }
 

My vue/js:

// voipPlugin.js
import { QuillCapacitorPlugin } from 'quill-capacitor-plugin';

export const getStoredVoIPToken = async () => {
  try {
    const result = await QuillCapacitorPlugin.getStoredValue();
    console.log('token is', result);
    return result.token;
  } catch (error) {
    console.error('Error getting VoIP token:', error);
    return null;
  }
};


// Vue Plugin
export const VoIPPlugin = {
  install() {
    console.log('Setting up VoIP Plugin');
    
    // Add method to get token to globalProperties
    getStoredVoIPToken().then((token) => {
        console.log('token is 2', token)
    });
  }
};

The debug log statements print the Set up of the VOIP Plugin after the Swift code grabs the token (so any async behavior shouldn’t occur). It ends up throwing the error in the try catch when it tries to fetch the stored value.

I have tried switching around and adding a timer to the delay in case it was an async issue, but I still ran into the same error above. I double checked that the plugin is included in the Podfile and compiled with the project.

Color gradient as style on marker

I’m trying to add a bottom-to-top color gradient to my markers, but it’s not working as I expected. I also don’t quite agree with the radius * 3 but I didn’t find another solution to let the circle look like a circle yet. Any ideas in how to fix this? Thank you.

const radius= 30;

const style = new Style({
    image: new Circle({
        radius: radius * 3,
        fill: new Fill({
            color: gradient(outerRadius, '#22C55E', '#4ADE80'),
        }),
    }),
});

function gradient(radius: number, color1: string, color2: string) {
    const canvas = document.createElement('canvas');
    const context = canvas.getContext('2d');

    const size = radius * 2;
    canvas.width = size;
    canvas.height = size;

    const gradient = context.createLinearGradient(0, size, 0, 0);
    gradient.addColorStop(0, color1);
    gradient.addColorStop(1, color2);

    context.fillStyle = gradient;
    context.beginPath();
    context.arc(radius, radius, radius, 0, 2 * Math.PI);
    context.fill();

    return context.createPattern(canvas, 'no-repeat');
}

The gray circle in the picture is correctly positioned and it’s fill color is created by using

 fill: new Fill({
      color: 'rgb(52, 69, 76)'
 })

But the gradient circle isn’t:

gradient color on markers

Here’s an example with two markers. A default one which is positioned correctly and a gradient one using the same coordinate. https://jsfiddle.net/zx36h7wy/1/

Is it possible to change a feature of MudExRichTextEdit?

I want to know if it’s possible to change a feature of the extension component MudExRichTextEdit. It’s about the link tooltip in the toolbar, where we can add different stuff or edit the text inside the editor.

The project I am handling recently requires a way to enter links inside the editor, and this extension component already made it possible, so I added it and couldn’t figure it out how it worked. Until I entered a link, selected that link and then the modal dialog appeared, so it could transform that normal “text” to a link.
But that is not so useful for normal users. Is it anyway I can make the modal appear before I select the text? And add the text inside the textarea that the modal shows?

If so I would appreciate the help.
Thank you!

useNavigate error : useNavigate() may be used only in the context of a component

i am using the useNavigate in my middleWare.js to redirect the user to ‘/’
but i am gettin this error saying “useNavigate() may be used only in the context of a component”
i also tried using window.location.href instead of navigate but it always refreshes the page that makes the website so laggy

here is my app.js :

import './App.css';
import { BrowserRouter as Router, Route, Routes, useLocation } from 'react-router-dom';
import Login from './components/Login';
import Callback from './components/CallBack';
import Home from './components/Home';
import ResponsiveAppBar from './components/NavBar';
import Profile from './components/Profile';
import { useEffect, useState } from 'react';
import axios from 'axios';
import { refreshAccessToken } from './spotifyAuth';
import { useAuth } from './middleWare';

function App() {
  const [userData, setUserData] = useState(null);
  const [token, setToken] = useState(localStorage.getItem('spotifyAccessToken'));
  const isAuthenticated = useAuth(); // Use the middleware to check authentication
  const [isLoading, setIsLoading] = useState(true);

  // Fetch User Data
  const fetchUserData = async () => {
    try {
      const response = await axios.get('https://api.spotify.com/v1/me', {
        headers: {
          Authorization: `Bearer ${token}`,
        },
      });
      setUserData(response.data);
    } catch (error) {
      console.error('Error fetching user data:', error);
    }
  };

  // Logout function
  const handleLogout = () => {
    localStorage.removeItem('spotifyAccessToken');
    localStorage.removeItem('spotifyRefreshToken');
    localStorage.removeItem('spotifyTokenExpiry');
    setUserData(null);
    window.location.href = '/';
  };

  // Check Token Expiration
  const checkTokenExpiration = async () => {
    const expiry = localStorage.getItem('spotifyTokenExpiry');
    if (Date.now() >= expiry) {
      try {
        const refreshToken = localStorage.getItem('spotifyRefreshToken');
        const newTokens = await refreshAccessToken(refreshToken);
        localStorage.setItem('spotifyAccessToken', newTokens.access_token);
        localStorage.setItem('spotifyTokenExpiry', Date.now() + newTokens.expires_in * 1000);
        setToken(newTokens.access_token);
      } catch (error) {
        console.error('Error refreshing token:', error);
      }
    }
  };

  useEffect(() => {
    if (isAuthenticated) {
      fetchUserData(); // Fetch user data only if authenticated
    }
    if (isAuthenticated) {
      fetchUserData(); // Fetch user data only if authenticated
    }
    setIsLoading(false); // Set loading to false after checking authentication
  }, [isAuthenticated]);

  const AppWithAppBar = () => {
    const location = useLocation();
    const shouldShowAppBar = location.pathname !== '/';

    return (
      <>
        {shouldShowAppBar && (
          <div style={{ position: 'fixed', width: '100%', top: 0, zIndex: 1000 }}>
            <ResponsiveAppBar handleLogout={handleLogout} />
          </div>
        )}
        <div style={{ paddingTop: shouldShowAppBar ? '64px' : '0px' }}>
          <Routes>
            <Route path="/" element={<Login />} />
            <Route path="/callback" element={<Callback />} />
            {isAuthenticated && (
              <>
                <Route path="/home" element={<Home userData={userData} handleLogout={handleLogout} />} />
                <Route path="/profile" element={<Profile userData={userData} />} />
              </>
            )}
          </Routes>
        </div>
      </>
    );
  };

  // Display loading screen while checking authentication
  if (isLoading) {
    return (
      <div style={loadingContainerStyle}>
        <div style={loadingSpinnerStyle}></div>
        <h2 style={{ color: '#fff' }}>Loading...</h2>
      </div>
    );
  }

  return (
    <Router>
      <AppWithAppBar />
    </Router>
  );
}

const loadingContainerStyle = {
  height: '100vh',
  display: 'flex',
  flexDirection: 'column',
  justifyContent: 'center',
  alignItems: 'center',
  backgroundColor: '#1e1e2f', 
};

const loadingSpinnerStyle = {
  width: '50px',
  height: '50px',
  border: '6px solid #a29bfe', 
  borderTop: '6px solid transparent',
  borderRadius: '50%',
  animation: 'spin 1s linear infinite',
};


const spinnerAnimationStyle = document.createElement('style');
spinnerAnimationStyle.innerHTML = `
  @keyframes spin {
    0% { transform: rotate(0deg); }
    100% { transform: rotate(360deg); }
  }
`;
document.head.appendChild(spinnerAnimationStyle);

export default App;

and my middleWare :

import { useEffect, useState } from 'react';
import { useNavigate } from 'react-router-dom';
import { refreshAccessToken } from './spotifyAuth';

export const useAuth = () => {
  const [isAuthenticated, setIsAuthenticated] = useState(false);
  const navigate = useNavigate();

  useEffect(() => {
    const checkAuth = async () => {
      const token = localStorage.getItem('spotifyAccessToken');
      const expiry = localStorage.getItem('spotifyTokenExpiry');

      if (!token || Date.now() >= expiry) {
        try {
          const refreshToken = localStorage.getItem('spotifyRefreshToken');
          if (refreshToken) {
            const newTokens = await refreshAccessToken(refreshToken);
            localStorage.setItem('spotifyAccessToken', newTokens.access_token);
            localStorage.setItem('spotifyTokenExpiry', Date.now() + newTokens.expires_in * 1000);
            setIsAuthenticated(true);
          } else {
            navigate('/');
          }
        } catch (error) {
          navigate('/');
        }
      } else {
        setIsAuthenticated(true);
      }
    };

    checkAuth();
  }, [navigate]);

  return isAuthenticated;
};

Attaching Files from Google Drive to Email sent in Google Sheets

I have a script in Google Sheets that allows me to send emails with attachments found in a selected folder in Google Drive. It mostly works fine, giving a failed message if there is no email address listed and sends emails with the correct attachment.

The one issue I have is when a file does not exist in the folder and the script stops running. I would rather have it skip and push a message to say file not found so I can investigate the missing files after the bulk is sent.

There are three scripts associated with it, firstly the main one sending the email:

{
  var ss = SpreadsheetApp.getActiveSpreadsheet();
  var sheet1 = ss.getSheetByName('Gas');
  var sheet2 = ss.getSheetByName('Email Gas');
  var subject = sheet2.getRange(2,1).getValue();
  var n = sheet1.getLastRow();

  folderID = displayPrompt("Enter folder ID:");


  for (var i = 2; i < n+1 ; i++ ) {

    var emailAddress = sheet1.getRange(i,3).getValue();
    var Date = sheet2.getRange(6,5).getValue();
    var message = sheet2.getRange(2,2).getValue();
    var documentName = '.xlsx';
    var name = sheet1.getRange (i,2).getValue();
    var finalfile = getFileFromFolder(folderID, name, documentName);
    message=message.replace("<Date>", Date);


    let errors = [];
   
      try{
        MailApp.sendEmail(emailAddress, subject, message, {attachments: [finalfile.getAs(MimeType.MICROSOFT_EXCEL)]});
        errors.push(["Sent"]);
      }catch(err){
        errors.push(["Failed"]);
      }
    

    sheet1.getRange(i,4).setValues(errors);
    
  }
}```


}

the second is a prompt to enter the folderID

function displayPrompt(question) {
  var ui = SpreadsheetApp.getUi();
  var result = ui.prompt(question);
  return result.getResponseText();
}

and lastly the script to get the attachment where I think the error is that is stopping the script when no file is found rather than skipping to the next line:

  var ss = SpreadsheetApp.getActiveSpreadsheet()
  var folder = DriveApp.getFolderById(folderID);
  var files = folder.getFilesByName(filename + docType);
  
  if (files.hasNext()){
    file = files.next();
  }else{
    error.push(["file not found"]);
  }
  

  return file;

}

Does anyone know how I can ammend this to give a message on the sheet to say file not found and skip to the next email?

innerHTML does not render CSS

I was working on project, and I was using JS. I saw that when I add HTML code via innerHTML the page does not render CSS. I do not really know what to do, because I have never seen something like this. How can I solve it ?

Do you guys have any idea ?

function addVideo() {
  const videoForm = document.querySelector("#video-form");
  const videoUploadbox = document.querySelector("#uploadBox");
  const inputs = document.querySelector("#stage-2");

  inputs.innerHTML += videoUploadbox.innerHTML + videoForm.innerHTML;

}
<div class="stage inputs flex flex-col items-center just-between" id="stage-2" style="display: none; transition: .3s all;">
  <div class="upload-box flex flex-col items-center just-center" id="uploadBox">
    <h3 id="loadingText" style="display: none;">Loading...</h3>
    <div id="videoText" class="text flex flex-col items-center just-center">
      <i class="fa-solid fa-film" style="width: 100px;height: 100px;font-size: 100px;"></i>
      <b class="videoName" style="color: #3479F9; font-size: 20px;">Upload Video</b>
      <span style="font-size: 12px;margin-left: 0;">( max 300 MB )</span>

      <video id="video-tag" style="border-radius: 10px; width: 300px; height: 250px; display: none;">
                            <source id="video-source">
                            Your browser does not support the video tag.
                        </video>
    </div>
    <input class="pointer" type="file" accept="video/*" id="videoUpload" multiple />
  </div>

  <div class="course-info-inputs flex flex-col items-center">
    <div id="video-form" class="grid">
      <div class="grid-item flex flex-col">
        <span>Video title <span style="color: tomato; font-weight: 200;">*</span> </span>
        <input type="text" placeholder="Video title here..." id="">
      </div>

      <div class="grid-item flex flex-col" style="margin-left: 0px;display: grid; grid-column: 1/3; grid-row: 2/4;">
        <span>Video description <span style="color: tomato; font-weight: 200;">*</span> </span>
        <textarea style="height: 120px;resize: none;" placeholder="Video description here"></textarea>
      </div>
    </div>

    <div style="width: 300px;" class="buttons flex just-between">
      <button onclick="prevStage(1)" class="cancel pointer">Back</button>
      <button onclick="addVideo()" class="pointer continue">Add video</button>
      <button onclick="nextStage(3)" class="pointer continue">Continue</button>
    </div>
  </div>
</div>

How to fix userscript to remove SDH portion of subtitles on Amazon Video?

I found a userscript on greasyfork that I am trying to change to function on the Amazon Video website. The script was originally for Netflix and I just changed the class name of the subtitles and it worked for Hulu’s site, but for some reason I can’t get it figured out for Amazon’s site. I’ve tried various different class names, but none seem to work. I’m pretty positive this is the correct one to target. Element selector of caption box

// ==UserScript==
// @name        Amazon subtitle cleanup
// @namespace   Violentmonkey Scripts
// @match       https://www.amazon.com/*
// @grant       none
// @version     1.0
// @description Remove all "[inhales]", "[loud noise]" from the subtitles
// @icon        https://upload.wikimedia.org/wikipedia/commons/4/4a/Amazon_icon.svg
// ==/UserScript==

let observed_node = undefined

let kill_song_lyrics = true

const cleanup = (t) => {
  if (kill_song_lyrics && t.includes('♪')) {
    return '' // ignore song lyrics
  } else if (t.includes('[') && t.includes(']')) {
    return t.replace(/(- *)?[[^]]+]/g, '') // (maybe "- ") "[" .. (not "]")+ .. "]"
  } else if (t.includes('(') && t.includes(')')) {
    return t.replace(/(- *)?([^)]+)/g, '') // (maybe "- ") "(" .. (not ")")+ .. ")"
  }

  return t
}

const on_mutated = (changes) => {
  const ts = observed_node.querySelectorAll('atvwebplayersdk-captions-text')
  for (let i = 0; i < ts.length; i++) {

    const t = ts[i].innerHTML
    const nt = cleanup(t)

    if (nt !== t) {
      ts[i].innerHTML = nt
      // console.log({ original: t, filtered: nt })
    }
  }
}

const observer = new MutationObserver(on_mutated)

const reobserve = () => {
  const elems = document.getElementsByClassName('atvwebplayersdk-captions-text')
  if (elems[0] !== undefined) {
    if (observed_node !== elems[0]) {
      observed_node = elems[0]
      console.log({ observed_node })
      observer.observe(observed_node, { childList: true, subtree: true})
    }
  }
  window.setTimeout(reobserve, 100)
}


const run_tests = () => {
  // the tests are lightning fast, so just do run them quickly on every script startup
  const test_cleanup = (source, expected) => {
    console.assert(cleanup(source) === expected, { test_result: false, source, expected, actual: cleanup(source) })
  }
  test_cleanup('normal text', 'normal text')
  test_cleanup('[coughs]', '')
  test_cleanup('[coughs] yeah', ' yeah')
  test_cleanup('-[coughs]', '')
  test_cleanup('- [coughs]', '')
  test_cleanup('- (inhales)', '')
  test_cleanup('some ♪ singing', '')
  console.log('tests ok')
}


console.log('Netflix subtitle filter userscript starting up')
run_tests()
reobserve()

Base64 JPEG image disappearing on page refresh

We have a corporate React Typescript project, in one part of which we scrape images from websites, encode to base64, write to the database and then display to the end-user.

Here is very simplified example of our code, just App.tsx:

const App = (): JSX.Element => {
  const jpgbase64 = "/9j/4AAQSkZJRgABAQAAAQABAA .... nveHWYNjqKqrk5I7zc/wAvhOHaHTwM/wDeA/7BPVLtD+OAIPmZfad";
  const pngbase64 = "iVBORw0KGgoAAAANSU .... lCgQUKJAQIkCASUKBJQoEFCiQECJAgElCgSUKBBQokBAiQIBJQoElCgQUKJAQIkCASUKBJQoEFCiQECJAgElCgSUKBBQokBAiQIBJQoElCgQUKJAQIkCASUKBJQoEFCiQECJAgElCgSUKBBQokBAiQIBJQoElCgQUKJAQIkCASUKBJQoEFCiQECJAgElCgSUKBBQokBAiQIBJQoElCgQUKJAQIkCAaX/AcrFIKL9KpbnAAAAAElFTkSuQmCC";

  return (
    <>
      <span className="fakeHtml">{"<div> with base64 JPEG and PNG <img>s:"}</span>
      <div className="imgHolder">
        <img src={"data:image/jpeg;base64, " + jpgbase64} />
        <img src={"data:image/png;base64, " + pngbase64}  />
      </div>
    </>
  );
};

export default App; 

Both jpgbase64 and pngbase64 are valid base64 strings.

A weird things are: when we open this simple example page in Firefox, initially both images were loaded:

screenshot – first site load

But then if we refresh a page by selecting site address in address bar and then hitting Enter, JPEG image disappears, but PNG is still here!

Then hitting F5 is not returning image back:

screenshot – after refresh.

Please feel free to check this short video of how to reproduce.

Question: how to make JPEG image not to disappear after page refresh?

At the same time, <div className="imgHolder"> is existing in DOM with both images inside; no errors/warnings in the console. Everything except a problem I mentioned seems to be fine.

When we open that simple example page in Chrome, both images loading correctly, even when we refresh a page multiple times.

If just save a page from browser by hitting Ctrl + S, and then open from saved file, everything seems to work fine as well.

Regarding the processing of the model after the conclusion of the clock animation

The animation is over, and the model will disappear or loop, but I want to achieve real-time vehicle trajectory playback. The animation playback is not continuous, and there may be delays. Therefore, during the waiting time for data, I want the model to still be displayed on the map. I don’t understand why the model needs to disappear when the animation ends.

const timeStepInSeconds = 30;
const totalSeconds = timeStepInSeconds * (flightData.length - 1);
const start = Cesium.JulianDate.fromIso8601("2020-03-09T23:10:00Z");
const stop = Cesium.JulianDate.fromIso8601("2020-03-09T24:10:10Z");
// Cesium.JulianDate.addSeconds(
//   start,
//   totalSeconds,
//   new Cesium.JulianDate()
// );
viewer.clock.startTime = start.clone();
viewer.clock.stopTime = stop.clone();
viewer.clock.currentTime = start.clone();
viewer.timeline.zoomTo(start, stop);
// Speed up the playback speed 50x.
viewer.clock.multiplier = 1;
// Start playing the scene.
viewer.clock.shouldAnimate = true;
viewer.clock.clockRange = Cesium.ClockRange.CLAMPED;
// The SampledPositionedProperty stores the position and timestamp for each sample along the radar sample series.
const positionProperty = new Cesium.SampledPositionProperty();
for (let i = 0; i < flightData.length; i++) {
  const dataPoint = flightData[i];
  const time = Cesium.JulianDate.fromIso8601(dataPoint.time);
  const position = Cesium.Cartesian3.fromDegrees(
    dataPoint.longitude,
    dataPoint.latitude,
    dataPoint.height
  );

  positionProperty.addSample(time, position);
  viewer.entities.add({
    description: `Location: (${dataPoint.longitude}, ${dataPoint.latitude},     ${dataPoint.height})`,
    position: position,
    point: { pixelSize: 10, color: Cesium.Color.BLUE },
  });
}

Javascript – promise vs async/await – is it really just syntactic sugar?

Its often said that async/await is just syntactic sugar over promises, and we can re-write code using one approach over other. Lets say I have this piece of code using promises:

async function main() {
    const promise = new Promise((resolve) => {
        return resolve('promise resolved value')
    })

    promise.then((res) => console.log(res))
    console.log('after promise.then()')
}

main().then((res) => console.log('end'))

The output would be:

after promise.then()
promise resolved value
end

which makes sense.
Now the issue I have is if I re-write this code using async/await:

async function main() {
    const asyncFunc = async () => {
        return 'async func resolved value'
    }
    console.log(await asyncFunc())
    console.log('after await asyncFunc()')
}

main().then((res) => console.log('end'))

The order of execution change:

async func resolved value
after await asyncFunc()
end

This is confusing to me, how should I rewrite the code using async/await so I would get the same order of execution?