webpack 4 中 tree shaking 生產(chǎn)環(huán)境配置

上一篇介紹了什么是tree shaking,這一篇我們來實操一下。
node 版本是v8.9.1,webpack的版本是4.35.0。

最終的項目文件目錄結(jié)構(gòu)如下:


新建一個項目webpack-4-demo,然后npm init -y,生成package.json文件,然后安裝webpack 4

 npm install --save-dev webpack webpack-cli webpack-dev-server webpack-merge
npm install --save-dev clean-webpack-plugin html-webpack-plugin

新建src目錄作為源文件目錄,新建webpack配置文件,區(qū)分開發(fā)環(huán)境和生產(chǎn)環(huán)境,然后使用webpack-merge來合并配置。
新建基礎(chǔ)配置文件webpack.common.js,代碼如下

//webpack.common.js
const path = require('path')
const { CleanWebpackPlugin } = require('clean-webpack-plugin')
const HtmlWebpackPlugin = require('html-webpack-plugin')

module.exports = {
    entry: {
        app: './src/index.js',
    },
    plugins: [
        new CleanWebpackPlugin(),
        new HtmlWebpackPlugin({
            title: 'webpack 4 production',
            template: 'index.html',
            filename: 'index.html'
        }),
    ],
    output: {
        filename: '[name].bandle.js',
        path: path.resolve(__dirname, 'dist')
    },
    module: {
        rules: [
        ]
    }
}

新建開發(fā)環(huán)境配置文件webpack.dev.js

//webpack.dev.js
const path = require('path')
const merge = require('webpack-merge')
const common = require('./webpack.common.js')
const webpack = require('webpack')

module.exports = merge(common, {
    mode: 'development',
    devtool: 'inline-source-map',
    devServer: {
        contentBase: './dist',
        hot: true,
        port: 9000
    },
    plugins: [
        new webpack.HotModuleReplacementPlugin(),   //啟用HMR,配合server的hot
    ]
})

新建生產(chǎn)環(huán)境配置文件webpack.prod.js

const merge = require('webpack-merge')
const common = require('./webpack.common.js')

module.exports = merge(common, {
    devtool: 'source-map'
})

新建項目入口文件src/index.js

//src/index.js
import { square } from './math.js'
console.log('打印2的平方',square(2))

const app = document.getElementById('app')
app.innerHTML = 'hello world';

再建一個index.js依賴的模塊文件math.js

//src/math.js
export function square(x) {
    return x * x;
}

export function cube(x) {
    return x * x * x;
}

新建打包需要的模板文件index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title><%= htmlWebpackPlugin.options.title %></title>
</head>
<body>
    <div id="app"></div>
</body>
</html>

最后配置我們需要的npm script 啟動命令,package.json

//package.json
{
  "name": "webpack-4-demo",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "start": "webpack-dev-server --open --config webpack.dev.js",
    "build": "webpack --config webpack.prod.js"
  },
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "clean-webpack-plugin": "^3.0.0",
    "html-webpack-plugin": "^3.2.0",
    "webpack": "^4.35.0",
    "webpack-cli": "^3.3.5",
    "webpack-dev-server": "^3.7.2",
    "webpack-merge": "^4.2.1"
  }
}

現(xiàn)在我們來直接打包,沒有做tree shaking的優(yōu)化,看下打包的大小;

E:\workCode\webpack-4-demo>npm run build

> webpack-4-demo@1.0.0 build E:\workCode\webpack-4-demo
> webpack --config webpack.prod.js

Hash: 59507293492d05eeeeff
Version: webpack 4.35.0
Time: 473ms
Built at: 2019-06-27 13:01:07
            Asset       Size  Chunks             Chunk Names
    app.bandle.js    4.7 KiB     app  [emitted]  app
app.bandle.js.map   3.97 KiB     app  [emitted]  app
       index.html  366 bytes          [emitted]
Entrypoint app = app.bandle.js app.bandle.js.map
[./src/index.js] 145 bytes {app} [built]
[./src/math.js] 104 bytes {app} [built]
Child html-webpack-plugin for "index.html":
     1 asset
    Entrypoint undefined = index.html
    [./node_modules/.3.2.0@html-webpack-plugin/lib/loader.js!./index.html] e:/wo
rkCode/webpack-4-demo/node_modules/.3.2.0@html-webpack-plugin/lib/loader.js!./in
dex.html 582 bytes {0} [built]
        + 3 hidden modules

E:\workCode\webpack-4-demo>

可以看出項目打包的大小是:app.bandle.js 4.7 KiB。我們index.js文件引入了math.js模塊,只用到了square方法,并沒有用到cube方法,查看打包之后的app.bandle.js,找到我們自己的代碼:

...
/***/ "./src/index.js":
/*!**********************!*\
  !*** ./src/index.js ***!
  \**********************/
/*! no exports provided */
/***/ (function(module, __webpack_exports__, __webpack_require__) {

"use strict";
__webpack_require__.r(__webpack_exports__);
/* harmony import */ var _math_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./math.js */ "./src/math.js");

console.log('打印2的平方',Object(_math_js__WEBPACK_IMPORTED_MODULE_0__["square"])(2))

const app = document.getElementById('app')
app.innerHTML = 'hello world';

/***/ }),

/***/ "./src/math.js":
/*!*********************!*\
  !*** ./src/math.js ***!
  \*********************/
