1. 程式人生 > 其它 >前端之變(三):變革與突破

前端之變(三):變革與突破

本週,我將繼續就前端之變闡述自己的思考,這一次講到前端之變的重點:變革與突破

這是前端之變系列的第三篇文章,前兩篇分別是:

  1. 前端之變(一):技術的變與不變
  2. 前端之變(二):不變的前端

同樣,在具體說到前端究竟發生了哪個改變前,我們要理解變化的本質原因是什麼

前端之困:被限於瀏覽器的支援中

回到上一篇我講的不變前端中,我在文章中明顯的指出了,前端的變化會有一個分界線,在這個分界線之前,前端有一個最大的困境,就是:

前端技術始終被限制在瀏覽器的範圍之內,無法突破

無論是HTML,CSS或是JS,它們的能力永遠限制在瀏覽器這個容器內,當然前些年流行的JQuery,Boostarp這一類的技術框架也是這樣,如果認真分析,會發現它們的能力始終在瀏覽器之內。

我們可以逐一分析前端的核心技術來窺視這種能力限制。

HTML

html主要是來展現內容的技術,最簡單的一個HTML如下:

<!DOCTYPE html>
<html>
<head>
<title>html示例</title>
</head>
<body>
  <h1>Hello,Html</h1>
</body>
</html>

如果我們把HTM與非前端的一些技術框架,比如後端的FreeMarker指令碼技術相類比

<html>
<head>
  <title>freemarker示例</title>
</head>
<body>
  <h1>Welcome ${user}!</h1>
  <p>Our latest product:
  <a href="${latestProduct.url}">${latestProduct.name}</a>!
</body>
</html>

顯而易見,如果我們拋開JS的能力,單純就HTML來說,它的不足與限制非常明顯

  • 本身不具備動態渲染能力,簡單的變數,if,for迴圈完全做不到。
  • 難以將一個複雜的頁面拆成不同的小頁面來實現。一個頁面就是一個HTML,甚至在一個HTML中引入另一個HTML中這種簡單的事都做不到(不依賴JS)

根本原因在於,瀏覽器只提供了根據HTML內容渲染出頁面展現使用者的能力,瀏覽器並未向HTML提供任何動態能力,如基本的if,else,for等能力支援。HTML不可能脫離瀏覽器而發展出任何類似的能力。

這也是為什麼前些年,頁面是由後端技術把持的原因所在,單純的HTML能力實在太差,就算結合JS的動態能力,也根本無法應對複雜頁面。大而劃小,分而治之在那個時候對前端來說是壓根不可能做到的事情。

JavaScript

當然,瀏覽器是用另一種方案來解決這個問題的,也就是JavaScript,由於HTML本身只能做內容展現,其能力實在有限,解決方案是,提供一種指令碼語言,這就是JavaScript的來源。

JavaScript最初的設想非常簡單,提供一些瀏覽器客戶行為支援,以避免昂貴的服務端渲染,比如提交資料前驗證資料是否完整,準確等。基於這種簡單的設想,JavaScript的設計也非常簡單,就做成了一個簡單的指令碼式語言,沒有塊級作用域、模組、子型別等現代語言的一些特性。

出於這種最初的設計的原因,JavaScript於是始終表現的不像一個現代語言,其各種設計與語言特性,用好聽的詞來形容就是:"別樹一幟"。

我們可以將Java與Swift去比較,也可以與OC,Kotlin去比較,因為它們很像,都屬於同一陣營。但與JavaScript相比,沒有任何必要,因為沒法比較。

事實上,JavaScript連一種基本的能力在很長的時間內都不具備:

在一個JS中引入另一個JS

終於在ES6的時代,JavaScript設計與引入了modules的概念,支援import了。

但如我在上一篇文章所講,真正來說,現在網際網路的主流還是ES5,而不是ES6。

原因在於:瀏覽器不支援

CSS

再來說,CSS是樣式。CSS的能力與HTML基本一致,就是簡單的樣式定義

body {
  background-color: lightblue;
}

h1 {
  color: white;
  text-align: center;
}

與HTML一樣,在CSS的世界中

  • 沒有任何動態能力,if,for等基本語法不被支援
  • 談不上將複雜的樣式大而劃小,分而治之。當然你可以將一個CSS拆成很多小CSS,但第一它們相互之間無法引用,只能統一被HTML引用,更者也談不上相互之間存在任何繼承,介面或抽象實現等概念,比如定義一個基本色,在其它CSS中引用這個基本色,這個在CSS中居然都無做到,因為CSS沒有變數的概念

