摘要:可維護性根據(jù)定義,每個模塊都是獨立的。良好設計的模塊會盡量與外部的代碼撇清關系,以便于獨立對其進行改進和維護。這標志模塊化編程正式誕生。的模塊系統(tǒng),就是參照規(guī)范實現(xiàn)的。對象就代表模塊本身。
javascript模塊化及webpack基本介紹 JavaScript 模塊化發(fā)展歷程
什么是模塊化 ?
為什么要做Javascript模塊化?
JavaScript 模塊化發(fā)展歷程
什么是模塊化 ?模塊化是一種處理復雜系統(tǒng)分解成為更好的可管理模塊的方式,它可以把系統(tǒng)代碼劃分為一系列職責單一,高度解耦且可替換的模塊,系統(tǒng)中某一部分的變化將如何影響其它部分就會變得顯而易見,系統(tǒng)的可維護性更加簡單易得。
一個模塊就是實現(xiàn)特定功能的文件, 邏輯上相關的代碼組織到同一個包內(nèi),包內(nèi)是一個相對獨立的王國,不用擔心命名沖突什么的,那么外部使用的話直接引入對應的package即可.
就好像作家會把他的書分章節(jié)和段落;程序員會把他的代碼分成模塊。
就好像書籍的一章,模塊僅僅是一坨代碼而已。
好的代碼模塊分割的內(nèi)容一定是很合理的,便于你增加減少或者修改功能,同時又不會影響整個系統(tǒng)。
為什么要做Javascript模塊化?早期前端只是為了實現(xiàn)簡單的頁面交互邏輯,隨著Ajax技術(shù)的廣泛應用,前端庫的層出不窮,前端代碼日益膨脹,JavaScript卻沒有為組織代碼提供任何明顯幫助,甚至沒有類的概念,更不用說模塊(module)了,這時候JavaScript極其簡單的代碼組織規(guī)范不足以駕馭如此龐大規(guī)模的代碼.
模塊化可以使你的代碼低耦合,功能模塊直接不相互影響。
可維護性:根據(jù)定義,每個模塊都是獨立的。良好設計的模塊會盡量與外部的代碼撇清關系,以便于獨立對其進行改進和維護。維護一個獨立的模塊比起一團凌亂的代碼來說要輕松很多。
命名空間:在JavaScript中,最高級別的函數(shù)外定義的變量都是全局變量(這意味著所有人都可以訪問到它們)。也正因如此,當一些無關的代碼碰巧使用到同名變量的時候,我們就會遇到“命名空間污染”的問題。
可復用性:現(xiàn)實來講,在日常工作中我們經(jīng)常會復制自己之前寫過的代碼到新項目中, 有了模塊, 想復用的時候直接引用進來就行。
JavaScript 模塊化發(fā)展歷程前端的先驅(qū)在刀耕火種的階段開始,做了很多努力,在現(xiàn)有的運行環(huán)境中,實現(xiàn)"模塊"的效果。函數(shù)封裝
模塊就是實現(xiàn)特定功能的一組方法。在JavaScript中,函數(shù)是創(chuàng)建作用域的唯一方式, 所以把函數(shù)作為模塊化的第一步是很自然的事情.
function foo(){ //... } function bar(){ //... }
上面的,組成一個模塊。使用的時候,直接調(diào)用就行了。
這種做法的缺點很明顯:全局變量被污染,很容易命名沖突, 而且模塊成員之間看不出直接關系。
對象寫法為了解決上面的缺點,可以把模塊寫成一個對象,所有的模塊成員都放到這個對象里面。
var MYAPP = { count: 0, foo: function(){}, bar: function(){} } MYAPP.foo();
上面的代碼中,函數(shù)foo和bar, 都封裝在MYAPP對象里。使用的時候,就是調(diào)用這個對象的屬性。 但是,這樣的寫法會暴露所有模塊成員,內(nèi)部狀態(tài)可以被外部改寫.
立即執(zhí)行函數(shù)(IIFE)寫法使用立即執(zhí)行函數(shù)(Immediately-Invoked Function Expression,IIFE),可以達到不暴露私有成員的目的。
var Module = (function(){ var _private = "safe now"; var foo = function(){ console.log(_private) } return { foo: foo } })() Module.foo(); Module._private; // undefined
這種方法的好處在于,你可以在函數(shù)內(nèi)部使用局部變量,而不會意外覆蓋同名全局變量,但仍然能夠訪問到全局變量, 在模塊外部無法修改我們沒有暴露出來的變量、函數(shù).
引入依賴將全局變量當成一個參數(shù)傳入到匿名函數(shù)然后使用
var Module = (function($){ var _$body = $("body"); // we can use jQuery now! var foo = function(){ console.log(_$body); // 特權(quán)方法 } // Revelation Pattern return { foo: foo } })(jQuery) Module.foo();
jQuery的封裝風格曾經(jīng)被很多框架模仿,通過匿名函數(shù)包裝代碼,所依賴的外部變量傳給這個函數(shù),在函數(shù)內(nèi)部可以使用這些依賴,然后在函數(shù)的最后把模塊自身暴漏給window。
如果需要添加擴展,則可以作為jQuery的插件,把它掛載到$上。
這種風格雖然靈活了些,但并未解決根本問題:所需依賴還是得外部提前提供、還是增加了全局變量。
從以上的嘗試中,可以歸納出js模塊化需要解決那些問題:
如何安全的包裝一個模塊的代碼?(不污染模塊外的任何代碼)
如何唯一標識一個模塊?
如何優(yōu)雅的把模塊的API暴漏出去?(不能增加全局變量)
如何方便的使用所依賴的模塊?
圍繞著這些問題,js模塊化開始了一段艱苦而曲折的征途。
JavaScript 模塊規(guī)范上述的所有解決方案都有一個共同點:使用單個全局變量來把所有的代碼包含在一個函數(shù)內(nèi),由此來創(chuàng)建私有的命名空間和閉包作用域。
你必須清楚地了解引入依賴文件的正確順序。就拿Backbone.js來舉個例子,想要使用Backbone就必須在你的頁面里引入Backbone的源文件。
然而Backbone又依賴 Underscore.js,所以Backbone的引入必須在其之后。
而在工作中,這些依賴管理經(jīng)常會成為讓人頭疼的問題。
另外一點,這些方法也有可能引起命名空間沖突。舉個例子,要是你碰巧寫了倆重名的模塊怎么辦?或者你同時需要一個模塊的兩個版本時該怎么辦?
還有就是協(xié)同開發(fā)的時候, 大家編寫模塊的方式各不相同,你有你的寫法,我有我的寫法, 那就亂了套.
接下來介紹幾種廣受歡迎的解決方案
CommonJS
AMD
CMD
ES6模塊
CommonJS2009年,美國程序員Ryan Dahl創(chuàng)造了node.js項目,將javascript語言用于服務器端編程。
這標志Javascript模塊化編程正式誕生。因為老實說,在瀏覽器環(huán)境下,沒有模塊也不是特別大的問題,畢竟網(wǎng)頁程序的復雜性有限;但是在服務器端,一定要有模塊,與操作系統(tǒng)和其他應用程序互動,否則根本沒法編程。
node.js的模塊系統(tǒng),就是參照CommonJS規(guī)范實現(xiàn)的。
CommonJS定義的模塊分為:
定義模塊:
根據(jù)CommonJS規(guī)范,一個多帶帶的文件就是一個模塊。每一個模塊都是一個多帶帶的作用域,也就是說,在該模塊內(nèi)部定義的變量,無法被其他模塊讀取,除非定義為global對象的屬性。
模塊輸出:
模塊只有一個出口,module.exports對象,我們需要把模塊希望輸出的內(nèi)容放入該對象。module對象就代表模塊本身。
加載模塊:
加載模塊使用require方法,該方法讀取一個文件并執(zhí)行,返回文件內(nèi)部的module.exports對象。
// math.js exports.add = function(a, b){ return a + b; }
// main.js var math = require("math") // ./math in node console.log(math.add(1, 2)); // 3
這種實現(xiàn)模式有兩點好處:
避免全局命名空間污染
明確代碼之間的依賴關系
但是, 由于一個重大的局限,使得CommonJS規(guī)范不適用于瀏覽器環(huán)境。
看上面的main.js代碼, 第二行的math.add(1, 2),在第一行require("math")之后運行,因此必須等math.js加載完成。也就是說,如果加載的依賴很多, 時間很長,整個應用就會停在那里等。
我們分析一下瀏覽器端的js和服務器端js都主要做了哪些事,有什么不同:
服務器端JS | 瀏覽器端JS |
---|---|
相同的代碼需要多次執(zhí)行 | 代碼需要從一個服務器端分發(fā)到多個客戶端執(zhí)行 |
CPU和內(nèi)存資源是瓶頸 | 帶寬是瓶頸 |
加載時從磁盤中加載 | 加載時需要通過網(wǎng)絡加載 |
這對服務器端不是一個問題,因為所有的模塊都存放在本地硬盤,可以同步加載完成,等待時間就是硬盤的讀取時間。但是,對于瀏覽器,這卻是一個大問題,因為模塊都放在服務器端,等待時間取決于網(wǎng)速的快慢,可能要等很長時間,瀏覽器處于"假死"狀態(tài)。
因此,瀏覽器端的模塊,不能采用"同步加載"(synchronous),只能采用"異步加載"(asynchronous)。這就是AMD規(guī)范誕生的背景。
AMDAMD 即Asynchronous Module Definition,中文名是異步模塊定義的意思。它采用異步方式加載模塊,模塊的加載不影響它后面語句的運行。所有依賴這個模塊的語句,都定義在一個回調(diào)函數(shù)中,等到加載完成之后,這個回調(diào)函數(shù)才會運行。
// main.js require(["moduleA", "moduleB", "moduleC"], function (moduleA, moduleB, moduleC){ // some code here });
用全局函數(shù)define來定義模塊,用法為:define(id?, dependencies?, factory);
id為模塊標識,遵從CommonJS Module Identifiers規(guī)范
dependencies為依賴的模塊數(shù)組,在factory中需傳入形參與之一一對應
如果dependencies的值中有"require"、"exports"或"module",則與commonjs中的實現(xiàn)保持一致
如果dependencies省略不寫,則默認為["require", "exports", "module"],factory中也會默認傳入require,exports,module.
如果factory為函數(shù),模塊對外暴漏API的方法有三種:return任意類型的數(shù)據(jù)、exports.xxx=xxx、module.exports=xxx.
如果factory為對象,則該對象即為模塊的返回值
大名鼎鼎的require.js就是AMD規(guī)范的實現(xiàn).
require.js要求,每個模塊是一個多帶帶的js文件。這樣的話,如果加載多個模塊,就會發(fā)出多次HTTP請求,會影響網(wǎng)頁的加載速度。因此,require.js提供了一個優(yōu)化工具(Optimizer)r.js,當模塊部署完畢以后,可以用這個工具將多個模塊合并在一個文件中,實現(xiàn)前端文件的壓縮與合并, 減少HTTP請求數(shù)。
我們來看一個require.js的例子
//a.js define(function(){ console.log("a.js執(zhí)行"); return { hello: function(){ console.log("hello, a.js"); } } });
//b.js define(function(){ console.log("b.js執(zhí)行"); return { hello: function(){ console.log("hello, b.js"); } } });
//main.js require.config({ paths: { "jquery": "../js/jquery.min" }, }); require(["jquery","a", "b"], function($, a, b){ console.log("main.js執(zhí)行"); a.hello(); $("#btn").click(function(){ b.hello(); }); })
上面的main.js被執(zhí)行的時候,會有如下的輸出:
a.js執(zhí)行
b.js執(zhí)行
main.js執(zhí)行
hello, a.js
在點擊按鈕后,會輸出:
hello, b.js
但是如果細細來看,b.js被預先加載并且預先執(zhí)行了,(第二行輸出),b.hello這個方法是在點擊了按鈕之后才會執(zhí)行,如果用戶壓根就沒點,那么b.js中的代碼應不應該執(zhí)行呢?
這其實也是AMD/RequireJs被吐槽的一點,由于瀏覽器的環(huán)境特點,被依賴的模塊肯定要預先下載的。問題在于,是否需要預先執(zhí)行?如果一個模塊依賴了十個其他模塊,那么在本模塊的代碼執(zhí)行之前,要先把其他十個模塊的代碼都執(zhí)行一遍,不管這些模塊是不是馬上會被用到。這個性能消耗是不容忽視的。
另一點被吐槽的是,在定義模塊的時候,要把所有依賴模塊都羅列一遍,而且還要在factory中作為形參傳進去,要寫兩遍很大一串模塊名稱,像這樣:
define(["a", "b", "c", "d", "e", "f", "g"], function(a, b, c, d, e, f, g){ ..... })CMD
CMD 即Common Module Definition, CMD是sea.js的作者在推廣sea.js時提出的一種規(guī)范.
在 CMD 規(guī)范中,一個模塊就是一個文件。代碼的書寫格式如下:
define(function(require, exports, module) { // 模塊代碼 // 使用require獲取依賴模塊的接口 // 使用exports或者module或者return來暴露該模塊的對外接口 })
也是用全局的define函數(shù)定義模塊, 無需羅列依賴數(shù)組,在factory函數(shù)中需傳入形參require,exports,module.
require 用來加載一個 js 文件模塊,require 用來獲取指定模塊的接口對象 module.exports。
//a.js define(function(require, exports, module){ console.log("a.js執(zhí)行"); return { hello: function(){ console.log("hello, a.js"); } } });
//b.js define(function(require, exports, module){ console.log("b.js執(zhí)行"); return { hello: function(){ console.log("hello, b.js"); } } });
//main.js define(function(require, exports, module){ console.log("main.js執(zhí)行"); var a = require("a"); a.hello(); $("#b").click(function(){ var b = require("b"); b.hello(); }); });
上面的main.js執(zhí)行會輸出如下:
main.js執(zhí)行
a.js執(zhí)行
hello, a.js
a.js和b.js都會預先下載,但是b.js中的代碼卻沒有執(zhí)行,因為還沒有點擊按鈕。當點擊按鈕的時候,會輸出如下:
b.js執(zhí)行
hello, b.js
Sea.js加載依賴的方式
加載期:即在執(zhí)行一個模塊之前,將其直接或間接依賴的模塊從服務器端同步到瀏覽器端;
執(zhí)行期:在確認該模塊直接或間接依賴的模塊都加載完畢之后,執(zhí)行該模塊。
AMD vs CMD
AMD推崇依賴前置,在定義模塊的時候就要聲明其依賴的模塊,
CMD推崇就近依賴,只有在用到某個模塊的時候再去require,
AMD和CMD最大的區(qū)別是對依賴模塊的執(zhí)行時機處理不同
同樣都是異步加載模塊,AMD在加載模塊完成后就會執(zhí)行改模塊,所有模塊都加載執(zhí)行完后會進入require的回調(diào)函數(shù),執(zhí)行主邏輯.
CMD加載完某個依賴模塊后并不執(zhí)行,只是下載而已,在所有依賴模塊加載完成后進入主邏輯,遇到require語句的時候才執(zhí)行對應的模塊,這樣模塊的執(zhí)行順序和書寫順序是完全一致的。
這也是很多人說AMD用戶體驗好,因為沒有延遲,依賴模塊提前執(zhí)行了,CMD性能好,因為只有用戶需要的時候才執(zhí)行的原因。
ES6模塊上述的這幾種方法都不是JS原生支持的, 在ECMAScript 6 (ES6)中,引入了模塊功能, ES6 的模塊功能汲取了CommonJS 和 AMD 的優(yōu)點,擁有簡潔的語法并支持異步加載,并且還有其他諸多更好的支持。
簡單來說,ES6 模塊的設計思想就是:一個 JS 文件就代表一個 JS 模塊。在模塊中你可以使用 import 和 export 關鍵字來導入或?qū)С瞿K中的東西。
ES6 模塊主要具備以下幾個基本特點:
自動開啟嚴格模式,即使你沒有寫 use strict
每個模塊都有自己的上下文,每一個模塊內(nèi)聲明的變量都是局部變量,不會污染全局作用域
模塊中可以導入和導出各種類型的變量,如函數(shù),對象,字符串,數(shù)字,布爾值,類等
每一個模塊只加載一次,每一個 JS 只執(zhí)行一次, 如果下次再去加載同目錄下同文件,直接從內(nèi)存中讀取。
補充: Typescript 識別模塊的模式一般來講,組織聲明文件的方式取決于庫是如何被使用的。 在JavaScript中一個庫有很多使用方式,這就需要你書寫聲明文件去匹配它們.
通過庫的使用方法及其源碼來識別庫的類型。
全局庫
全局庫是指能在全局命名空間下訪問的,許多庫都是簡單的暴露出一個或多個全局變量。 比如jQuery.
當你查看全局庫的源代碼時,你通常會看到:
頂級的var語句或function聲明
一個或多個賦值語句到window.someName
模塊化庫
一些庫只能工作在模塊加載器的環(huán)境下。 比如,像 express只能在Node.js 里工作所以必須使用CommonJS的require函數(shù)加載。
模塊庫至少會包含下列具有代表性的條目之一:
無條件的調(diào)用require或define
像import * as a from "b"; or export c;這樣的聲明
賦值給exports或module.exports
UMD (Universal Module Definition)庫
UMD創(chuàng)造了一種同時使用兩種規(guī)范的方法,并且也支持全局變量定義。所以UMD的模塊可以同時在客戶端和服務端使用。 本質(zhì)上,UMD 是一套用來識別當前環(huán)境支持的模塊風格的 if/else 語句。下面是一個解釋其功能的例子:
(function (root, factory) { if (typeof define === "function" && define.amd) { define(["libName"], factory); } else if (typeof module === "object" && module.exports) { module.exports = factory(require("libName")); } else { root.returnExports = factory(root.libName); } }(this, function (b) {})前端自動化構(gòu)建工具
Grunt
Gulp
Webpack
Browserify
......
簡單的說,Grunt / Gulp 和 browserify / webpack 不是一回事。
Gulp / Grunt Gulp / Grunt 是一種工具,能夠優(yōu)化前端工作流程。比如自動刷新頁面、combo、壓縮css、js、編譯less等等。簡單來說,就是使用Gulp/Grunt,然后配置你需要的插件,就可以把以前需要手工做的事情讓它幫你做了。
說到 browserify / webpack ,那還要說到 seajs / requirejs 。這四個都是JS模塊化的方案。其中seajs / require 是一種類型,browserify / webpack 是另一種類型。seajs / require : 是一種在線"編譯" 模塊的方案,相當于在頁面上加載一個 CMD/AMD 解釋器。這樣瀏覽器就認識了 define、exports、module 這些東西。也就實現(xiàn)了模塊化。
browserify / webpack : 是一個預編譯模塊的方案,相比于上面 ,這個方案更加智能, 首先,它是預編譯的,不需要在瀏覽器中加載解釋器。另外,你在本地直接寫JS,不管是 AMD / CMD / ES6 風格的模塊化,它都能認識,并且編譯成瀏覽器認識的JS。這樣就知道,Gulp是一個工具,而webpack等等是模塊化方案。Gulp也可以配置seajs、requirejs甚至webpack的插件。
Grunt每次運行grunt 時,他就利用node提供的require()系統(tǒng)查找本地安裝的 Grunt。
如果找到一份本地安裝的 Grunt,grunt-CLI就將其加載,并傳遞Gruntfile中的配置信息,然后執(zhí)行你所指定的任務。
安裝grunt-cli
npm install -g grunt-cli
配置gruntfile.js文件
module.exports = function(grunt) { // 項目配置. grunt.initConfig({ // 定義Grunt任務 }); // 加載能夠提供"uglify"任務的插件。 grunt.loadNpmTasks("grunt插件"); // Default task(s). grunt.registerTask("default", ["任務名"]); }gulp
gulp是基于Nodejs的自動化任務運行器,它能自動化地完成javascript/sass/less/html/image/css 等文件的的測試、檢查、合并、壓縮、格式化、瀏覽器自動刷新、部署文件生成,并監(jiān)聽文件在改動后重復指定的這些步驟。
使用Gulp的優(yōu)勢就是利用流的方式進行文件的處理,使用管道(pipe)思想,前一級的輸出,直接變成后一級的輸入,通過管道將多個任務和操作連接起來,因此只有一次I/O的過程,流程更清晰,更純粹。Gulp去除了中間文件,只將最后的輸出寫入磁盤,整個過程因此變得更快。
使用Gulp,可以避免瀏覽器緩存機制,性能優(yōu)化(文件合并,減少http請求;文件壓縮)以及效率提升(自動添加CSS3前綴;代碼分析檢查)
browserifyBrowserify 是一個模塊打包器,它遍歷代碼的依賴樹,將依賴樹中的所有模塊打包成一個文件。有了 Browserify,我們就可以在瀏覽器應用程序中使用 CommonJS 模塊。
browserify模塊化的用法和node是一樣的,所以npm上那些原本僅僅用于node環(huán)境的包,在瀏覽器環(huán)境里也一樣能用.
webpack官網(wǎng)有對二者的使用方法進行對比,可以看一下:[webpack for browserify users
](http://webpack.github.io/docs...
browserify main.js -o bundle.js
Compare Webpack vs Browserify vs RequireJS
webpack官網(wǎng)對webpack的定義是MODULE BUNDLER(模塊打包器),他的目的就是把有依賴關系的各種文件打包成一系列的靜態(tài)資源。 請看下圖
Webpack的工作方式是:把你的項目當做一個整體,通過一個給定的主文件(如:main.js),Webpack將從這個文件開始找到你的項目的所有依賴文件,使用loaders處理它們,最后打包為一個(或多個)瀏覽器可識別的JavaScript文件。
webpack核心概念 1. 入口(entry):webpack將創(chuàng)建所有應用程序的依賴關系圖表(dependency graph)。
entry配置項告訴Webpack應用的根模塊或起始點在哪里,
入口起點告訴 webpack 從哪里開始,并遵循著依賴關系圖表知道要打包什么。可以將應用程序的入口起點認為是根上下文或 app 第一個啟動文件。它的值可以是字符串、數(shù)組或?qū)ο?
//webpack.config.js const config = { entry: { app: "./src/app.js", vendors: "./src/vendors.js" } };2. 出口(output)
將所有的資源(assets)合并在一起后,我們還需要告訴 webpack 在哪里打包我們的應用程序。output 選項控制 webpack 如何向硬盤寫入編譯文件。注意,即使可以存在多個入口起點,但只指定一個輸出配置。
output: { path: helpers.root("dist/nonghe"), publicPath: "/", filename: "js/[name].[chunkhash].bundle.js", chunkFilename: "js/[name].[chunkhash].bundle.js" }3. 加載器(loader)
在webpack的世界里, 一切皆模塊, 通過 loader 的轉(zhuǎn)換,任何形式的資源都可以視作模塊,比如 CommonJs 模塊、 AMD 模塊、 ES6 模塊、CSS、圖片、 JSON、Coffeescript、 LESS 等。而且 webpack 只理解 JavaScript。
對比 Node.js 模塊,webpack 模塊能夠以各種方式表達它們的依賴關系:
ES2015 import 語句
CommonJS require() 語句
AMD define 和 require 語句
css/sass/less 文件中的 @import 語句。
樣式(url(...))或 HTML 文件()中的圖片鏈接
webpack compiler在碰到上面那些語句的時候, 通過與其相對應的loader將這些文件進行轉(zhuǎn)換,而轉(zhuǎn)換后的文件會被添加到依賴圖表中。
module: { loaders: [{ test: /.scss$/, loaders: "style!css!sass" }, { test: /.(png|jpg|svg)$/, loader: "url?limit=20480" //20k }] }}4. 插件(plugin)
plugin 插件,用于擴展webpack的功能,在webpack構(gòu)建生命周期的節(jié)點上加入擴展hook為webpack加入功能。
Loaders和Plugins常常被弄混,但是他們其實是完全不同的東西,可以這么來說,loaders是在打包構(gòu)建過程中用來處理源文件的(js,ts, Scss,Less..),一次處理一個,通常作用于包生成之前或生成的過程中。
插件并不直接操作單個文件,它直接對整個構(gòu)建過程其作用。
幾款常用的插件
HtmlWebpackPlugin : 這個插件的作用是依據(jù)一個簡單的html模板,生成一個自動引用打包后的JS文件的新index.html。
Hot Module Replacement: 它允許你在修改組件代碼后,自動刷新實時預覽修改后的效果。
CommonsChunkPlugin: 對于有多個入口文件的, 可以抽取公共的模塊,最終合成的文件能夠在最開始的時候加載一次,便存起來到緩存中供后續(xù)使用。
DefinePlugin: 允許你創(chuàng)建一個在編譯時可以配置的全局常量。這可能會對開發(fā)模式和發(fā)布模式的構(gòu)建允許不同的行為非常有用。
ExtractTextWebpackPlugin: 它會將打包在js代碼中的樣式文件抽離出來, 放到一個多帶帶的 css 包文件 (styles.css)當中, 這樣js代碼就可以和css并行加載.
UglifyjsWebpackPlugin: 這個插件使用 UglifyJS 去壓縮你的JavaScript代碼。
webpack構(gòu)建流程從啟動webpack構(gòu)建到輸出結(jié)果經(jīng)歷了一系列過程,它們是:
解析webpack配置參數(shù),合并從shell傳入和webpack.config.js文件里配置的參數(shù),生產(chǎn)最后的配置結(jié)果。
注冊所有配置的插件,讓插件監(jiān)聽webpack構(gòu)建生命周期的事件節(jié)點,以做出對應的反應。
從配置的entry入口文件開始解析文件構(gòu)建依賴圖譜,找出每個文件所依賴的文件,遞歸下去。
在解析文件遞歸的過程中根據(jù)文件類型和loader配置找出合適的loader用來對文件進行轉(zhuǎn)換。
遞歸完后得到每個文件的最終結(jié)果,根據(jù)entry配置生成代碼塊chunk。
輸出所有chunk到文件系統(tǒng)。
代碼拆分(Code Splitting)代碼拆分是 webpack 中最引人注目的特性之一。你可以把代碼分離到不同的 bundle 中,然后就可以去按需加載這些文件.
分離資源,實現(xiàn)緩存資源
分離第三方庫(vendor) CommonsChunkPlugin
分離 CSS
傳統(tǒng)的模塊打包工具(module bundlers)最終將所有的模塊編譯生成一個龐大的bundle.js文件。因此Webpack使用許多特性來分割代碼然后生成多個“bundle”文件,而且異步加載部分代碼以實現(xiàn)按需加載
使用 require.ensure() 按需分離代碼
require.ensure(dependencies: String[], callback: function(require), chunkName: String)模塊熱替換(Hot Module Replacement)
模塊熱替換功能會在應用程序運行過程中替換、添加或刪除模塊,而無需重新加載頁面。這使得你可以在獨立模塊變更后,無需刷新整個頁面,就可以更新這些模塊.
webpack-dev-server 支持熱模式,在試圖重新加載整個頁面之前,熱模式會嘗試使用 HMR 來更新。
webpack-dev-server 主要是啟動了一個使用 express 的 Http服務器 。它的作用 主要是用來伺服資源文件 。此外這個 Http服務器 和 client 使用了 websocket 通訊協(xié)議,原始文件作出改動后, webpack-dev-server 會實時的編譯,但是最后的編譯的文件并沒有輸出到目標文件夾, 實時編譯后的文件都保存到了內(nèi)存當中。
"server": "webpack-dev-server --inline --progress --hot",
webpack-dev-server 支持2種自動刷新的方式:
Iframe mode
Iframe mode 是在網(wǎng)頁中嵌入了一個 iframe ,將我們自己的應用注入到這個 iframe 當中去,因此每次你修改的文件后,都是這個 iframe 進行了 reload 。
inline mode
而 Inline-mode ,是 webpack-dev-server 會在你的 webpack.config.js 的入口配置文件中再添加一個入口,
module.exports = { entry: { app: [ "webpack-dev-server/client?http://localhost:8080/", "./src/js/index.js" ] }, output: { path: "./dist/js", filename: "bundle.js" } }
這樣就完成了將 inlinedJS 打包進 bundle.js 里的功能,同時 inlinedJS 里面也包含了 socket.io 的 client 代碼,可以和 webpack-dev-server 進行 websocket 通訊。
其他配置選項
--hot 開啟 Hot Module Replacement功能
--quiet 控制臺中不輸出打包的信息
--compress 開啟gzip壓縮
--progress 顯示打包的進度
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/90329.html
摘要:簡介來構(gòu)建用戶界面的庫,不是框架關注于層虛擬單向數(shù)據(jù)流這些概念如何使用下載文件也可以使用,需要用到的模塊介紹是編寫組件的一種語法規(guī)范,可以看為是的擴展,它支持將和混寫在一起,最后使用編譯為常規(guī)的,方便瀏覽器解析編寫第一個例子使用編寫組件 react簡介 來構(gòu)建用戶界面的庫,不是框架 關注于view層 虛擬DOM 單向數(shù)據(jù)流 JSX這些概念 如何使用react 下載文件 rea...
摘要:由于本篇我們只講的基本使用,故這里不再深入講解,有興趣的可以點擊這里學習。使用的方式有三種使用方式,如下配置推薦在文件中指定。下一篇會給大家介紹系列之及簡單的使用 歡迎大家訪問我的github blog查看更多文章 webpack系列之loader及簡單的使用 一. loader有什么用 webpack本身只能打包Javascript文件,對于其他資源例如 css,圖片,或者其他的語...
摘要:插件開發(fā)前端掘金作者原文地址譯者插件是為應用添加全局功能的一種強大而且簡單的方式。提供了與使用掌控異步前端掘金教你使用在行代碼內(nèi)優(yōu)雅的實現(xiàn)文件分片斷點續(xù)傳。 Vue.js 插件開發(fā) - 前端 - 掘金作者:Joshua Bemenderfer原文地址: creating-custom-plugins譯者:jeneser Vue.js插件是為應用添加全局功能的一種強大而且簡單的方式。插....
摘要:我們也可以不用在命令行里面輸入,因為我們可能以后會查詢更多東西,因此我們可以,在的里面加入這里的和只是為了輸出進度條和,沒有實際意義,然后在命令行輸入就可以默認使用進行打包了。更具體的就請查看一下官方文檔了,畢竟篇幅不能太長。 Webpack 網(wǎng)上有很多webpack的介紹,也有不少的視頻,但是不少人看到應該還是不是很了解webpack里面到底是講什么,而且報錯了之后也是不知所措 那么...
摘要:我們也可以不用在命令行里面輸入,因為我們可能以后會查詢更多東西,因此我們可以,在的里面加入這里的和只是為了輸出進度條和,沒有實際意義,然后在命令行輸入就可以默認使用進行打包了。更具體的就請查看一下官方文檔了,畢竟篇幅不能太長。 Webpack 網(wǎng)上有很多webpack的介紹,也有不少的視頻,但是不少人看到應該還是不是很了解webpack里面到底是講什么,而且報錯了之后也是不知所措 那么...
閱讀 2568·2021-11-22 13:53
閱讀 4069·2021-09-28 09:47
閱讀 858·2021-09-22 15:33
閱讀 809·2020-12-03 17:17
閱讀 3315·2019-08-30 13:13
閱讀 2121·2019-08-29 16:09
閱讀 1176·2019-08-29 12:24
閱讀 2452·2019-08-28 18:14