這篇文章主要介紹webpack中使用tree-shaking的方法,文中介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們一定要看完!
創(chuàng)新互聯(lián)建站-專業(yè)網(wǎng)站定制、快速模板網(wǎng)站建設(shè)、高性價比信豐網(wǎng)站開發(fā)、企業(yè)建站全套包干低至880元,成熟完善的模板庫,直接使用。一站式信豐網(wǎng)站制作公司更省心,省錢,快速模板網(wǎng)站建設(shè)找我們,業(yè)務(wù)覆蓋信豐地區(qū)。費(fèi)用合理售后完善,十載實(shí)體公司更值得信賴。
1.什么是tree-shaking
webpack 2 的到來帶來的最棒的新特性之一就是tree-shaking 。tree-shaking源自于rollup.js,先如今,webpack 2也有類似的做法。
webpack 里的tree-shaking的到來不得不歸功于es6規(guī)范的模塊。為什么這么說,如今的前端模塊規(guī)范很多,比較出流行的比如commonJS , AMD , es6 ,我簡單的說一下commonJS和es6模塊的區(qū)別。
commonJS 模塊
commonJS的模塊規(guī)范在Node中發(fā)揚(yáng)光大,總的來說,它的特性有這幾個:
1.動態(tài)加載模塊
commonJS和es6的最大區(qū)別大概就在于此了吧,commonJS模塊的動態(tài)加載能夠很輕松的實(shí)現(xiàn)懶加載,優(yōu)化用戶體驗(yàn)。
2.加載整個模塊
commonJS模塊中,導(dǎo)出的是整個模塊。
3.每個模塊皆為對象
commonJS模塊都被視作一個對象。
4.值拷貝
commonJS的模塊輸出和 函數(shù)的值傳遞相似,都是值的拷貝
es6 模塊
1.靜態(tài)解析
即在解析階段就確定輸出的模塊,所以es6模塊的import一般寫在被引入文件的開頭。
2.模塊不是對象
在es6里,每個模塊并不會當(dāng)做一個對象看待
3.加載的不是整個模塊
在es6模塊中經(jīng)常會看見一個模塊中有好幾個export 導(dǎo)出
4.模塊的引用
es6模塊中,導(dǎo)出的并不是模塊的值拷貝,而是這個模塊的引用
在結(jié)合es6模塊和commonJS模塊的區(qū)別之后,我們知道es6的特點(diǎn)是靜態(tài)解析,而commonJS模塊的特點(diǎn)是動態(tài)解析的,因此,借于es6模塊的靜態(tài)解析,tree-shaking的實(shí)現(xiàn)才能成為可能。
在webpack中,tree-shaking指的就是按需加載,即沒有被引用的模塊不會被打包進(jìn)來,減少我們的包大小,縮小應(yīng)用的加載時間,呈現(xiàn)給用戶更佳的體驗(yàn)。
2.怎么使用tree-shaking
說了這么多那到底如何使用tree-shaking呢?
webpack默認(rèn)es6規(guī)范編寫的模塊都能使用tree-shaking。這是什么意思呢?下面來看個例子。
首先奉上我的demo目錄如下:
├─dist
└─index.html
├─node_modules
└─...
├─src
├─scripts
├─assets
├─webpack.config.js
└─package.json
dist用來存放打包好的代碼
src相反的用來存放源文件
src里的scripts目錄用來存放js腳本文件,assets用來存放靜態(tài)資源文件
以下幾條命令過后開始我們的tree-shaking之旅
npm install --save-dev webpack webpack-dev-server webpack.config.js const webpack = require('webpack') const path = require('path') module.exports = { entry:'./src/scripts/main.js', output:{ path:path.resolve(__dirname,'dist/'), filename:'main.bundle.js' }, plugins:[ new webpack.HotModuleReplacementPlugin() ], devServer:{ port:4200, contentBase:path.resolve(__dirname,'dist/'), historyApiFallback:true, hot:true } }
接下來是main.js,直接引入了sayHello
import { sayHello } from './greeter.ts';
sayHello();
相應(yīng)的main.js的依賴greeter.js
export function sayHello(){ alert('hello') }
export function sayWorld(){ alert('world') }
在dist目錄下有個index.html 用來引入打包后的bundle
Document
以上就是整個demo的代碼,接下來的事情我們直接webpack打包試試看
去掉打包后冗長的代碼只看chunk傳參的部分:
[
/* 0 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
Object.defineProperty(__webpack_exports__, "__esModule", { value: true });
/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__person__ = __webpack_require__(1);
Object(__WEBPACK_IMPORTED_MODULE_0__person__["a" /* sayHello */])();
/***/ }),
/* 1 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "a", function() { return sayHello; });
/* unused harmony export sayWorld */
function sayHello(){
alert('hello');
}
function sayWorld(){
alert('world');
}
/***/ })
/******/ ]
我們關(guān)注這一行
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "a", function() { return sayHello; });
實(shí)際上只return了一個sayHello。
因此我們現(xiàn)在只需要壓縮一下整個Js代碼,就能把沒引用的sayWorld剔除。
鍵入以下命令進(jìn)行壓縮
webpack --optimize-minimize
由于壓縮后的代碼只有一行了,我們移步尾部:
function(e,n,r){"use strict";function t(){alert("hello")}r.d(n,"a",function(){return t})}]);
可以看到sayWorld函數(shù)已經(jīng)被成功剔除。
我們啟動webpack-dev-server
webpack-dev-server
在瀏覽器中輸入
http://localhost:4200
每次都需要在命令行里輸入?yún)?shù),豈不是很麻煩,還有沒有其他更好的辦法呢?
(1)我們可以把這串命令放入package.json的scripts字段,然后通過npm start來自動執(zhí)行
(2)其實(shí)–optimize-minimize的底層實(shí)現(xiàn)是一個插件UglifyJsPlugin,因此,我們可以直接在webpack.config.js里配置它
在webpack.config.js里配置插件
const path = require('path'); const webpack = require('webpack'); module.exports = { entry:'./src/scripts/main.js', output:{ filename:'main.bundle.js', path:path.join(__dirname,'dist') }, plugins:[ new webpack.optimize.UglifyJsPlugin(), // <----------- 壓縮js new webpack.HotModuleReplacementPlugin() ], devServer:{ port:4200, historyApiFallback:true, hot:true, contentBase:path.join(__dirname,"dist/") } }
然后我們webpack打包
即看到同樣的效果
function(e,n,r){"use strict";function t(){alert("hello")}r.d(n,"a",function(){return t})}]);
在tree-shaking觸發(fā)打包后,僅僅是撇開了模塊的引用,但還是要結(jié)合壓縮工具來進(jìn)行,這才是完整的一次tree-shaking
那如果是typescript該怎么使用tree-shaking呢?
3.如何在typescript里使用tree-shaking
要在webpack里使用ts,首先我們必須安裝tsc
npm install --save-dev typescript
之后我們需要解析ts文件的loader
npm install --save-dev ts-loader
然后在webpack.config.js進(jìn)行配置
const webpack = require('webpack') const path = require('path')
module.exports = { entry:'./src/scripts/main.ts', output:{ path:path.resolve(__dirname,'dist/'), filename:'main.bundle.js' }, module:{ rules:[ { test:/\.ts$/, use:['ts-loader'] } ] }, plugins:[ new webpack.optimize.UglifyJsPlugin(), new webpack.HotModuleReplacementPlugin() ], devServer:{ port:4200, contentBase:path.resolve(__dirname,'dist/'), historyApiFallback:true, hot:true } }
獻(xiàn)上我的兩份文件main.ts , greeter.ts (這兩份文件除了后綴名基本沒有改動)
main.ts
import { sayHello } from './greeter.ts'; sayHello();
greeter.ts
export var sayHello = function(){ alert('hello') } export var sayWorld = function(){ alert('world') }
之后我們需要做的是,創(chuàng)建一個tsconfig.json的配置文件供tsc解析,這時,坑來了。
下面是我的tsconfig.json文件
{ "compilerOptions":{ "target":"es5", "sourceMap":true }, "exclude":[ "./node_modules" ] }
好像沒有什么不對
接著我們webpack
看下打包壓縮后的代碼的最后一部分:
"use strict";Object.defineProperty(n,"__esModule",{value:!0}),n.sayHello=function(){alert("hello")},n.sayWorld=function(){alert("world")}}]);
sayWorld居然還是存在?。?!怎么回事,為什么沒有被觸發(fā)tree-shaking優(yōu)化?
這是因?yàn)閠sc編譯后的代碼為es5 ,而正因如此,tsc默認(rèn)使用了commonJS的規(guī)范來加載模塊,因此并沒有觸發(fā)tree-shaking,那我們要怎么做?
修改一下tsconfig.json,把target改為es6即可!
{ "compilerOptions":{ "target":"es6", "sourceMap":true }, "exclude":[ "./node_modules" ] }
再次打包
看一下打包后的bundle
function(e,n,r){"use strict";r.d(n,"a",function(){return t});var t=function({alert("hello")}}]);
果然是觸發(fā)了tree-shaking
開啟webpack-dev-server
webpack-dev-server
可以看到成功打印hello
以上是“webpack中使用tree-shaking的方法”這篇文章的所有內(nèi)容,感謝各位的閱讀!希望分享的內(nèi)容對大家有幫助,更多相關(guān)知識,歡迎關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道!