所以,我們可以明顯看出,在『前』前端的時代,前端各種技術發展的能力始終受限於瀏覽器的支援。被困於瀏覽器之中。瀏覽器因為安全的問題,甚至連讀取本地作業系統檔案的能力都不會提供給這些技術。

由於瀏覽器提供的能力有限,這就造成了前端始終難以發展現能與其它現代語言相比的語言設計與框架,比如

  • 面向物件的能力特性,繼承,封裝,多型在前端技術中不知道如何實現
  • 很像將一些設計原則應用到前端,如單例,工廠,觀察者等
  • 談不上在應對複雜軟體時的核心解決方案:『大而劃小,分而治之』

當然,這些已經成為過去式,由於一個本質的突破,就是

突然有一天,前端發現自己的技術不再受到瀏覽器的限制

突破,與瀏覽器說拜拜

終於,在越過一條明顯的分界線後,前端技術的發展出現了突破:

雖然在最終產物階段,仍受限於瀏覽器,但在編碼階段,技術的發展與能力與瀏覽器再無關聯

由於不再受到瀏覽器的限制,前端的技術開始突飛猛進,五花八門,包括但不限於:

  • 由於JavaScript比較糟糕,出現了TypeScript這樣的與Java現代化語言非常相近的技術替代JavaScript
  • 在HTML方向,出現了React,Vue等元件式的框架
  • 為應對複雜樣式的需要,演進出了具備程式設計能力的樣式,如less,sass等

我們還是從前端的三個核心技術逐一分析

HTML

React與Vue等類似框架在編碼階段徹底取代了單純的HTML,一個簡單的React的頁面可能是這樣:

const numbers = [1, 2, 3, 4, 5];
const listItems = numbers.map((number) =&gt;
  </p><li>{number}</li>
); 
ReactDOM.render(
  <ul>{listItems}</ul>,
  document.getElementById('root')
);

就算從上面簡單的程式碼也可以看出,與HTML相比,React等這些技術能做到

  • 支援基本的程式設計能力,if,for等都可以使用
  • 支援元件化能力,把一個大的頁面拆成不同的元件與頁面。

比如在PCX中,對於聊天,聊天分很多種類,比如文字,圖片,語音,在React中,你可以將這個複雜的頁面大而劃小,分而治之

如上圖所示:每一種訊息類別 ,使用一個獨立的子類來實現。

這種就完全具備了現代化語言的能力。在以前的HTML+JS的時代,完全沒有辦法做到。

JavaScript

在『後』前端的階段,並不能說JavaScript是被TypeScript取代了,現狀只能說是TypeScript更流行,越來越受到歡迎。但JavaScript仍然大量存在,仍然是不可替代的。

TypeScript雖然最終仍然被翻譯成JavaScript,它也無法取代JavaScript,但相比JavaScript,TypeScript對前端仍然具有里程碑的意義,從某種程度上說:

TypeScript使得前端第一次也具有了面向物件的語言

export class SessionRepository extends ISessionRepository {


    protected getRepository():IRepository{
        return BaseRepository.getInstance().getRepository();
    }
  
     /**
     * 刪除一個會話
     */
    public async deleteSession(sessionId:string):Promise<boolean>{
        const deleteSQL = "delete from session_ where identifier = $sessionId";
        return this.getRepository().executeUpdate(deleteSQL,{
            $sessionId:sessionId
        });
    }

}

上面的TS程式碼來自於我在20年的PCX中的程式碼片段。

我們可以完全看到,相比於JavaScript,TypeScript更像Java。如果讓一個後端Java人員和一個前端JavaScript人員同時來學習,Java人員會學習的更快,因為TypeScript是類似Java的面向物件的語言。

理所當然的,包括面向物件的五大基本原則:

  • 單一職責原則
  • 里氏替換原則
  • 開閉原則
  • 依賴倒轉原則
  • 介面隔離原則

以及大家熟悉的二十多種設計模式,如工廠模式,觀察者模式,命令模式等,在TypeScript都可以沒有障礙的使用。

但在JavaScript的語言中,至少我不太清楚要怎麼才能做到。

CSS

在『後』前端時代,由於突破了瀏覽器的限制,自然出現了更好的css的替代者。

比如less

其實less總體上與css基本一致,它也並未提供任何新的css樣式,它的區別只是在單純的靜態CSS樣式基礎上,添加了一些動態能力,比如變數,函式等

@width: 10px;
@height: @width + 10px;

#header {
  width: @width;
  height: @height;
}

.class {
  //通過函式來計算
  width: percentage(@width); // returns `50%`
  color: saturate(@base, 5%);
  background-color: spin(lighten(@base, 25%), 8);
}

更多

