1.webpack基本概念
- 0配置 webpack4如今是支持0配置的
- 基本概念 entry output loader plugins mode
- file module chunks compiler complilation tapable事件流
2.從0開始配置
- 初始化項目 npm init git init
- 新增 .gitignore文件 src目錄(index.js) webpack.config.js
- 安裝webpack npm install -D webpack webpack-cli(不推薦全局安裝)
- 在package.json文件中新增script的build指令(指定mode) 或者使用npx命令
- 在webpack.config.js中簡單配置entry output(path必須是絕對路徑)
- 執行npm run build獲得打包以後的js文件
3.簡單分析下build生成的js文件
- 基本架構是一個函數的調用(function(modules) {}) ({key-value})
- function內部實現一個__webpack_require__方法(緩存優化)
- 函數return webpack_require(入口文件)
- 參數是一個對象(webpack3是一個數組),是一個key-value鍵值對的形式
- key是文件的路徑"./src/index.js"(項目的根目錄的路徑)value是函數體
4.基本概念的一些介紹
- entry入口 支持多種寫法 字符串 數組 對象(多入口)
- output出口 path屬性必須是絕對路徑 filename (emit)
- loader webpack自身只支持js文件的處理 其餘的模塊(css)須要使用loader來作轉換
- loader的多種寫法
- loader暴露的就是一個函數 接收一個source參數
- 注意loader的執行順序[style-loader,css-loader]
- resolveLoader用來配置查找loader的目錄(默認是找node_modules的)
- plugins 是webpack的一等公民(函數是js的一等公民)
- plugin比loader執行範圍更廣的任務
- tapable的事件流
- 須要實現一個apply (compiler)方法 參數是compiler
- compiler對象是webpack中一個很是核心的對象
- webpack內部是存在一個時間流tapable的.從entry配置的module開始解析entry依賴的全部module,每找到一個module就根據配置的loader去找對應的轉換規則,遞歸執行,而後將生成的chunk轉換爲文件輸出,在整個過程當中 webpack會在恰當的時機執行plugin中訂閱的事件
5.webpack的基本過程介紹
- 初始化參數 從配置文件和shell語句讀取與合併參數 獲得最終的參數
- 開始編譯 使用上一步獲得的參數 初始化compiler對象,加載配置的插件(forEach遍歷),執行對象的run方法開始編譯
- 編譯模板 從入口文件出發 根據不一樣模塊使用對應的loader,找出模塊依賴的模塊遞歸執行
- 完成模板的編譯 獲得每一個模塊編譯的模塊和模塊之間的依賴關係
- 輸出資源 根據入口和模塊的依賴關係 組裝成一個個包含多個模塊的chunk 再將每一個chunk轉換成一個單獨的文件加入到輸出列表
- 輸出完成 肯定好輸出內容根據配置的output把文件內容寫於到文件系統
- webpack會在特定的時間點廣播特定的事件 插件再監聽到對應的事件就會執行對應的邏輯
- plugins的順序是不關心的(事件的訂閱是不分前後的)
6.開始配置webpack.config.js文件
沒有上代碼是由於我比較蠢 通常都是copy別人的配置 作一些修改(允悲)css
- 樣式文件的處理
- css-loder 對樣式文件一個路徑的處理
- style-loader 生成style標籤
- less less-loader對less文件的處理
- node-sass(npm常常按照失敗) sass-loder
- autoprefixer postcss-loader 自動添加瀏覽器前綴 配置.postcssrc.js文件
- vue-cli2中使用了utils根據不一樣的後綴加載不一樣的loader
- OptimizeCSSPlugin插件 提取css樣式文件
- ExtractTextPlugin替換爲MiniCssExtractPlugin插件
- 圖片 字體圖標的處理
- url-loader 對file-loader的一層封裝(能夠處理二進制)
- 打包出來的只有js文件 要手動的寫一個html文件引入 怎麼解決
- 使用html-webpack-plugin插件
- 能夠new多個
- 每次都須要build對調試很不友好
- npm install -D webpack-dev-server 從在本地起一個服務
- 配置devServer proxy一般會用來解決跨域的問題
- 在打包以前想刪除以前的dist目錄
- 輸出filename定義了hash會根據內容的變化生成不少的文件
- clean-webpack-plugin插件
- hash、chunkhash、contenthash的區別?
- 拷貝static目錄中的資源
- 代碼規範
- eslint的檢查 配置.eslintrc.js和.eslintignore
- eslint eslint-loader eslint-plugin-standard eslint-friendly-formatter等
- 使用husky配置pre-commit在代碼git commit以前作檢驗
- js文件的處理
- 主要就是使用babel來作轉換
- @babel/core babel-loader @babel/preset-env
- 配置babel.config.js文件 配置presets預設 和plugins 插件
- vue項目的配置
- vue-loader vue-template-compiler vue-style-loader eslint-plugin-vue babel-plugin-transform-vue-jsx vue vuex vue-router axios
- 須要顯示的new VueLoaderPlugin()
- babel的一些配置 eslint規則的修改
- react項目的配置
- @babel/preset-react @babel/plugin-proposal-class-properties @babel/plugin-proposal-decorators @babel/plugin-syntax-dynamic-import等
7.常見的一些優化
- 減小文件的搜索訪問 resolve alias exclude mainFields
- module.noParse不須要遞歸解析此模塊(ele的UI框架)
- dll動態連接庫(代碼塊)將基礎模塊打包出來到單獨的動態連接庫中在須要導入的時候直接到鏈接庫中webpack.dll.config.js
- 多線程 happypack webpack-parallel-uglify-plugin(js多線程壓縮)
- cdn 靜態資源放在cdn服務器上(注意pubilcPath的配置)
- 提取公共代碼,代碼分離
- 入口的起點分離 entry分割
- 懶加載 import在webpack就是個自然的分割器 使用jsonp形式加載的
- 基礎類庫 長期緩存
- 頁面之間的公用代碼
- 配置optimization:中的splitChunks(分割代碼)
- tree shaking剔除無用的死代碼做用域等
8.其餘一些配置
- 懶加載 import npm install @babel/plugin-syntax-dynamic-import
- resolve的配置 extensions擴展 alias別名配置
- devtool source-map文件 源碼映射 定位錯誤
- devServer 這個配置很重要 代理屬性 hot https等
- 區分不一樣環境的配置 cross-env 定義環境變量 webpack-merge作配置的合併
9.vue-cli2升級webpack的過程
- 安裝最新的webpack webpck-cli webpack-dev-server
- 更新一些loader plugin eslint babel的升級使用自動升級工具
- webpack相關的 npm install --save-dev webpack@latest webpack-cli webpack-dev-server@latest webpack-dev-middleware@latest webpack-bundle-analyzer@latest webpack-merge@latest
- 一些loader的升級npm install --save-dev extract-text-webpack-plugin@latest html-webpack-plugin@latest inject-loader@latest friendly-errors-webpack-plugin@latest copy-webpack-plugin@latest optimize-css-assets-webpack-plugin@latest css-loader@latest file-loader@latest url-loader@latest less-loader@latest postcss-loader@latest
- eslint的升級npm install --save-dev eslint@latest eslint-config-standard@latest eslint-friendly-formatter@latest eslint-loader@latest eslint-plugin-import@latest eslint-plugin-node@latest eslint-plugin-promise@latest eslint-plugin-standard@latest eslint-plugin-vue@latest
- vue相關的升級npm install --save-dev vue-template-compiler@latest vue-loader@latest vue-style-loader@latest
- babel的升級npx babel-upgrade --write --install
- mode: 'development'的修改
- 刪除一些內置的插件 例如webpack.NamedModulesPlugin webpack.NoEmitOnErrorsPlugin
- 引入const { VueLoaderPlugin } = require('vue-loader')
- 使用mini-css-extract-plugin 替代extract-text-webpack-plugin
- 代碼分割 將new webpack.optimize改成 optimization: {splitChunks: {}}來配置
10.babel相關
- astexplorer.net/ 獲取代碼對應的ast結構
- @babel/core babel核心庫 用來實現核心的編譯
- @babel/types實現類型的判斷 生成ast零部件
- 使用js parser esprima (webpack使用的是acorn)
- 解析生成ast語法樹 遍歷優化 在生成code 不少都是這樣的一個過程 vue的dom diff
11.自定義loader
- loader就是暴露出一個function出去 source做爲參數
- 最後的loader最先調用 傳入原始的資源
- 異步 async 緩存等
- 實現一個less-loader
// css-loader
let less = require('less')
module.exports = function (source) {
// 將less變成css
less.render(source, (err, result) => {
// 將結果給下一個style-loader處理
this.callback(err, result.css)
})
}
// style-loader
const path = require('path')
module.exports = function (source) {
// 建立一個style標籤 插入到頁面中
let script = (`
let style = document.createElement('style')
style.innerHTML = ${JSON.stringify(source)}
document.head.appendChild(style)
`
)
return script
}
複製代碼
12.自定義plugin
- 插件是webpack的一等公民(明確監聽的事件 觸發的鉤子函數)
- 兩個核心概念 compiler和compilation
- compiler對象表明了完整的webpack環境配置 這個對象在啓動webpack被一次創建 配置好可操做的設置 在webpack應用一個插件事 接收一個compiler對象的引用 能夠用來訪問webpack的主環境
- compilation對象表明了一次資源版本構建 運行webpack中間件時 每當檢測到一個文件的變化 就會建立一個compilation 生成一組新的編譯資源 compilation對象提供了不少關鍵時機的回調 供插件自定義處理使用
- 插件須要實現一個apply方法 執行一個hooks(之前使用的時plugins註冊)
// 一個沒用的插件
class CompilationsPlugin {
constructor (options) {
this.options = options
}
// 這個apply方法名是固定的
apply (compiler) {
// compiler.plugin('compilation', function (compilation) 被廢棄的寫法
compiler.hooks.compilation.tap('CompilationsPlugin', (compilation) => {
// 不一樣的hooks類型 async promise類型等
compilation.hooks.optimize.tap('optimize', () => {
console.log('資源正在被優化')
})
})
}
}
module.exports = CompilationsPlugin
複製代碼
- 常見的鉤子 不一樣的階段
- 初始化階段
- 從配置文件和shell語句讀取和配置參數獲得最終的參數
- 初始化compiler 全局只有一個compiler 該實例包含了完整的webpack配置 來負責文件監聽和啓動配置
- 加載插件 依次調用插件的apply方法 讓插件監聽事件節點
- 給插件傳入compiler實例的引用 方便調用webpack提供的api
- entry-option 讀取配置的entry實例化對應的entryplugin爲遞歸解析作準備
- after-plugin 調用完全部內置和配置插件的apply方法
- after-resolvers 根據配置初始化resolver 負責在文件系統中尋找指定路徑的文件
- 編譯階段
- run 啓動一次新的編譯
- watch-run 監聽模式的編譯
- compile 告訴插件一次新的編譯要啓動
- compilation 每次檢測到文件變化 一個新的compilation被建立
- make 從entry開始讀取文件 根據不一樣文件使用對應的loader作編譯 遞歸
- after-compiler 一次compilation執行完成
- 在compilation還有不少消失件 build-module normal-module-loader program seal
- 輸出階段
- should-emit 須要輸出的文件準備好
- emit 肯定要輸出的文件
- after-emit 文件輸出完成
- failed 在編譯和輸出遇到異常就會退出 直接到failed 能夠獲取到具體的出錯緣由
13.實現一個簡單的webpack(mypack)
- github.com/Lliuxs/my-w…
14.webpack源碼分析
小弟最近準備學習某課網上的webpacck4的教程 分享出來你們一塊兒學習
連接:pan.baidu.com/s/1ATq2VIT0…
提取碼:rqc2html