webpack4在2月底的時候發佈,此次webpack4有了一個名字"Legato",也就是"連奏"的意思,寓意webpack在不斷進化,並且是無縫(no-gaps)的進化。webpack的進化點是經過捐贈者和用戶投票來決定的,以前在介紹webpack3的時候,曾給出過投票數在前幾名的優化點,集中在用戶體驗、構建性能(速度和產出大小)、通用和適配性(es module、typescript、web assemble)等。webpack4發佈了,下面將結合文檔和實踐,驗證一下webpack是否兌現了當初的諾言。css
webpack3官方發佈的時候,提到了下個版本可能的改動點,翻譯過來以下所示:html
webpack4官方發佈的文檔之中主要說起了如下新特性:vue
該特性主要用於解決webpack的門檻高問題,webpack是一個配置聲明式的操做模式,npm、gulp是指令式的,須要描述每一步是幹什麼的,而webpack的配置項凌亂且無序,讓不少開發者頭疼。
webpack4提供了零配置方案,默認入口屬性爲./src
,默認輸出路徑爲./dist
,再也不須要配置文件,實現了開箱即用的封裝能力,更通俗的講,webpack會自動查找項目中src目錄下的index.js文件,而後選擇的模式進行相應的打包操做,最後新建dist目錄並生成一個main.js文件。此外針對開發環境和線上環境提供了兩種打包模式:"production"
和"development"
,"production"
模式內置了項目產出時的基本配置項,"development"
模式基本知足了快速構建和開發體驗。使用的方法是在運行webapck命令的時候,設置好mode參數的值便可,默認是production屬性。node
"scripts": { "dev": "webpack --mode development", "build": "webpack --mode production" }
具體的案例能夠前往github進行下載。webpack
下面根據官方的文檔介紹一下兩種模式。ios
提供了發佈程序時的優化配置項,旨在更小的產出文件、更快的運行速度、不暴露源碼和路徑。會默認採用代碼壓縮(minification),做用域提高(scope hoisting),tree-shaking,NoEmitOnErrorsPlugin,無反作用模塊修剪(side-effect-free module pruning)等。git
旨在提高開發調試過程當中的體驗,如更快的構建速度、調試時的代碼易讀性、暴露運行時的錯誤信息等。會默認採用bundle的輸出包含路徑名和eval-source-map
等,提高代碼的可讀性和構建速度。es6
兩種模式就是兩個箱子,箱子裏面就是各類插件工具,只是有些是開啓的,有些是關閉的,具體有哪些工具能夠參考這篇文章。github
webpack4廢棄了CommonsChunkPlugin,引入了optimization.splitChunks
和optimization.runtimeChunk
,旨在優化chunk的拆分。先介紹一下code splitting下的CommonsChunkPlugin有什麼缺點,而後仔介紹一下chunk split是怎麼進行優化的。web
CommmonsChunkPlugin的思路是Create this chunk and move all modules matching minChunks into the new chunk
,即將知足minChunks
配置想所設置的條件的模塊移到一個新的chunk文件中去,這個思路是基於父子關係
的,也就是這個新產出的new chunk是全部chunk的父親,在加載孩子chunk的時候,父親chunk是必需要提早加載的。舉個例子:
example: entryA: vue vuex someComponents entryB: vue axios someComponents entryC: vue vux axios someComponents minchunks: 2
產出後的chunk:
vendor-chunk:vue vuex axios chunkA~chunkC: only the components
帶來的問題是:對entryA和entryB來講,vendor-chunk都包含了多餘的module。
CommonsChunkPlugin另一個問題是:對異步的模塊不友好。下面也舉例說明:
example: entryA: vue vuex someComponents asyncB:vue axios someComponents entryC: vue vux axios someComponents minchunks: 2
產出後的chunk:
vendor-chunk:vue vuex chunkA: only the components chunkB: vue axios someComponents chunkC: axios someComponents
帶來的問題是:若是asyncB在entryA中動態引入,則會引入多餘的module。
總的來講CommonsChunkPlugin有如下三個問題:
與CommonsChunkPlugin的父子關係
思路不一樣的是,SplitChunksPlugin引入了chunkGroup
的概念,在入口chunk和異步chunk中發現被重複使用的模塊,將重疊的模塊以vendor-chunk的形式分離出來,也就是vendor-chunk可能有多個,再也不受限因而全部chunk中都共同存在的模塊,原理的示意以下圖所示:
其中,能夠發現SplitChunksPlugin產出的vendor-chunk有多個,對於入口A來講,引入的代碼只有chunkA、vendor-chunkA-B、vendor-chunkA-C、vendor-chunkA-B-C;這時候chunkA、vendor-chunkA-B、vendor-chunkA-C、vendor-chunkA-B-C造成了一個chunkGroup。下面舉個列子:
example: entryA: vue vuex someComponents entryB:vue axios someComponents entryC: vue vux axios someComponents
產出後的chunk:
vendor-chunkA-C:vuex vendor-chunkB-C:axios vendor-chunkA-B-C:vue chunkA: only the components chunkB: only the components chunkC: only the components
SplitChunksPlugin可以解決掉CommonsChunkPlugin中提到的三個問題,SplitChunksPlugin在production
模式下是默認開啓的,可是它默認只做用於異步chunk,若是要做用於入口chunk的話,須要配置optimization.splitChunks.chunks: "all"
,同時webpack自動split chunks是有幾個限制條件的:
這些限制能夠在SplitChunks的默認配置項中能夠一一對應的看到。
splitChunks: { chunks: "async", minSize: 30000, minChunks: 1, maxAsyncRequests: 5, maxInitialRequests: 3, name: true, cacheGroups: { default: { minChunks: 2, priority: -20 reuseExistingChunk: true, }, vendors: { test: /[\\/]node_modules[\\/]/, priority: -10 } } }
其實不難理解這些限制,由於SplitChunksPlugin產生的結果就是原來chunk被拆分了,引入的文件數量會變多,所以須要在文件數量上進行限制。
在使用CommonsChunkPlugin的時候,咱們一般會把webpack runtime的基礎函數提取出來,單獨做爲一個chunk,畢竟code splitting想把不變的代碼單獨抽離出來,方便瀏覽器緩存,提高加載速度。webpack4廢棄了CommonsChunkPlugin,採用了runtimeChunkPlugin能夠將每一個entry chunk中的runtime部分的函數分離出來,只須要一個簡單的配置:optimization.runtimeChunk: true
。
在webapck2開始支持ESModule後,webpack提出了tree-shaking進行無用模塊的消除,主要依賴ES Module的靜態結構。在webapck4以前,主要經過在.babelrc文件中設置"modules": false
來開啓無用的模塊檢測,該方法顯然比較粗暴。webapck4靈活擴展瞭如何對某模塊開展無用代碼檢測,主要經過在package.json
文件中設置sideEffects: false
來告訴編譯器該項目或模塊是pure的,能夠進行無用模塊刪除。
官方的github上提供了一個sideEffects的demo示例供參考,若是對tree-shaking的概念不是太瞭解,可去官方的文檔中tree-shaking部分詳細瞭解。下面是官方提供的一個減包效果示例,僅供欣賞。
在webapck4以前,webpack.prod.conf.js中關於UglifyJsPlugin的註釋會有這麼一段話:
// UglifyJs do not support ES6+, you can also use babel-minify for better treeshaking: https://github.com/babel/minify
意思就是UglifyJs沒法對ES6+的代碼進行壓縮,需使用babel-minify獲取更好的treeshaking效果。webapck4目前已經支持壓縮ES6+的代碼。
// 源代碼 import {sayHello} from './libs/js/util.js' let output = sayHello('hwm'); console.log(output); // 產出 ...let r=(e=>`Hello ${e}!`)("hwm");console.log(r)}...
webpack4支持以import
和export
形式加載和導出本地的WebAssembly模塊,這一塊本人實際項目並未使用到,暫不作介紹;此外,webpack4支持json模塊和tree-shaking,以前json文件的加載須要json-loader
的支持,webpack4已經可以支持json模塊(JSON Module),不須要額外的配置;此外,當json文件用ESModule的語法import引入的時候,webpack4還能支持對json模塊進行tree-shaking處理,把用不到的字段過濾掉,起到減包的做用。下面是個示例:
// 引用數據的三種方法 let jsonData = require('./data/test.json'); import jsonData from './data/test.json' // 打包時只會提取test.json文件中onePart部分。 import { onePart } from './data/test.json'
webpack4聲稱可以0配置,可是0配置有不少侷限性,好比只能是單入口的項目,入口和產出的文件名是固定的,entry是src目錄下的index.js,產出是dist目錄下的main.js,很明顯不能知足實際項目應用。因而,開發者仍是得本身配置webpack.config.js文件。
如何配置webpack4下的配置文件,須要大體瞭解webapck4的配置項的改動點。
mode:開發模式 development
mode:生產模式 production
plugin
loader
其餘的改動信息建議查看webpack的中文升級日誌。
介紹完了webpack4中核心配置項的變化,接下來結合vue-cli示例項目介紹一下,如何配置webpack.conf.js文件。
1.升級npm包版本
建議升級webpack4,同時升級涉及到的loaders和plugins。webpack4 中 cli 工具分離成了 webpack 核心庫 與 webpack-cli 命令行工具兩個模塊,須要使用 CLI ,必安裝 webpack-cli 至項目中。
npm i webpack webpack-cli webpack-dev-server -D
涉及到的插件有:
"vue-loader": "^15.0.10", "vue-style-loader": "^4.1.0", "vue-template-compiler": "^2.5.16", "copy-webpack-plugin": "^4.0.1", "extract-text-webpack-plugin": "^4.0.0-beta.0", "html-webpack-plugin": "^3.1.0", "optimize-css-assets-webpack-plugin": "^4.0.0", "webpack-bundle-analyzer": "^2.11.1", "webpack-dev-middleware": "^3.1.2", "webpack-dev-server": "^3.1.3", "webpack-merge": "^4.1.0"
2.修改webpack.base.conf.js
webpack4推薦使用了最新版本的vue-loader("vue-loader": "^15.0.10"),可是最新的vue-loader須要在webapck config文件中設置VueLoaderPlugin
插件,不然會報如下錯誤:
vue-loader was used without the corresponding plugin. Make sure to include VueLoaderPlugin in your webpack config.
webpack.base.conf.js文件中的改動主要是添加VueLoaderPlugin插件。
const { VueLoaderPlugin } = require('vue-loader'); module.exports = { ... plugins: [ // 添加VueLoaderPlugin,以響應vue-loader new VueLoaderPlugin() ], ... }
3.修改webpack.dev.conf.js
添加mode屬性,並設置爲development模式;而後註釋掉 webpack4開發模式已經內置的插件,如webpack.NamedModulesPlugin
和webpack.NoEmitOnErrorsPlugin
插件。
4.修改webpack.prod.conf.js
添加mode屬性,並設置爲production模式;而後註釋掉 webpack4生產模式已經內置的插件,如CommonsChunkPlugin
、uglifyjs-webpack-plugin
、ModuleConcatenationPlugin
插件;最後根據webpack4提供的文檔配置optimization,使用splitChunks
和runtimeChunk
完成chunk的提取和優化。
const webpackConfig = merge(baseWebpackConfig, { ... optimization: { // 採用splitChunks提取出entry chunk的chunk Group splitChunks: { cacheGroups: { // 處理入口chunk vendors: { test: /[\\/]node_modules[\\/]/, chunks: 'initial', name: 'vendors', }, // 處理異步chunk 'async-vendors': { test: /[\\/]node_modules[\\/]/, minChunks: 2, chunks: 'async', name: 'async-vendors' } } }, // 爲每一個入口提取出webpack runtime模塊 runtimeChunk: { name: 'manifest' } } ... })
通過以上操做,咱們已經基本完成了vue-cli項目的改造。運行項目的時候,注意看控制檯的報錯,是哪一個插件報的錯就去升級那個插件,若是存在找不到模塊之類的錯誤就去升級對應的loader。vue-cli項目webapck4下配置demo已經上傳到github,歡迎下載。
webapck4旨在開發模式下提高構建速度、提高用戶體驗,在生產模式下減少產出包的大小,提高加載和運行速度,下面是webapck3和webapck4下vue-cli的webapck模板項目的實際效果截圖:
開發者模式下:
由上圖能夠知道:webapck4下的構建速度是3703ms,明顯因爲webapck3下的5617ms;
生產模式下:
由上圖能夠知道:webapck4下的app-chunk的大小是933byte,明顯小於webapck3下的11.6K;webapck4下vendor-chunk的大小是109K,小於webapck3下的112K。
兩種模式下,webapck4性能上的確是精進很多,雖然有各類坑,仍是建議把坑填了,升級到webpack4。
想了解webpack的將來,建議先過一下webpack的歷史。
webpack1支持CMD和AMD,同時擁有豐富的plugin和loader,webpack逐漸獲得普遍應用。
webpack2相對於webpack最大的改進就是支持ES Module,能夠直接分析ES Module之間的依賴關係,而webpack1必須將ES Module轉換成CommonJS模塊以後,才能使用webpack進行下一步處理。除此以外webpack2支持tree sharking,與ES Module的設計思路高度契合。
webpack3相對於webpack2,過渡相對平穩,可是新的特性大都圍繞ES Module提出,如Scope Hoisting和Magic Comment。
webpack4集中發力在用戶體驗、構建性能(速度和產出大小)、通用和適配性(es module、typescript、web assemble)。
展望將來,webpack的將來確定持續提高用戶體驗、下降使用門檻,進一步提高構建速度和產出代碼的性能,同時webpack的團隊已經承諾會根據社區的投票來決定新特性開發優先權。如下是公告中給出的將來的重點關注點:
webapck4官方medium pr稿
webpack4中文升級日誌
webpack4升級指南以及從webpack3.x遷移
Webpack4 新特性 及 Vue-cli項目升級
Webpack4官方指導教程
webpack4.0打包優化策略整理
webapck3新特性