webpack的核心概念:
· entry 一個可執行模塊或庫的入口文件。
· chunk 多個文件組成的一個代碼塊,例如把一個可執行模塊和它全部依賴的模塊組合和一個 chunk 這體現了webpack的打包機制。
· loader 文件轉換器,例如把es6轉換爲es5,scss轉換爲css。
· plugin 插件,用於擴展webpack的功能,在webpack構建生命週期的節點上加入擴展hook爲webpack加入功能。
從啓動webpack構建到輸出結果經歷了一系列過程,它們是:
1. 解析webpack配置參數,合併從shell傳入和webpack.config.js文件裏配置的參數,生產最後的配置結果。
2. 註冊全部配置的插件,好讓插件監聽webpack構建生命週期的事件節點,以作出對應的反應。
3. 從配置的entry入口文件開始解析文件構建AST語法樹,找出每一個文件所依賴的文件,遞歸下去。
4. 在解析文件遞歸的過程當中根據文件類型和loader配置找出合適的loader用來對文件進行轉換。
5. 遞歸完後獲得每一個文件的最終結果,根據entry配置生成代碼塊chunk。
6. 輸出全部chunk到文件系統。
須要注意的是,在構建生命週期中有一系列插件在合適的時機作了合適的事情,好比UglifyJsPlugin會在loader轉換遞歸完後對結果再使用UglifyJs壓縮覆蓋以前的結果。
webpack是react項目標配的打包工具,和NPM搭配起來使用管理模塊實在很是方便。
webapck 把全部的靜態資源都看作是一個 module,經過 webpack,將這些 module 組成到一個 bundle 中去,從而實如今頁面上引入一個 bundle.js,來實現全部靜態資源的加載。
webpack 打包後源碼有讀過嗎 模塊之間怎麼依賴的
每一個模塊都會被賦予一個id(正常是從0開始的數字),模塊之間經過內置的__webpack_require__函數來模擬CommonJS,從而創建聯繫
webpack打包流程
流程圖: https://img.alicdn.com/tps/TB1GVGFNXXXXXaTapXXXXXXXXXX-4436-4244.jpg
webpack中的ESlint怎麼配置
1).安裝
須要這幾個npm包:
· eslint
· eslint-loader
· eslint-plugin-html (用以lint一些在html文件裏面經過script包裹的js代碼,它默認的匹配規則是不帶type屬性,或者是`/^(application|text)/(x-)?(javascript|babel|ecmascript-6)$/i`,具體的內容請查閱相關文檔,經過cli啓動lint的時候定義文件後綴名時eslint --ext .html,.js)
· eslint-config-standard (和javascript-style-standard風格指南須要的包)
· eslint-plugin-promise
· eslint-plugin-standard
· eslint-friendly-formatter (生成的報告格式)
2).配置ESlint
關於eslint的配置方式。比較多元化:
· js註釋
· .eslintrc.*文件
· package.json裏面配置eslintConfig字段
可使用任何一個配置來配置ESlint,對於ESlint如何配置,這個裏就不贅述了.
3).配置webpack
在webpack中的js模塊處進行eslint-loader的配置,示例代碼以下所示:
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/, // exclude: /node_modules/ 能夠不用定義這個字段的屬性值,eslint會自動忽略node_modules
enforce: 'pre', // 在babel-loader對源碼進行編譯前進行lint的檢查
include: /src/, // src文件夾下的文件須要被lint
use: [{
loader:'babel-loader'
},{
loader: 'eslint-loader',
options: {
formatter: require('eslint-friendly-formatter') // 編譯後錯誤報告格式
}
}],
query: {
cacheDirectory: true
}
}
]
}
4).配置package.json
在package.json中配置npm命令:
{
...
"lint": "eslint --ext .js src"
...
}
而後執行npm run lint 來進行代碼的靜態檢查
定位 Webpack 速度慢的緣由
打包的命令webpack後加三個參數:
-
--colors 輸出結果帶彩色,好比:會用紅色顯示耗時較長的步驟
-
--profile 輸出性能數據,能夠看到每一步的耗時
-
--display-modules 默認狀況下 node_modules 下的模塊會被隱藏,加上這個參數能夠顯示這些被隱藏的模塊
從命令行的結果裏具體分析速度慢的緣由。
經過Resolve設置,提升模塊分析依賴的速度
resolve主要是用來配置解析模塊路徑和分析依賴,可讓require模塊的定位更快。
1.resolve.alias
別名是 Webpack 的一個配置項,它的做用是把用戶的一個請求重定向到另外一個路徑 。若是在alias中定義了值,而後在代碼中require該值的時候,會重定向到alias指定的位置。
2.resolve.root和resolve.modulesDirectories
root是經過絕對路徑的方式來定義查找模塊的文件夾。能夠是一個數組,主要是用來增長模塊的搜尋位置使用的。
modulesDirectories是用來設置搜索的目錄名的,默認值:["web_modules", "node_modules"]。若是把值設置成["mydir"]
, webpack會查詢 「./mydir」, 「../mydir」, 「../../mydir」等。
注意: Passing"../someDir","app","."or an absolute path isn’t necessary here. Just use a directory name, not a path. Use only if you expect to have a hierarchy within these folders. Otherwise you may want to use theresolve.root
option instead.
配置module.noParse
module.noParse是webpack的另外一個頗有用的配置項,若是你 肯定一個模塊中沒有其它新的依賴就能夠配置這項,webpack將再也不掃描這個文件中的依賴。
module: {
noParse: [/moment-with-locales/]
}
配置Loader的exclude或include來設定babel的使用範圍
對於不少的 npm 包來講,他們徹底沒有通過 babel 的必要(成熟的 npm 包會在發佈前將本身 es5,甚至 es3 化),讓這些包經過 babel 會帶來巨大的性能負擔。
使用 exclude,屏蔽掉 npm 裏的包,從而使整包的構建效率飛速提升。
module: {
loaders: [ {
test: /\.js(x)*$/,
loader: 'babel-loader',
exclude: function(path) {
// 路徑中含有 node_modules 的就不去解析。
var isNpmModule = !!path.match(node_modules/);
return isNpmModule;
},
query: {
presets: ['react', 'es2015-ie', 'stage-1']
}
} ]
}
甚至,在十分確信的狀況下,使用 include 來限定 babel 的使用範圍,進一步提升效率。
module: {
loaders: [ {
test: /\.js(x)*$/,
loader: 'babel-loader',
include: [
// 只去解析運行目錄下的 src 和 demo 文件夾
path.join(process.cwd(), './src'),
path.join(process.cwd(), './demo')
],
query: {
presets: ['react', 'es2015-ie', 'stage-1']
}
} ]
}
使用externals,把不須要打包的模塊排除在外
Webpack 能夠配置 externals來將依賴的庫指向全局變量,從而再也不打包這個庫。在頁面上引入 Web 上的公用 CDN 服務。
webpack中配置:
externals: { moment: true }
頁面html上引入script:
<script src="//apps.bdimg.com/libs/moment/2.8.3/moment-with-locales.min.js"></script>
等於讓 Webpack 知道,對於 moment這個模塊就不要打包啦,直接指向 window.moment就好。不過別忘了加載moment-with-locales.min.js,讓全局中有 moment這個變量。
使用DLL & DllReference
除了正在開發的源代碼以外,一般還會引入不少第三方 NPM 包,這些包咱們不會進行修改,可是仍然須要在每次 build 的過程當中消耗構建性能,那有沒有什麼辦法能夠減小這些消耗呢?DLLPlugin 就是一個解決方案,他經過前置這些依賴包的構建,來提升真正的 build 和 rebuild 的構建效率。
首先,咱們來寫一個 DLLPlugin 的 config 文件。定義webpack-dll-config.js文件:
const path = require('path');
const webpack=require('webpack');
const vendors=[
'react',
'react-dom',
'react-router',
'history',
'immutable',
'redux',
'react-redux',
'redux-router',
'redux-thunk',
'moment',
'es6-promise',
'whatwg-fetch',
'lodash'
];
module.exports={
entry:{
'vendor':vendors,
},
output:{
path:path.join(__dirname, 'dist'),
filename:'[name].dll.js',//[name]的部分由entry的名字替換
/**
* output.library
* 將會定義爲 window.${output.library}
* 在此次的例子中,將會定義爲`window.vendor_library`
*/
library:'[name]_library',
},
plugins:[
new webpack.DllPlugin({
/**
* path 定義 manifest 文件生成的位置
*/
path:'manifest.json',
/**
* name 是dll暴露的對象名,要跟 output.library 保持一致;
* dll bundle 輸出到那個全局變量上
*/
name: '[name]_library',
context:__dirname //是解析包路徑的上下文,這個要跟接下來配置的 webpack.config.js 一致。
})
]
}
執行 命令【webpack --config webpack-dll-config.js 】就會在 dist 目錄下生成 dll bundle 和在根目錄生成對應的 manifest文件。manifest 文件的格式大體以下,由包含的 module 和對應的 id 的鍵值對構成。
接下來經過 DLLReferencePlugin 來使用剛纔生成的 DLL Bundle。在默認的webpack-config.js中添加plugins:
new webpack.DllReferencePlugin({
context: __dirname,//context 須要跟dll中的保持一致,這個用來指導 Webpack 匹配 manifest 中庫的路徑;
manifest: require('./manifest.json')
}),
最後在頁面中要引入兩個js
<body>
<script src="dist/vendor.dll.js"></script>
<script src="dist/bundle.js"></script></body>
使用DLL這樣的方式的能夠把第三方包和本身的代碼包分離,有修改也只須要發佈本身的代碼包。
關於優化插件OPTIMIZATION
webpack 提供了一些能夠優化瀏覽器端性能的優化插件,如UglifyJsPlugin,OccurrenceOrderPlugin 和 DedupePlugin,都很實用,也都在消耗構建性能(UglifyJsPlugin 很是耗性能),若是你是在開發環境下,這些插件最好都不要使用,畢竟腳本大一些,跑的慢一些這些比起每次構建要耗費更多時間來講,顯然仍是後者更會消磨開發者的耐心,所以,只在正產環境中使用 OPTIMIZATION。
CommonsChunkPlugin
當你的 webpack 構建任務中有多個入口文件,而這些文件都 require 了相同的模塊,若是你不作任何事情,webpack 會爲每一個入口文件引入一份相同的模塊,顯然這樣作,會使得相同模塊變化時,全部引入的 entry 都須要一次 rebuild,形成了性能的浪費,CommonsChunkPlugin 能夠將相同的模塊提取出來單獨打包,進而減少 rebuild 時的性能消耗。
同時將多個入口文件相同的js打包處一個共同的後,也能夠利用緩存,使加載第二頁面的時候不須要再加載共同文件。
commonsPlugin = newwebpack.optimize.CommonsChunkPlugin('common', 'common.[hash].js')