前端工程化、爲什麼需要工程化

前端工程化

  前端工程化的概念在近些年來逐漸成爲主流構建大型web應用不可或缺的一部分,在此我通過以下這三方面總結一下自己的理解。

  1. 爲什麼需要前端工程化。

  2. 前端工程化的演化。

  3. 怎麼實現前端工程化。

爲什麼需要工程化

  隨着近些年來前端技術的不斷髮展,越來越多複雜的業務放在了前端,前端不再是以前幾個HTML + CSS + javascript就能解決的了。業務複雜了,需要維護的代碼量就自然多了,如此一來,前端代碼的可靠性,可維護性,可拓展性,以及前端web應用的性能,開發效率等等各方面就成了不得不考慮的問題。

  於是我們就產生了前端工程化這個概念,來解決這些問題。現階段的前端工程化,需要考慮到各個方面,包括但不限於以下這幾點:

提升開發效率

  • webpack-dev-server 熱加載
      以前,我們的日常前端開發的流程是這樣的: 修改代碼 -> 切換IDE到瀏覽器 -> 刷新瀏覽器查看效果(有時候還需要清除緩存) -> 修改代碼 ....。

      這套流程,尤其是刷新瀏覽器這個過程,無疑是相當低效繁瑣枯燥的。 而webpack-dev-server 替我們解決了這個問題,它有兩種模式,兩種模式,一種是 watch 模式,功能是你修改代碼,自動幫你刷新頁面,無需手動刷新;另一種更加強大,基於 websocket 全雙工通信技術,直接無刷新幫你把修改的代碼替換掉。 從而極大程度上提高了開發效率。
     

  • 數據mock
      在後端接口還沒提供的時候,前後端制定好共同的接口協議,開發時前端可以使用mock模擬數據,與後端徹底分離,並行開發。面向接口編程,儘可能減少前後端溝通成本。

優化性能

  • 代碼合併壓縮,混淆加密 
     

  • 減少小圖片請求
      webpack中url-loader:loader: 'url-loader?limit=8192',使得小於8kb的圖片使用data:image base64 編碼內聯,減少圖片請求量
     

  • 部署靜態文件緩存管理
      使用webpack的內置的chunkhash功能,可以給生成的js文件添加hash後綴,標識文件版本。

提高代碼質量

  • 模塊化
      主要指 js 代碼的模塊化。以前的前端開發並沒有模塊化這個概念,這給維護大型項目帶來了極大的困難。發展到現在的前端有很多模塊化的方法可供選擇,如seajs ,requirejs, webpack 等。 模塊化能很大程度上提高了代碼的可維護性
     

  • CSS 預處理
      通過sass,less 等css 預處理器,可以實現 css 文件的拆分,顆粒化,實現css可複用。而且通過autoprefixer或postcss 還可以讓 css 樣式對老舊瀏覽器向下兼容。 

      此外,通過使用 css-modules 能夠避免css全局污染的問題,極大提高css代碼的可控性,不需要設定一堆命名空間與命名規範來限制。
     

  • ES6 + babel 編譯
      javascript本身設計存在一定程度上的缺陷,例如“沒有模塊化”,“沒有塊級作用域”,“全局變量污染”,“回調地獄”等等之類的問題,爲了改善這些缺陷,計算機協會在2015年推出了ECMAScript 6 標準(今年已經ES8 已經發布了),使用ES6的語法除了能有效減少代碼量之外,還引入了塊級作用域,模塊化,類的語法糖,promise以及一些新的API,很大程度上填了以前javascript的遺留下的坑,以及提高了代碼質量。

      不過即便過了兩年,ES6也並沒有被市面的主流瀏覽器完全支持,所以我們還需用 babel 將ES6 編譯成ES5,再將一些不支持的API polyfill 處理。
     

  • eslint 代碼檢查
      一直一來,代碼風格都是一場無休止的爭論,每個人都有自己的代碼風格習慣,而這些習慣無非就是tab還是空格,換不換行,加不加空格等等之類的瑣事,與其通過制定規範去強行限制開發者的編寫習慣,不如從工具層面徹底解決代碼風格的問題。eslint可以自動處理一些代碼風格的問題,直接將代碼通過指定的規則格式化,使代碼整體風格統一。 

      更進一步,eslint 還可以禁止代碼的一些可能造成不良影響的行爲(例如eval,未定義變量),使其拋出錯誤。降低代碼產生bug的可能性。
     

  • 單元測試
      集成單元測試,提高代碼可靠性。前端較爲流行的單元測試 mocha,qunit 等
     

  • UI 自動化測試
      UI 自動化測試是 軟件通過模擬瀏覽器,對頁面進行UI操作,判斷是否產生預想的UI效果。目前較爲流行的UI自動化測試套件主要是 基於phantomjs的 nightmare
     

  • web組件化
      web組件化是通過自定義標籤,從UI層面對代碼的拆分,提高前端代碼的可複用性。儘管w3c已經初步對web組件化制定了規範, 但目前瀏覽器對web 組件化的支持慘不忍睹,無法通過原生的方法來實現web組件,但目前流行的前端框架,如vue,angular,react都有提供自己的web組件化,從而提高代碼可複用性