/*! exports provided: square, cube */
/***/ (function(module, __webpack_exports__, __webpack_require__) {

"use strict";
__webpack_require__.r(__webpack_exports__);
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "square", function() { return square; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "cube", function() { return cube; });
function square(x) {
    return x * x;
}

function cube(x) {
    return x * x * x;
}

/***/ })

/******/ });
//# sourceMappingURL=app.bandle.js.map
...

可以看到cube方法仍然被打包到了app.bandle.js里面。
現(xiàn)在我們使用tree shaking,看看看打包之后的文件大小。(注意,也可以在命令行接口中使用webpack --optimize-minimize 標記,來啟用 TerserPlugin。
webpack 4版本中,直接對生產(chǎn)環(huán)境配置mode:'production',即可啟用tree shaking,并將代碼壓縮,
然后在package.json文件加上"sideEffects": false,(注意,所有導(dǎo)入文件都會受到 tree shaking 的影響。這意味著,如果在項目中使用類似 css-loader 并 import 一個 CSS 文件,則需要將其添加到 side effect 列表中,以免在生產(chǎn)模式中無意中將它刪除:)用來提示webpack compiler找出哪些代碼是未被引用的,然后刪除掉。

//webpack.prod.js
const merge = require('webpack-merge')
const common = require('./webpack.common.js')

module.exports = merge(common, {
    mode: 'production',
    devtool: 'source-map'
})
//package.json
{
  ...
  "sideEffects": false
  ...
}

繼續(xù)運行npm run build,可以看到代碼體積變小了app.bandle.js 1.06 KiB,

E:\workCode\webpack-4-demo>npm run build

> webpack-4-demo@1.0.0 build E:\workCode\webpack-4-demo
> webpack --config webpack.prod.js

Hash: d1508bf9df4f2ca17868
Version: webpack 4.35.0
Time: 662ms
Built at: 2019-06-27 13:41:06
            Asset       Size  Chunks             Chunk Names
    app.bandle.js   1.06 KiB       0  [emitted]  app
app.bandle.js.map   4.88 KiB       0  [emitted]  app
       index.html  366 bytes          [emitted]
Entrypoint app = app.bandle.js app.bandle.js.map
[0] ./src/index.js + 1 modules 249 bytes {0} [built]
    | ./src/index.js 145 bytes [built]
    | ./src/math.js 104 bytes [built]
Child html-webpack-plugin for "index.html":
     1 asset
    Entrypoint undefined = index.html
    [0] e:/workCode/webpack-4-demo/node_modules/.3.2.0@html-webpack-plugin/lib/l
oader.js!./index.html 582 bytes {0} [built]
        + 3 hidden modules

E:\workCode\webpack-4-demo>

再來看一下打包之后的代碼app.bandle.js,現(xiàn)在整個 bundle 都已經(jīng)被 minify(壓縮)mangle(混淆破壞),但是如果仔細觀察,則不會看到引入cube函數(shù),但能看到 square函數(shù)的混淆破壞版本{"use strict";var n;r.r(t),console.log("打印2的平方",(n=2)*n),document.getElementById("app").innerHTML="hello world"}

!function(e){var t={};function r(n){if(t[n])return t[n].exports;var o=t[n]={i:n,l:!1,exports:{}};return e[n].call(o.exports,o,o.exports,r),o.l=!0,o.exports}r.m=e,r.c=t,r.d=function(e,t,n){r.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:n})},r.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},r.t=function(e,t){if(1&t&&(e=r(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var n=Object.create(null);if(r.r(n),Object.defineProperty(n,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var o in e)r.d(n,o,function(t){return e[t]}.bind(null,o));return n},r.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return r.d(t,"a",t),t},r.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},r.p="",r(r.s=0)}([function(e,t,r){"use strict";var n;r.r(t),console.log("打印2的平方",(n=2)*n),document.getElementById("app").innerHTML="hello world"}]);
//# sourceMappingURL=app.bandle.js.map

更多詳細的tree shaking介紹,大家可以參考官方文檔。
參考:
https://webpack.js.org/guides/tree-shaking/#root
https://webpack.docschina.org/guides/production
https://webpack.docschina.org/guides/tree-shaking/

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 一、入坑初探 1. 設(shè)置項目為私有 我們只需要在package.json文件中配置,因為是私有項目不需要向外部暴露...
    zxhnext閱讀 2,151評論 0 15
  • 全局安裝webpack 全局安裝webpack會有個問題,就是當(dāng)你有兩個項目依賴于不同版本的webpack,就會有...
    説好的妹紙呢閱讀 1,959評論 0 11
  • 作者:小 boy (滬江前端開發(fā)工程師)本文原創(chuàng),轉(zhuǎn)載請注明作者及出處。原文地址:https://www.smas...
    iKcamp閱讀 2,826評論 0 18
  • 前端將大型項目分成一個個單獨的模塊,一般封裝好的每個模塊都會實現(xiàn)一個目的明確的完成的功能。如何處理這些模塊以及模塊...
    pixels閱讀 3,509評論 1 14
  • 更新:Webpack4已經(jīng)發(fā)布,本篇是基于Webpack3的,請注意。更正:1.package.json中使用了應(yīng)...
    HermitCarb閱讀 1,275評論 2 4

友情鏈接更多精彩內(nèi)容