像Grunt、Gulp這類構建工具,打包的思路是: 遍歷源文件 → 匹配規則 → 打包,這個過程當中作不到按需加載,即對於打包起來的資源,到底頁面用不用,打包過程當中是不關心的。css
webpack跟其餘構建工具本質上的不一樣之處在於: webpack 是從入口文件開始,通過模塊依賴加載、分析和打包三個流程完成項目的構建。在加加載、分析和打包的三個過程當中,能夠針對性的作一些解決方案,好比code split(拆分公共代碼等)。html
固然,webpack還能夠輕鬆的解決傳統構建工具解決的問題:前端
webpack的配置類型是多樣的,最多見的是直接做爲一個對象來使用,除了使用對象,webpack還支持函數 promise和多配置數組。vue
若是咱們打包的目的是生成一個共別人使用的庫,那麼可使用output.library來指定庫的名稱庫的名稱支持佔位符與普通字符串。使用output.library肯定了庫的名稱以後,還可使用output.libraryTarget指定庫打包出來的規範。使用output.externals配置項去除輸出的打包文件中依賴的某些第三方js模塊(例如jquery,vue等)。這些被依賴的模塊應該由使用者提供,而不該該包含再js庫文件中。jquery
[hash]:是整個項目的hash值,其根據每次編譯內容計算獲得,每次編譯以後都會生成新的hash,即修改任何文件都會致使全部文件的hash發生改變;在一個項目中雖然入口不一樣,可是hash是相同的;hash沒法實現前端靜態資源在瀏覽器上長緩存,這時候應該使用chunkhashwebpack
[chunkhash]:根據不一樣的入口文件(entry)進行依賴文件解析,構建對應的chunk,生成相應的hash;只要組成entry的模塊文件沒有變化,則對應hash也是不變的,因此通常項目優化時,會將公共代碼庫拆分到一塊兒,由於公共代碼庫代碼變更較少的,使用chunkhash能夠發揮最長緩存的做用es6
[contenthash]:使用chunkhash存在一個問題,當在一個js文件引入css文件,編譯後他們的hash是相同的。並且,只要js文件內容發生改變,與其關聯的css文件hash也會改變,針對這種狀況,能夠把css從js中抽離出來並使用contenthash。web
// 手寫一個webpack配置最主要的就是 entry, output,module.rules(loader)和plugin module.exports = { entry: './src/index.js', output: { filename: '[name].js', path: path.resolve(__dirname, 'dist') }, module: { rules: [ { test: /\.css$/, use: ['style-loader', 'css-loader'] } ] }, plugins: [ new ExtractTextPlugin({ filename: 'style.css' }) ] }
const html = require('html-loader!./test.html'); console.log(html)
從右向左或者從下至上。數組
模塊是指爲了完成某種功能所需的程序或者子程序,模塊是系統中職責單一且可替換的部分。模塊化開發是指如何開發新的模塊和複用已用的模塊來實現應用的功能。JavaScript可遵循的主流規範有:commonJS,AMD和ES6 module。promise
// main.js const component = require('./component-loader?commponent=demo') // component-loader.js const querystring = require('querystring') const query = querystring.parse(__resourceQuery.slice(1)) // 去掉 ? consolelog(query); // {comonent: demo}
在webpack中,import不只僅是ES6 module的模塊導入方式,仍是一個相似require的函數,咱們能夠經過import('module')的方式引入一個模塊,import()返回的是一個Promise對象;使用import()方式就能夠實現webpack的按需加載。在import()裏能夠添加一些註釋,如定義該chunk的名稱,要過濾的文件,指定引入的文件等等,這類帶有特殊功能的註釋被稱爲神器註釋。
babel的語法轉換是經過強大的插件系統來支持的。babel的插件分爲兩類:轉換插件和語法解析插件。
不一樣的語法對應着不一樣的轉換插件,好比咱們要將箭頭函數轉換成爲es5的函數寫法,那麼能夠單獨安裝@babel/plugin-transform-arrow-functrions插件,若是不想一個個的添加插件,那麼可使用插件組合preset(插件預設,插件組合更加好理解一些),最多見的preset是@babel/preset-env。
babel是一個JavaScript的靜態解析分析編譯器,所謂靜態分析指的的在不須要執行代碼的前提下對代碼進行分析和處理的過程。要實現babel從一個語法轉換成另一種語法,須要通過三個主要步驟:解析,轉換,生成。
解析:指的的首先將代碼通過詞法解析和語法解析,最終生成一棵AST(抽象語法樹),在babel中,語法解析器是Babylon;
轉換:獲得AST以後,能夠對其進行遍歷,在此過程當中對節點進行添加,更新和移除等操做,babel中AST遍歷工具是@babel/traverse;
生成:通過一系列轉換以後獲得的一棵新樹,要將樹轉換成代碼,就是生成的過程,babel用到的是@babel/generator。
在babel中,代碼會由babel先進行解析AST,babel插件作的事情就是寫vistor而已,因此babel插件固定的模板以下:
module.exports = () => { return { name: 'example-plugin', visitor: { Identifier(path, state) {
} } }
}
babel只負責進行語法轉換,即將es6語法轉換成es5語法,但若是是在es5中,有些對象,方法實際在瀏覽器中多是不支持的,例如:promise,array.prototype.includes,這時候就須要@babel/polyfill來作模擬。
@babel/polyfill雖然能夠解決模擬瀏覽器不存在對象方法的事情,可是有如下兩個問題:
爲了解決這個問題,babel社區又提出了@babel/runtime的方案,@babel/runtime再也不修改原型,而是採用替換的方式,好比咱們用promise,使用@babel/polyfill會產生一個window.promise對象,而@babel/runtime則會生成一個_Promise(示例而已)來替換掉咱們代碼中用到的Promise.另外@babel/runtime還支持按需引入。
browserslist就是幫助咱們來設置目標瀏覽器的工具。它實際上就是聲明瞭一段瀏覽器的集合,咱們的工具能夠根據這段集合描述,針對性的輸出兼容性代碼。