前端工程化的發展

<script> 直接引入加載

  在沒有引入模塊化的概念之前,前端往往需要手動處理js文件的依賴關係,例如;bootstartp 依賴 jquery,就需要在引入bootstrap之前引入jquery

<script src="src/jquery.min.js" ></script>
<script src="src/bootstrap.min.js" ></script>

  如果引入js文件順序錯了則會報錯。 乍一看似乎沒什麼難度呀,是人都能分清是吧。那麼請看下面這種情況:
  有 a.js, b.js, c.js, d.js, e.js 五個文件,其中

  • a 依賴 b和e,

  • b 依賴 d和e,

  • c 依賴 a和d,

  • d 依賴 e,

  • e 無依賴。

  那麼根據以上關係,請按正確順序引入js文件(黑人問號???)。當然,事實上也並不難區分其優先級,逐級遞推就很快可以推斷出引入順序爲 e,d,b,a,c

  毫無疑問,對於稍微複雜點的web工程,存在複雜依賴情況是極有可能發生的,並且把時間耗費在管理依賴關係上也不值當。

  所以就誕生了前端模塊化

模塊化標準(AMD,CMD,ES6 Module)

  經歷了混亂加載的黑歷史,我們終於迎來了js的模塊化,忽如一夜春風來,一夜之間冒出一堆模塊化標準。

  其中具有代表性的模塊加載器分別是是遵循AMD(Asynchronous Module Definition)規範的RequireJS ,還有淘寶玉伯開源的 遵循CMD(Common Module Definition)規範的 SeaJS。 兩者除了遵循規範不一樣之外,封裝模塊有差別之外,都各有所長,而且對舊版本瀏覽器的支持都相當完美。

  當然除了這兩個,還有各類其他開發者開發的模塊加載器,當真是一番羣魔亂舞百家爭鳴的盛世呀。在此就不一一細述了。

  下面有請我們的主角出廠: ES6 Module。 

  ES6 Module 是新一代javascript標準 ECMAScript 6 的新增特性,其語法和Python相似,比較簡潔易用。另外,相比於其他模塊加載器,ES6 Module 是語法級別的實現,其靜態代碼分析相比於其他框架會更快更高效,方便做代碼檢測。

// import 基本語法
import React from 'react';    //等價於 var React = require("react");
import { stat, exists, readFile } from 'fs';
// 等價於 
// var fs = require('fs');
// var stat = fs.stat, exists = fs.exists, readFile = fs.readFile;

  
  而且,且不論其API優劣,其語法與前面說的模塊化有什麼區別的,ES6 Module最大優點是顯而易見的: 它是官方標準,而不是其他妖豔賤貨第三方開發的框架/庫。跟着有名分的原配混,毫無疑問是有前途更穩定的吧。 

  當然,缺點也是很明顯的,不同於RequireJS,SeaJS 向下兼容到極致(ie6+),ES6 Module 的兼容性還未覆蓋絕大部分瀏覽器,支持ES6 Module的瀏覽器寥寥無幾,雖然可以通過babel進行語法轉譯,不過兼容性畢竟是硬傷,唯有時間能治癒。

