CEO of Limit-LAB 喜欢鼓捣底层的代码,意图改变世界

Why I am against Single-Page App (SPA)


Nowadays, more and more single-page websites claim that you can use them just by opening the webpage! And more and more frameworks are trying to write in this way. However, as a rebellious and stubborn person, I strongly oppose this.

User Experience#

Those who have used Meituan, Ele.me, Taobao, and Alipay know it very well.

The experience is extremely poor.

Is the webpage really cross-platform?#

As we all know, HTML5, CSS3, JS262, WebAssembly, and WebGPU are all browser standards. Some follow the standards, some establish the standards, some adhere to the factual standards, and some completely deviate from the standards. Moreover, the newer the technology standard, the more chaotic its implementation and the more chaotic the standard itself. The more bizarre the UB (Undefined Behavior) that deviates from the standard. Therefore, these SPAs will use various polyfills and node modules to try to solve this problem. Whether it is the polyfill.js of yesterday, Babel, or the eslint of today, along with the birth of more and more front-end tools, front-end community projects often bring high expectations and ever-changing so-called workflows.

Front-end developers have to change their frameworks every two years to keep up with the times, which is often very painful. Traditional app developers such as Qt and Gtk, or Android, Winform, etc., do not change as frequently as the web. You can even run GUI software developed with Delphi on the latest Windows 11, or software written for Windows 3 using Turbo Pascal's direct call to WinAPI.

But your previous era's Flash ActionScript can no longer be loaded in today's browsers.

Is the security really better?#

Unlike traditional apps, SPAs not only need to maintain their own set of lifecycle components in this small webpage but also ensure high rendering speed and handle data interaction with the backend. Let's not talk about its performance issues, even security becomes particularly tricky.

We all know that sometimes we use cookies and web storage (of course, some browsers do not support it well 😄) to store various session data to authenticate that you are indeed you. However, there are various XSS attack methods, and XSS attacks have even become the largest attack method after buffer overflow attacks (oh my Apple, your M1 encryption chip was hacked by shellcode on the first day). Let's not talk about the impact on the server, let's talk about the impact on the client.

If a script can obtain your cookies and successfully guess the pattern of your cookies and make certain modifications to make the backend think that you are really logged in, then any data in your account will become very dangerous.

Secondly, for the backend, many SPAs reduce the backend's workload by using front-end validation. We also know that JS is a crappy language. In case you encounter a brain-dead developer who does not strictly validate certain information, a creative user can enter this information in the username...

This used to be one of my favorite things to do, and I successfully brought down many PHP websites.

This is also a big threat to the backend. We also know that JS, this crappy language, has eval. We can even perform XSS, injection, and eval in the username...

If the local app developer is well-trained and uses various obfuscation techniques to resist reverse engineering, it will pose a great challenge to this type of attack. However, SPAs are faced with browsers that can be opened with just an F12 key, which greatly reduces the learning cost for hackers.

Is sacrificing performance really not a big deal?#

I have to say, Google engineers, you are amazing. You can JIT this pile of crap called JS to such an extent.

But we know that the APIs provided by the native operating system are often written in native languages such as C/C++, Swift, and ObjC. Even if these languages are crappy, they can at most achieve the speed of the best optimized C (3x). However, JS, although it is so fast (5xC), the browser not only builds an abstraction layer on top of it. First, there is 2D drawing. The browser uses Skia (Chrome), and the default 2D drawing provided by Windows is GDI or more comprehensive APIs such as DirectX. Skia will translate its own calls into OpenGL/Vulkan that provides similar functions, and then use platforms like Angle to achieve cross-platform calls. This is only at the rendering level.

In terms of multi-threading, JS itself is a single-threaded language and does not have any synchronization semantics. WebWorker, this rudimentary interface, is often inadequate for complex requirements. Here we can see that HHLAB's CPU computing performance is far behind major scientific computing frameworks. Let's ignore the algorithmic issues for now. Native languages like C/C++ have MPI to wield SIMD and multi-core big sticks. Why do you think you can compete with them?

What about my Bluetooth, USB devices, and peripherals?#

In reality, although most software does not directly access hardware or the interfaces to hardware have been well-developed, there are still some software that needs to interact with drivers, such as the hardware wallets of blockchain wallets that have recently become popular.

Now our Chrome is about to abandon NAPI, I don't know what will be used in the future to communicate with USB ports or Bluetooth on the local machine.

Some may say, oh, you can use the JS interface for USB and Bluetooth!

Let me show you how difficult these interfaces are!

First, let's look at compatibility.

Then let's look at the bizarre syntax.

let button = document.getElementById('request-device');
button.addEventListener('click', async () => {
  let device;
  try {
    device = await navigator.usb.requestDevice({ filters: [{
        vendorId: 0xABCD,   // well...
        classCode: 0xFF,    // okay
        protocolCode: 0x01  // fine! You win
    while (true) {
      let result = await device.transferIn(1, 6);

      if (result.data && result.data.byteLength === 6) {
        console.log('Channel 1: ' + result.data.getUint16(0)); // Look at this beautiful raw data
        console.log('Channel 2: ' + result.data.getUint16(2));
        console.log('Channel 5: ' + result.data.getUint16(4));

      if (result.status === 'stall') {  // Look at this stupid string
        console.warn('Endpoint stalled. Clearing.');
        await device.clearHalt(1); // Look at this convulsive await
  } catch (err) {
    // No device was selected.

  if (device !== undefined) {
    // Add |device| to the UI.

At present, there should not be many companies that have implemented this interface. This is the specification document.

And what if you want to connect to a USB device on Windows? (Unix-like devices including Android use libusb)

You can easily find the documentation you want by simply consulting MSDN, and write beautiful C# code using Visual Studio, and debug it freely without any limitations on functionality.

protected override async void OnLaunched(LaunchActivatedEventArgs args){
    // Find vid and pid
    UInt32 vid = 0x045E;
    UInt32 pid = 0x078F;

    string aqs = UsbDevice.GetDeviceSelector(vid, pid);

    var myDevices = await Windows.Devices.Enumeration.DeviceInformation.FindAllAsync(aqs, null);
    if (myDevices.Count == 0){
        ShowError("Device not found!");

    UsbDevice device = await UsbDevice.FromIdAsync(myDevices[0].Id);

    // Control signal
    UsbSetupPacket initSetupPacket = new UsbSetupPacket() { 
        Request = initRequest,
        RequestType = new UsbControlRequestType()
            Recipient = UsbControlRecipient.DefaultInterface,
            ControlTransferType = UsbControlTransferType.Vendor 
   await device.SendOutControlTransferAsync(initSetupPacket);

Bluetooth... Do you want to use the web to operate Bluetooth?

Forget about it!

Then don't even mention PCIe devices.

JS language was not originally designed for writing apps. It is only thanks to the cross-platform rendering consistency provided by the current DOM system that everyone wants to write software that can run on various platforms with less effort.#

Personally, I still advocate using webpages as platforms for displaying and exchanging information. Other functionalities do not necessarily have to be implemented by browsers. Frameworks written in native languages for the operating system or cross-platform languages are far superior to front-end technologies in terms of usability and security.

The reason for the emergence of SPAs is not because the native platform lacks functionality, but because in terms of usability, native operating systems and GUI software vendors have not made efforts to optimize the learning curve for users and developers. Fewer people know how to use them, and naturally, fewer software is developed, resulting in unsatisfactory results.

What I hope to see is that I can quickly obtain the information I need on a webpage within one second, rather than waiting for the webpage to load various components and directories like an app.


Ownership of this post data is guaranteed by blockchain and smart contracts to the creator alone.