摘要:前端工程化的演化。前端較為流行的單元測試,等自動化測試自動化測試是軟件通過模擬瀏覽器,對頁面進行操作,判斷是否產生預想的效果。
前端工程化
??前端工程化的概念在近些年來逐漸成為主流構建大型web應用不可或缺的一部分,在此我通過以下這三方面總結一下自己的理解。
為什么需要前端工程化。
前端工程化的演化。
怎么實現前端工程化。
為什么需要工程化??隨著近些年來前端技術的不斷發展,越來越多復雜的業務放在了前端,前端不再是以前幾個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組件化,從而提高代碼可復用性。
??在沒有引入模塊化的概念之前,前端往往需要手動處理js文件的依賴關系,例如;bootstartp 依賴 jquery,就需要在引入bootstrap之前引入jquery
??如果引入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工程,存在復雜依賴情況是極有可能發生的,并且把時間耗費在管理依賴關系上也不值當。
所以就誕生了前端模塊化
??經歷了混亂加載的黑歷史,我們終于迎來了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進行語法轉譯,不過兼容性畢竟是硬傷,唯有時間能治愈。
??從描述可知,前端工程化需要做的事情,單憑人力一個一個去處理基本沒有可能完成,那么,我們就需要學會使用工具,畢竟程序猿和猿之間最大的區別就是會不會使用工具。
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目錄中。可以說是集模塊化與工作流于一身的工具。
當然,webpack也并非銀彈。工具沒有好壞,只有適合與否。即便是webpack也并非適用于所有場合。
webpack 的最大特點是一切皆為模塊,一切全包,最適和應用在SPA一站式應用場景。只有簡單幾個頁面的情況下使用 webpack 反而可能會增加不必要的配置成本,反而直接用gulp或者其他工具處理代碼壓縮,css 預處理之類的工作會更加快捷易用。
另外,除了最主流的 webpack 之外,同性質的模塊化打包器還有 browserIfy,以及百度的 fis ,由于對這兩者了解不多,就不一一比較了。
??廢話少說,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/ }, { test: /.(png|jpg|gif|svg|ico)$/, loader: "file-loader", options: { name: "[name].[ext]?[hash]" } }, { test: /.(eot|svg|ttf|woff|woff2)(?S*)?$/, loader: "file-loader" }, { test: /.css$/, loader: "style-loader!css-loader" }, { test: /.scss$/, loader: "style-loader!css-loader!autoprefixer-loader?{browsers:["last 5 version", "Firefox" + " 15"]}!sass-loader?sourceMap&outputStyle=compressed" } ] }, resolve: { extensions: [".js"], // 定義后綴名 ,import時可以省略“.js”后綴 alias: { // 別名。 如 import "./src/style/common.css" ==> import "style/common.css" "components": resolve(webRootDir, "./src/components"), "page": resolve(webRootDir, "./src/page"), "style": resolve(webRootDir, "./src/style"), "script": resolve(webRootDir, "./src/script"), "static": resolve(webRootDir, "./static") } }, devServer: { // webpack-dev-server 熱加載的配置 host: "127.0.0.1", //本地ip, 如需局域網內其他及其通過ip訪問,配置"0.0.0.0"即可 port: 8080, disableHostCheck: true, historyApiFallback: true, noInfo: true }, performance: { hints: false }, } module.exports.devtool = "#source-map" /*插件*/ module.exports.plugins = (module.exports.plugins || []).concat([ // webpack 變量定義,,可在其他模塊訪問到該變量值,以便根據不同環境來進行不同情況的打包操作。 // 例如,在main.js 下 console.log( process.env.Node_ENV ) 輸出 development字符串 new webpack.DefinePlugin({ "process.env": { NODE_ENV: `"development"` } }), ])
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/88485.html
摘要:原作者唐斌騰訊什么原名是一個簡單易用的前端模板預編譯工具。本文作者為來自騰訊團隊的唐斌,他在本文中為我們分析了傳統前端模板內嵌的弊端,如開發調試效率低下自動化構建復雜度比較高等特點,并針對目前現狀給出了較好的解決方案。 原作者: 唐斌(騰訊)| TmodJS什么 TmodJS(原名atc)是一個簡單易用的前端模板預編譯工具。它通過預編譯技術讓前端模板突破瀏覽器限制,實現后端模板一樣的同...
摘要:基于平臺的開發框架路由中間件使用中間件將整合工具對外提供的命令配置將不斷更新完善 express: 基于nodejs平臺的web開發框架express = 路由 + 中間件 showImg(https://segmentfault.com/img/bVbalNI?w=1600&h=1200); 使用express中間件 將task整合showImg(https://segmentfau...
閱讀 2016·2021-11-12 10:36
閱讀 1865·2021-11-09 09:49
閱讀 2591·2021-11-04 16:12
閱讀 1144·2021-10-09 09:57
閱讀 3235·2019-08-29 17:24
閱讀 1909·2019-08-29 15:12
閱讀 1272·2019-08-29 14:07
閱讀 1285·2019-08-29 12:53