即然突破了瀏覽器,那自然整體技術發展也不會只侷限在HTML,JS以及CSS三個維度了,因為沒有了瀏覽器的限制,在編碼階段,前端出現了更多的突破性的技術,最典型的代表就是:npm依賴管理

其實,區分你是在『前』前端階段,還是在『後』前端階段的一個最簡單的識別手段就是:

你是否使用了npm依賴管理

因為:

在『前』前端階段,這個是絕無可能做到的。npm依賴管理需要大量的讀取及分析本地檔案,在這個基礎之上才能做到

{
  "name": "taoofcode",
  "version": "1.0.0",
  "private": true,
  "description": "微言碼道",
  "author": "lingen.liu",
  "keywords": [
    "gatsby"
  ],
  "license": "0BSD",
  "dependencies": {
    "@fika/gatsby-source-cockpit": "^1.1.2",
    "@material-ui/core": "^4.11.2",
    "@material-ui/icons": "^4.11.2",
    "@material-ui/lab": "^4.0.0-alpha.57",
    "@mdx-js/mdx": "^1.6.22",
    "@mdx-js/react": "^1.6.22",
    "@types/react-helmet": "^6.1.0",
    "gatsby": "^2.26.1",
    "gatsby-image": "^2.8.0",
    "gatsby-plugin-css-modules-typings": "^1.0.1",
    "gatsby-plugin-google-analytics": "^2.9.0",
    "gatsby-plugin-less": "^4.4.0",
    "gatsby-plugin-manifest": "^2.9.1",
    "gatsby-plugin-material-ui": "^2.1.10",
    "gatsby-plugin-mdx": "^1.7.1",
    "gatsby-plugin-react-helmet": "^3.7.0",
    "gatsby-plugin-sharp": "^2.11.2",
    "gatsby-plugin-sitemap": "^2.9.0",
    "gatsby-remark-prismjs": "^3.10.0",
    "gatsby-source-filesystem": "^2.8.1",
    "gatsby-transformer-remark": "^2.13.1",
    "gatsby-transformer-sharp": "^2.9.0",
    "prismjs": "^1.22.0",
    "react": "^16.13.1",
    "react-dom": "^16.13.1",
    "react-helmet": "^6.1.0"
  }
}

現在,你通過npm來申明與管理你的各種依賴了。

這會令你想到什麼?在其它方向都有自己的依賴管理

  • 後端是使用maven或gradle來進行依賴管理
  • iOS最流行的是cocoapods
  • Android是gradle來管理依賴

看到沒,前端終於和其它技術方向站在同一起跑線上了。

轉換技術

我在前面的文章也說過,前端其實並未改變,它仍然主要是由HTML,JS以及CSS組成。

在『後』前端階段,編碼已經發生了極大的改變,但最終產物仍然是這三個,並未改變。

那究竟它是怎麼做到的?

那就是依賴--轉換技術

由於突破了瀏覽器的限制,使得一切皆有可能,那當然也可以新增翻譯這個能力。因此前端出現了一些翻譯轉換技術,它們的作用就是將前端各種花式的新技術的玩意轉換成HTML,CSS,JS三個東西。

也就是,事實上,不管前端有了多少新技術,概念,最終仍然依賴於轉換技術,仍然需要轉換成HTML,JS以及CSS。

也就是:

  • React,Vue這些程式碼只存在於編碼階段,最終它是HTML+JS
  • TypeScript只存在於編碼階段,最終它是JavaScript
  • Less,Sass也同樣只存在於編碼階段,最終它是CSS

是不是很有意思的現象?

主流的轉換技術包括:

  1. babel -- 這是將es6及以上的一些新特性轉換成es5的語法
  2. Webpack -- 它遠比babel複雜,babel只做一件事,webpack則是做一堆事,它會使用ts-loader去轉換typescript,使用less-loader去轉換less,也會使用balbel去轉換es6以上的語法。它有很多外掛。

當然webpack也有一些同等級的技術,但論流行度,還是以Webpack為主。

所以,現在前端開發,基本不可能脫離webpack,有些整合的框架或技術,比如gatsby,你從程式碼中看不到Webpack的存在,但這不代表它不存在,而是被gatsby給隱藏到後面去了。它在Webpack之上,構建了一套自己的規則,使得開發人員不用關心WebPack的配置而已。

另外,create-react-app也是這種方式。

前端,王者的歸來

我們不得不去詢問一個問題?

這一切究竟是如何發生的?

從『前』前端階段到『後』前端階段,是誰讓這一切發生了?

下一篇繼續,前端之變(四):王者歸來


訪問【微言碼道】官方網站https://taoofcode.cc- 用我們微小的力量傳播編碼之道