前端模塊化
標簽(空格分隔): 模塊化
前端模塊化系列(一):網站需要模塊化的原因
由於我最近在研究前端各種各樣的模塊化系統,所以就翻譯了一篇來自webpack官網的文章,總的來說作者寫的還是相當不錯的。這樣在自己學習的同時也可以與大家共同學習~~~
在今天的網站正在逐步的向
web apps
轉變。
- 單個頁面中越來越多的Javascript。
- 在現代瀏覽器中你可以做越來越多的功能。
- 少量的全頁面刷新,以至於單個頁面中有更多的代碼。
正因為這些原因造成越來越多的代碼鑲嵌在瀏覽器端中。
這樣一個大的代碼倉庫(code base
)急需做出相應的管理。正好,模塊化系統提供了這些功能分割你的代碼倉庫,把它們分割為一個個的模塊。
各個模塊系統的風格
眼下對於如何定義依賴項和暴露接口有很多的標准:
- <script>標簽風格(ps:不使用模塊系統)。
- CommonJs
- AMD和它的一些衍生物
- ES6模塊
- 更多。。。
在下面,我們會一次簡介這些模塊化系統之間的好處以及壞處。
<script>標簽風格
如果你沒有使用模塊化系統,那么你只能用這種方式來處理你的模塊化代碼了。
<script src="module1.js"></script>
<script src="module2.js"></script>
<script src="libraryA.js"></script>
<script src="module3.js"></script>
每個模塊向外暴露一個接口給全局對象,即window對象。模塊就可以通過全局對象訪問依賴項向外暴露的接口。
通常存在的問題
- 全局對象中的變量沖突。
- 按需加載的問題。
- 開發者需要手動解析模塊或者庫的依賴項。
- 在特別大的項目中,這個現象會變得越來越嚴重,越來越難以管理。
CmmonJs:同步require
這種方式使用了一個同步的require方法去加載依賴項並且返回一個向外暴露的接口。一個模塊可以通過給exports添加屬性或者給module.exports設置固定值來指定向外暴露的值。
require("module");
require("../file.js");
exports.doStuff = function() {};
module.exports = someValue;
這個只是被node.js
使用在server端。
優點:
- server端的模塊可以被復用。
- 有許多現成的模塊以供使用(npm)。
- 非常的簡單易用。
缺點:
- 因為網絡請求都是異步的。所以阻塞式的調用在網路中支持的不是很好。
- 多個模塊之間並能同時並行的加載進來。
實現
1、node.js - server端。
2、browserify
3、modules-webmake-編譯到一個bundle里
4、wreq-客戶端
AMD:異步的require
Asynchronous Module Definition
其他的模塊化系統(對於瀏覽器來說)對於同步require(CommonJs)都有或多或少的問題。接下來我們介紹一個異步require的模塊化系統(定義模塊和暴露值的另外一種實現方式)。
require(["module", "../file"], function(module, file) {
/* ... */
});
define("mymodule", ["dep1", "dep2"], function(d1, d2) {
return someExportedValue;
});
優點:
- 十分適合在現下網絡的異步請求。
- 支持多個模塊的同時並行加載。
缺點:
- 寫碼開銷。讀寫十分的困難。
- 看上去像是一種解決方案。
實現
1、require.js - client端。
2、curl - client端。
ES6模塊化
EcmaScript6針對JavaScript添加了一些新的語言結構,其中就包括模塊化系統。
import "jquery";
export function doStuff() {}
module "localModule" {}
優點:
- 很容易的靜態模塊解析。
- 未來不久將要作為ES標准來推行。
缺點:
- 讓大部分的瀏覽器支持這個功能還需要一段時間。
- 這種風格的模塊太少了,讓人不適應。
咱誰也不偏向誰的解決方案
給開發者關於模塊化風格的選擇權。在現有代碼可以正常運行的前提下,可以很容易地添加自定義模塊。關鍵還要看使用某個模塊系統對於現在的系統影響大不大。
模塊的傳輸方式
模塊是應該在client端被執行的,所以這就需要它們通過http協議讓server端向瀏覽器端傳輸。
現在有兩種方式來處理如何傳輸模塊
1、一個請求一個模塊。
2、所有的模塊都在一個請求里。
這兩種方式都有人在用,不過這兩種都是次優的:
一個請求一個模塊
優點
- 僅僅傳輸被請求的那個模塊。
缺點:
- 許多的請求意為着網絡開銷也很大。
- 程序啟動變慢,因為請求會延遲。
所有的模塊都在一個請求里
優點
- 很小的請求開銷,少量的延遲。
缺點:
- 不需要(還沒有)被請求的模塊也被傳輸過來了。
分塊傳輸方式
相對於上面兩種方式都太死板了,所以靈活點的模塊傳輸會不會更好哪?因為向兩個極端之間的折中妥協通常都是最好的。
雖然我們需要把所有的模塊都編輯,把模塊安裝功能和是否公用拆分為多個較小的代碼塊。
我們有很多的小量請求。把那些不需要一開始就請求,或者是需要按需加載的模塊來進行分塊傳輸。瀏覽器最開始的訪問請求並不用包含你的所有代碼庫(code base)。這樣的話,server返回的數據大小也就會變的很小。有效解決了上面兩種方式所出現的問題。
至於如何分隔模塊
應該是開發者根據功能
,格式
,加載順序
,繼承關系
分割為一個一個單獨的部分.
注意:拆分的粒度問題,可復用問題,效率問題.如何這些問題處理的不好,就有可能出現不想要的后果。
這樣的話。就算再多的代碼也可以解決掉了。
獲取更多相關代碼塊如何分割的知識。
為什么僅僅只是JavaScript?
不知道大家有沒有發現,為什么一個模塊化系統僅僅只幫助開發者處理JavaScript哪?除此之外還需要很多的靜態資源需要我們去處理呀!
- stylesheets(樣式表)
- images(圖片)
- webfonts(web字體)
- html for templating(html模版)
- 等等...
當然,還有其他的資源:
- coffeeScript -> javascript
- less -> stylesheets
- jade -> 經過javascript生成的html
- 等等...
它們也應該向JavaScript一樣可以被很容易的require到:
require("./style.css");
require("./style.less");
require("./template.jade");
require("./image.png");
模塊靜態解析
當編譯所有模塊的時候,為了協調異步環境下模塊開發與性能間的矛盾,我們必須在工程階段就具備依賴分析的能力,把具備依賴關系的資源進行打包。就算不打包,也希望像 F.I.S
那樣有個記錄依賴關系的map.json,可以照單抓葯,一次性地把需要的依賴項加載下來。
策略
一個聰明的解析器將允許大多數現有的代碼可以有效運行,不管開發者有沒有使用模塊化系統。即使開發人員做了一些奇怪的東西,它也會嘗試找到最適合的解決方案。實在不行,也就只能抱歉咯!!!
翻譯自:http://webpack.github.io/docs/motivation.html
翻譯人:張亞濤