理解前端工程化

AaronLin發表於2024-04-28

最初對前端的觀感:眼花繚亂,各種各樣的工具鏈以及其對應的配置檔案、VS Code 外掛,各種技術百家爭鳴,選擇眾多。後來才理解前端不同於後端,後端程式碼的執行環境相對可控,而前端程式碼執行在使用者裝置上,所以需要相容不同的環境,而很大一部分的工具、配置都是解決相容性的問題

TL;DR

工程化的目的:降低開發成本提高開發效率
方式:解決前端三大件(HTML, CSS, JS)存在的問題並對其進行增強,JS 透過 Babel 而 CSS 可以透過 Sass, Less, PostCSS 等工具實現進行增強,並且保證輸出向後相容的的 JS 或 CSS 程式碼

模組化、包管理

分解聚合:拆分複雜任務,降低複雜度(分而治之)

模組化解決 問題:1. 全域性汙染 2. 依賴管理 等等
JS 模組化標準(常用):1. CommonJS (Node 標準)2. ES modules(JavaScript 官方標準模組化方案)
實現:1. 瀏覽器只支援 ESM 2. Node 和 構建工具 上面兩種標準都支援

包 (package) 管理:npm(Node.js的標準包管理器),還有其他的 pnpm 和 yarn 等

JS 工具鏈

JS 語言本身一直都在繁榮地發展,經常出現新的 API 和 語言特性,但是使用者的執行環境(瀏覽器、Node等)的版本可能是五花八門的,可能會導致報錯、相容性等的問題,所以最樸素的解決方式就是把 JS 都轉換為向後相容的老版本 JS 程式碼。前端的執行環境更多的是在使用者這邊,這點不同於後端能比較自由地調整伺服器執行環境,這可能就是前端縫縫補補的原因吧,修補主要有的方式:

  1. 新 API:使用 Polyfill(填充物),為其實現缺少的 API,例如 core-js 庫,就實現了 ArrayflatMap 方法,這樣在舊版本的 Node 環境,也可使用該方法
  2. 新語法:例如 Promise,對於這樣的語法糖,就無法直接為其編寫方法,需要轉換程式碼,有點類似翻譯,透過 regenerator 庫可以將含有 Promise 的程式碼轉換為向後相容的程式碼

有很多這樣的庫用於解決某個特定的相容性問題,一個個匯入很麻煩,所以就有了 Babel,可以透過 Babel 的外掛整合這些轉換程式碼的庫,需要安裝對應的 Babel 外掛依賴 並在 babel.config.js 中配置 plugins。這樣還是很麻煩,所以我們可以直接使用 Babel 的預設,其中最常用的就是:@babel/preset-env,安裝依賴以後完成以下的 babel.config.js 配置,即可開箱即用:

// common js
module.exports = {
    presets: [
        // 預設名稱 & 配置
        ['@babel/preset-env', {
            targets: {
                edge: '17',
                firefox: '60',
                chrome: '67',
                safari: '11.1'
            },
            // 按需匯入 polyfill,未使用的 API 不匯入
            useBuiltIns: 'usage',
            corejs: '3.37.0',
        }]
    ]

    // 外掛的配置方式
    // plugins: [
    //     '@babel/plugin-transform-optional-chaining'
    // ]
}

有了這種思維之後,就可以透過 轉換程式碼 的方式任意地增強 JS 的能力,就像:JSXTypeScript ,它們最終還是會被編譯為純 JS 程式碼

CSS 工具鏈

CSS 語法缺失(邏輯、函式等等),無法進行復雜的操作,所以就有了 CSS 預編譯器:Less, Sass 等等的,與 JS 的處理方式一樣,可以透過工具對其進行轉換,轉換為最樸素的 CSS,這樣就沒有相容性的問題。解決了相容性問題還需要解決 CSS 本身的問題:

  1. 瀏覽器字首 ( vendor prefixes ):類似 -webkit- 開頭的樣式 ,可以透過 autoprefixer 來自動新增瀏覽器字首以確保網頁在不同瀏覽器中的相容性
  2. 壓縮:減少 CSS 檔案的大小,從而提高網頁載入速度,相關的庫 cssnano
  3. 剪枝:移除沒有用到的 CSS,相關的庫:purgecss
  4. 類名衝突:透過 css module 來實現,相關的庫:postcss-modules

與處理 JS 的 Babel 類似,CSS 也有工具整合了上面這些工具,它就是PostCSS,安裝需要的 依賴後,還需要配置 postcss.config.js。與 Babel 類似,它也可以開箱即用,需要安裝依賴並配置 postcss-preset-env

module.exports = {
  map: false,
  plugins: {
    tailwindcss: {},
    'postcss-preset-env': {},
  },
};

構建工具和腳手架

開發和執行的程式碼不一致,開發階段我們希望工程程式碼可以方便地開發維護,而在對於生產執行的程式碼,我們則希望它相容性強、檔案小、載入快等等。這中間就需要打包工具來進行轉換,常用的打包工具有:webpack,它的主要作用:

  1. 模組化管理:使得專案結構清晰、依賴關係明確
  2. 打包編譯:將各個模組按照其依賴關係進行打包編譯,將它們轉換為瀏覽器可識別的靜態資原始檔
  3. 資源最佳化:壓縮 JavaScript、CSS、圖片等檔案,以減小檔案體積,提高載入速度
  4. 程式碼分割:實現按需載入,提高頁面載入效能
  5. 開發伺服器:自動編譯並執行服務(熱更新),便於開發
  6. Source Map:儲存了編譯後程式碼與原始碼之間的對映關係,便於除錯程式碼

BabelPostCSS 相似,一旦有很多細碎的東西出現,就必然有工具可以進行整合並提供預設,對於整個程式碼工程來說,它就是腳手架:vue-cli, vite 等等,提供了互動式的介面輔助生成工程模版

參考資料

ECMAScript 6 入門 - 阮一峰
工程化大師課
What is @babel/preset-env and why do I need it?
postcss 結合 tailwindcss
前端技術的十八年風雨(2006-2024)

相關文章