自動化構建工具(gulp,grunt)

  從描述可知,前端工程化需要做的事情,單憑人力一個一個去處理基本沒有可能完成,那麼,我們就需要學會使用工具,畢竟程序猿和猿之間最大的區別就是會不會使用工具。 

  grunt 和 gulp 就是自動化構建工具。我們通過安裝對應的node_module,根據gulp/grunt 的API編寫相對應的任務(如:css預處理,代碼合併壓縮,代碼校驗檢查等任務,js代碼轉譯),那麼就可以生成我們想要的結果,完成前端工作流管理,極大程度地提高效率。其作用其實就相當於makefile 的make 操作,將手工操作自動化,其任務編寫格式如下。

// gulp scss預處理任務
gulp.task('styles', function() {
  return gulp.src('src/styles/main.scss')
    .pipe(sass({ style: 'expanded' }))
    .pipe(autoprefixer('last 2 version', 'safari 5', 'ie 8', 'ie 9', 'opera 12.1', 'ios 6', 'android 4'))
    .pipe(gulp.dest('dist/assets/css'))
    .pipe(rename({suffix: '.min'}))
    .pipe(minifycss())
    .pipe(gulp.dest('dist/assets/css'))
    .pipe(notify({ message: 'Styles task complete' }));
});

模塊化打包器(webpack)

  前面說了那麼多SeaJS,RequireJS的模塊化 ,又有gulp ,grunt的自動化處理,想必都有點覺得這前端工程化的技術棧也太繁瑣了吧。

  那麼現在,你可以統統不用管啦,讓我們推出終極解決方案:Webpack。  

  相比於seajs / requirejs 需要在瀏覽器引入 sea.js 、require.js 的模塊解析器文件,瀏覽器才能識別其定義的模塊。 webpack不需要在瀏覽器中加載解釋器,而是直接在本地將模塊化文件(無論是AMD,CMD規範還是ES6 Module)編譯成瀏覽器可識別的js文件。 

  另外,相對於gulp/grunt 的批處理工作流功能,webpack 也可以通過 loader、plugin的形式對所有文件進行處理,來實現類似的功能。 

  其主要工作方式是: 整個項目存在一個或多個入口js文件,通過這個入口找到項目的所有依賴文件,通過loader,plugin進行處理後,打包生成對應的文件,輸出到指定的output目錄中。可以說是集模塊化與工作流於一身的工具

clipboard.png


  當然,webpack也並非銀彈。工具沒有好壞,只有適合與否。即便是webpack也並非適用於所有場合。 

  webpack 的最大特點是一切皆爲模塊,一切全包,最適和應用在SPA一站式應用場景。只有簡單幾個頁面的情況下使用 webpack 反而可能會增加不必要的配置成本,反而直接用gulp或者其他工具處理代碼壓縮,css 預處理之類的工作會更加快捷易用。 

  另外,除了最主流的 webpack 之外,同性質的模塊化打包器還有 browserIfy,以及百度的 fis ,由於對這兩者瞭解不多,就不一一比較了。

使用 webpack 實現工程化

  廢話少說,talk is easy , show me the code,我們來看看webpack是怎麼工作的。以下是一個配置了webpack-dev-server的本地開發webpack配置文件。 具體可訪問 github 地址 查看完整信息

// webpack.dev.config.js
let path = require('path'),
      webpack = require('webpack');

let resolve = path.resolve;
let webRootDir = resolve(__dirname, '../');


module.exports = {
    entry: {                 // 入口文件,打包通過入口,找到所有依賴的模塊,打包輸出
        main: resolve(webRootDir, './src/main.js'), 
    },
    output: {
        path: resolve(webRootDir, './build'),  // 輸出路徑
        publicPath: '/build/',     // 公共資源路徑
        filename: '[name].js'      // 輸出文件名字,此處輸出main.js, babel-polyfill.js ,  視情況可以配置[name].[chunkhash].js添加文件hash, 管理緩存
    },
    module: {
        rules: [   //模塊化的loader,有對應的loader,該文件才能作爲模塊被webpack識別
            {
                test: /\.js$/,
                loader: 'babel-loader',
                exclude: /node_modules/
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章