原文地址[前端架構](http://saito.im/note/The-Architecture-of-F2E/)
前端架構
總述
在互聯網應用越來越大,越來越復雜的今天,我們不可避免的需要工具來管理我們的前端代碼。 替代以前的一個巨大的腳本文件,我們希望可以將文件寫入不同的文件模塊。并且希望代碼可以 重用,可以簡單的引用和添加各種各樣的依賴到我們的項目( 無論是菜單一樣的 UI 組件還是 一個類似 jQuery 的 DOM 操作庫)。不止是 JavaScript 我們希望可以用這種方式來組織, 他應該也包含 CSS,HTML 模板,字體,圖片和其他靜態文件。
為什么前端需要模塊化開發
隨著互聯網應用越來越大,前端的開發也越來越復雜。如果還維持在以往以頁面為單位的開發, 會導致很多問題,類似依賴管理,命名沖突等棘手的問題。
命名沖突是最常見的問題:
~~~
// util.js
function log(message) {
}
// logger.js
function log(message) {
}
~~~
當頁面的 script 標簽同時依賴這兩個文件時便會產生沖突,導致后面函數會覆蓋前面的。 從而可能會產生一些預想之外的結果。
而傳統的解決方案是使用命名空間:
~~~
// util.js
var util.log = function(message) {
}
// logger.js
var logger.log = function(message) {
}
~~~
這樣會帶來顯而易見的問題,所有的代碼會變得冗余且編寫困難。
如果使用模塊化的編寫方案,例如 Common Module Definition,代碼見的依賴會變得格外簡單。
~~~
// util.js
var log = function(message) {
}
module.exports = log
// logger.js
var log = function(message) {
}
module.exports = log
// app.js using util.js log for logging
var log = require("util.js")
log("Hello Module Definition")
~~~
util.js 與 logger.js 不會相互沖突,他們會被工具包裝為 CMD 下的定義方式。 然后通過依賴的方式來解決沖突
依賴管理同樣是一個棘手的問題:
~~~
<script src="/util.js" type="text/javascript"></script>
<script src="/logger.js" type="text/javascript"></script>
<script src="/app.js" type="text/javascript"></script>
~~~
如果你有一大堆的依賴關系,你必須依序將所有的文件引入,否則會導致變量未定義等問題。 如果使用了 Common Module Definition 便可以無序的引入組件文件。
在樣式方面由于 CSS 與瀏覽器本身的限制我們仍然無法使用這樣的技術來劃分模塊。
~~~
/* layout.css */
.box {
}
/* dropdown.css */
.box {
}
~~~
這樣的話 dropdown.css 的 .box 便會覆蓋之前的 .box 的樣式,所以我們需要在模塊中添加限制。
所以在樣式表方面我們需要詳細的劃分模塊的命名空間,例如在 dropbox.css 中我們可以用這樣的命名方式 .dropdown .box 的方式。 這邊便不會影響到父級的樣式。
如何進行模塊化開發
首先對頁面進行模塊化的拆分,將模塊的定義文件放在一個文件夾下,其中包含有 JavaScript CSS 以及 Templates(前后端)的文件。模塊的腳本文件默認會被 CMD 包裝, 而 CSS 文件,開發著需要對文件進行特殊的命名,默認以模塊文件夾名為命名空間, 以防與別人沖突,而模板文件則不會有這樣的顧慮。
我們開發了 Linner 來支持模塊化的開發。
架構概覽
在前端項目中,我們在底層擁有基礎組件庫與可視化編輯框架用于裝修需求。 在基礎組件之上,我們會沉淀出標準的組件庫,類似電商標準組件庫之類的類庫, 而真正的類庫中開發者也需要將自己的組織為組件的形式。
而工具則為整個過程保駕護航。
工具闡述
簡單來說,Linner 允許我們做:
項目結構化
頁面組件化
倉庫管理
使用 CoffeeScript 與 SCSS 來替代 JavaScript 與 CSS
合并 CSS 與 JavaScript 文件
復制 CSS 與 JavaScript 文件
預編譯 CSS 與 JavaScript 文件
合并圖片至一張大圖(Sprites)
壓縮 CSS 與 JavaScript 文件
監視文件系統變化并實時更新
1. 項目結構化
項目通過標準化的方式來組織:
.
├── app
│ ├── components
│ │ └── dropdown
│ │ ├── view.coffee
│ │ ├── view.hbs
│ │ └── view.scss
│ ├── images
│ │ └── logo.png
│ ├── scripts
│ │ └── app.coffee
│ ├── styles
│ │ └── app.scss
│ ├── templates
│ │ └── welcome.hbs
│ └── views
│ └── index.html
├── bin
│ └── server
├── config.yml
├── public
├── test
└── vendor
app 文件夾是用戶自己編寫代碼的地方
images 用以存放項目相關的圖片文件
scripts 用以存放項目相關的 JavaScript 文件
styles 用以存放項目相關的 Stylesheet 文件
templates 用以存放項目相關的前端模板文件
views 用以存放項目相關的后端模板文件
components 用以存放項目的組件文件
config.yml 是整個項目的配置文件
bin 文件夾可以讓用戶很方便的啟動一個本地的服務器,以當前文件夾作為根
test 文件夾可以使用戶編寫一些單元測試來測試自己的前端項目
vendor 文件夾可以使用戶引入第三方的代碼組件,如 jQuery、Underscore 等
public 文件夾是項目打包后文件位置,發布項目所需要的所有文件
2. 頁面組件化
不要面向頁面編程,要面向組件編程。
當拿到網站的整體設計稿時,我們應該首先去找出頁面間有相同邏輯的模塊。 將他們抽出,考慮如何將其設計為可復用的模塊。
我們可以將模塊的內容包含 JavaScript CSS 與前后端模板組織在 app/components 內,通過在 app/scripts 里面的 app.coffee 中去初始化所有的組件。
通過 cmd 的形式去管理組件與組件之間的依賴關系。這樣組件內部就可以通過 module.exports = "dropdown" 與 require "dropdown" 這樣的形式去導出與依賴組件。
3. 倉庫管理
通過 bundles 來管理遠端依賴,在項目中可以非常方便的引入一些著名的第三方庫。 如 jQuery,Underscore 等。
依賴可以規定多個版本,當需要升級版本時,可以更改 version 與 url 在工具下次啟動時便可以拉取新版本的依賴。如果希望依賴一直為最新狀態,可以將 version 設置為 master 這樣工具會在每次啟動時都獲取最新的文件。
4. 使用 CoffeeScript 與 SCSS 來替代 JavaScript 與 CSS
CoffeeScript
CoffeeScript 是這一門編程語言構建在 JavaScript 之上,其被編譯成高效的 JavaScript, 這樣你就可以在 Web 瀏覽器上運行它,或是通過諸如用于服務器端應用的 Node.js 一類的技術來使用它。 編譯過程通常都很簡單,產生出來的 JavaScript 與許多的最佳做法都保持了一致。
SCSS
SCSS 擴展了 CSS3,增加了規則、變量、混入、選擇器、繼承等等特性。 SCSS 生成良好格式化的 CSS 代碼,易于組織和維護。
使用成本
使用 CoffeeScript 與 SCSS 可以大幅降低開發成本,使用 CoffeeScript 可以避免一些常見的 JavaScript 開發錯誤。 而 SCSS 則可以更好的抽象樣式文件,使樣式得到更好的維護。并且 CoffeeScript 與 SCSS 的學習成本都很低, 前端可以通過很簡短的學習就能立刻寫出優雅的代碼。
5. 合并 CSS 與 JavaScript 文件
前端文件的合并可以明顯的減少 HTTP 請求,明顯的加快網頁的瀏覽速度。
6. 復制 CSS 與 JavaScript 文件
復制文件是一個很普遍的需求,可以將文件從一個位置復制到另一個位置。如果是 CoffeeScript 文件或者 SCSS 文件,工具會幫助轉換為對應的 Javascript 與 CSS 文件。
7. 預編譯 JavaScript 模板文件
隨著互聯網應用越來越大,前端模板的需求也日漸突出。在使用前端模板的過程中, 為了提高前端的渲染性能,我們需要對前端模板進行預編譯。預編譯的結果是使 templates 文件能直接轉化為 JavaScript 的方法調用。這樣可以以非常快的速度來渲染前端模板。
8. 合并圖片至一張大圖(Sprites)
當頁面內的圖片很多時,會產生多個 HTTP 請求,當請求變多時會嚴重影響網站的速度。 所以我們需要將多個 PNG 圖片合并成一張圖片。同時利用 CSS 的 background 來顯示對應的單個圖片
9. 壓縮 CSS 與 JavaScript 文件
在項目發布上線時需要將資源文件進行最大程度的壓縮。從而減少 HTTP 請求文件的體積。 從而可以將文件盡快的傳輸給用戶,使頁面更快的展示出來。
工具提供了快速的文件名的版本替換,可以使服務器更好的緩存壓縮后的文件。
10. 監視文件系統變化并實時更新
文件系統的實時監控可以監控到項目內文件的變動,同時重新執行整個工具的邏輯。
在開發階段,我們可以盡最大程度的提高開發者的效率。例如使用瀏覽器實時刷新。 當文件系統有任何變化時,工具會發動 LiveReload 來自動刷新頁面, 當用戶只修改了 CSS 文件時,我們甚至可以不刷新頁面,直接重載 CSS 文件。 極大的提高開發效率。
性能調優
大約 80%-90% 的終端響應時間是花費在前端,其中包含下載頁面中的圖片,樣式表,腳本,flash等。Yahoo 為此總結了 14 條規則,成為網站性能優化的事實標準。
雅虎網站性能優化的 14 條規則:
盡可能減少 HTTP 請求數
使用 CDN(內容分發網絡)
為文件頭指定 Expires 或 Cache-Control,使內容具有緩存性
使用 Gzip 壓縮內容
把 CSS 放到頂部
把 JavaScript 放在底部
避免在 CSS 中使用 Expressions
把 JavaScript 和 CSS 都放到外部文件中
減少 DNS 查找次數
壓縮 JavaScript 和 CSS
避免重定向
剔除重復的 JavaScript 和 CSS
配置 Etags
使 AJAX 緩存
對規則的分析:
代碼編寫方面的規則:
把 CSS 放到頂部
把 JavaScript 放在底部
把 JavaScript 和 CSS 都放到外部文件中
避免在 CSS 中使用 Expressions
使 AJAX 緩存
打包方面的規則:
盡可能減少 HTTP 請求數
壓縮 JavaScript 和 CSS
剔除重復的 JavaScript 和 CSS
部署方面的規則:
使用 CDN(內容分發網絡)
為文件頭指定 Expires 或 Cache-Control,使內容具有緩存性
使用 Gzip 壓縮內容
減少 DNS 查找次數
避免重定向
配置 Etags
對規則的實踐
部署方面的規則,應用 Nginx 為靜態文件添加 Expires 跟 Cache-Control 頭, 配置 Etags,并啟用 Gzip 壓縮。并且避免在 Nginx 中做重定向,有條件的話可以 啟用 CDN,并優化網絡配置以減少 DNS 查找次數。
代碼編寫方面的規則,需要在編寫代碼種形成規范。默認使用類似 jQuery 這樣的庫 便可以對 AJAX 進行緩存。
打包方面 Linner 可以合并 JavaScript 與 CSS 文件, 并且支持小圖片的合并, 用以減少 HTTP 請求數。同時 Linner 的倉庫管理可以避免重復的 JavaScript 與 CSS 文件的出現。在 build 過后所有的文件將會被壓縮。
附件
工具的使用
安裝 Ruby 2.0.0 以上版本
安裝 Linner 及其使用規則
# 安裝 Linner
gem install linner
# 使用 Linner 創建項目結構
linner new webapp && cd webapp
# 在項目下啟動 Linner
linner watch
# 退出 Linner
CTRL + C
# 打包資源文件
linner build
# 清空打包的資源文件
linner clean
config.yml 文件配置詳解
~~~
paths:
app: "app"
test: "test"
public: "public"
groups:
scripts:
paths:
- app/scripts
concat:
"/scripts/app.js": "app/**/*.{js,coffee}"
"/scripts/vendor.js": "vendor/**/*.{js,coffee}"
order:
- vendor/jquery-1.10.2.js
- ...
- app/scripts/app.coffee
styles:
paths:
- app/styles
concat:
"/styles/app.css": "app/styles/**/[a-z]*.{css,scss,sass}"
images:
paths:
- app/images
sprite:
"../app/images/icons.scss": "app/images/**/*.png"
views:
paths:
- app/views
copy:
"/": "app/views/**/*.html"
templates:
paths:
- app/templates
precompile:
"/scripts/templates.js": "app/templates/**/*.hbs"
modules:
wrapper: cmd
ignored: vendor/**/*
definition: /scripts/app.js
sprites:
url: /images/
path: /images/
selector: .icon-
revision: index.html
notification: true
bundles:
jquery.js:
version: 1.10.2
url: http://code.jquery.com/jquery-1.10.2.js
handlebars.js:
version: 1.0.0
url: https://raw.github.com/wycats/handlebars.js/1.0.0/dist/handlebars.runtime.js
~~~
paths 表示當前工具做監視的文件系統目錄
groups 區分了不同的組,每個組可以有一個名字。在組內部的聲明中需要指定當前組的 paths,然后可以指定一系列的操作原語,包括:concat order copy precompile sprite 等
modules 定義了需要被 CMD 包裝的文件路徑,以及包裝定義的頭文件連接位置
sprites 定義了圖片 sprites 的一些生成規則,例如以 .icon- 開頭來生成 CSS 列表,這樣用戶便可以以這樣的 CSS 選擇器來直接生成樣式。
revision 定義了需要被加載 rev 的文件,用以 md5 的文件名來替換舊文件名
notification 定義了是否需要有通知系統,(用以 Mac 系統的通知)
bundles 定義了項目的依賴關系,項目可以依賴很多第三方的項目,可以自定義版本號。 如果需要每次啟動都更新最新版本的依賴,可以將 version 設置為 master
- 1. KanCloud快捷鍵
- algate.github.io的網站建設
- algate.github.io基礎完善
- 如何在github上展示作品——為你的項目生成一個快速訪問的網址
- Github README.md 添加圖片
- git上傳github常用命令
- WEB開發文檔
- 工具相關文檔說明
- GulpJs開發文檔
- 安裝Gulp詳細教程
- 如何上傳到github
- 服務端相關文檔
- tomcat配置多域名多端口訪問
- Vue遇到的那些大坑
- vue-bulid新建問題解決方案
- vue-prev功能實現方案優劣(element)
- 常用組件使用和功能實現
- 1-文件上傳功能
- 2-select插件實現利弊
- 3-實現分步驟流程效果
- ES6-export與export default遇到的坑
- require.context()-route去中心化管理
- webpack.ensure(webpack代碼分割)
- angular爬-跪著也要爬完
- 新建遇到的問題
- 常用angular核心知識
- React初生牛犢不怕虎
- react初次見面之泥坑深譚
- react+webpack+es6精簡版HelloWorld
- create-react-app創建失敗
- create-react-app不歸路
- react用到的組件module
- react-hot-loader
- JavaScript成長之路
- Js進階
- Js模塊化編程:require.js的用法
- 淺談前端架構
- Js常見問題匯總
- 瀏覽器渲染原理及解剖瀏覽器內部工作原理
- 雅虎前端優化的35條軍規
- 常見問題描述-面試常問
- 前端性能優化-algate
- http狀態碼詳解
- 作用域,閉包,面向對象
- Js基礎知識
- Js基本功必須扎實
- 各個瀏覽器加載icon
- html特殊標簽和屬性的說明
- 個人資源總結
- 個人簡歷-絕對真實有效
- Jekyll博客創建
- Jekyll開始創建
- Jekyll文檔說明
- jekyll-paginate分頁問題
- HEXO博客創建
- es6新用法解析以及使用
- 神奇的三個點:...
- 幾大類
- coding創建hexo
- sublime相關配置
- Atom使用