背景 由于,我们在开发过程中,会引入很多大大小小的模块,比如一个计算方法通用的大包,封装了很多很多的方法,但是我们只用到了其中一两个方法,往往希望,打包只打包使用到的方法,未使用到的方法,不被打包进最后的代码中,以保持体积的最小化。
方案 webpack为这种情况,提供了tree shaking
写法
清理一下文件并新增一个math.js
。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 webpack_learn |- node_modules |- package.json |- webpack.config.js |- yarn.lock - |- staticFrom - |- test.txt |- src |- let.js |- get.js |- index.js + |- math.js |- dist |- bundle.js - |- main.js |- index.html - |- test.txt
修改math.js
的内容
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 //math.js + export function square(x) {//平方 + return x * x; + } + + export function cube(x) {//立方 + return x * x * x; + } + + export function add(x,y) {//求和 + return x + y; + } + + export function cut(x,y) {//计算差 + return x - y; + }
修改index.js
1 2 3 4 5 6 7 let name = require('./let.js'); let sayName = require('./get.js'); + let math = require('./math.js'); sayName('大家好,我的名字是'+name) + console.log(math.add(2,3)) + console.log(math.add(9,18))
然后执行打包指令1 npm run build #也可以yarn build
打包后的代码如下1 2 3 4 5 !function(n){var t={};function e(r){if(t[r])return t[r].exports;var o=t[r]={i:r,l:!1,exports:{}};return n[r].call(o.exports,o,o.exports,e),o.l=!0,o.exports}e.m=n,e.c=t,e.d=function(n,t,r){e.o(n,t)||Object.defineProperty(n,t,{enumerable:!0,get:r})},e.r=function(n){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(n,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(n,"__esModule",{value:!0})},e.t=function(n,t){if(1&t&&(n=e(n)),8&t)return n;if(4&t&&"object"==typeof n&&n&&n.__esModule)return n;var r=Object.create(null);if(e.r(r),Object.defineProperty(r,"default",{enumerable:!0,value:n}),2&t&&"string"!=typeof n)for(var o in n)e.d(r,o,function(t){return n[t]}.bind(null,o));return r},e.n=function(n){var t=n&&n.__esModule?function(){return n.default}:function(){return n};return e.d(t,"a",t),t},e.o=function(n,t){return Object.prototype.hasOwnProperty.call(n,t)},e.p="",e(e.s=0)}([function(n,t,e){var r=e(1),o=e(2),u=e(3);o("大家好,我的名字是"+r),console.log(u.add(2,3))},function(n,t){n.exports="小明"},function(n,t){n.exports=function(n){console.log(n)}},function(n,t,e){"use strict";function r(n){return n*n}function o(n){return n*n*n}function u(n,t){return n+t}function c(n,t){return n-t}e.r(t), e.d(t,"square",(function(){return r})), e.d(t,"cube",(function(){return o})), e.d(t,"add",(function(){return u})), e.d(t,"cut",(function(){return c}))}]);
可以看出,我们只使用了math.js
中的add
方法,但是打包后的内容里math.js
中导出的square
、cube
、add
、cut
方法都被打包了,这显然不是我们想要的结果。
我们修改package.json
的内容
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 { "dependencies": { "babel-loader": "^8.0.6", "copy-webpack-plugin": "^5.1.1", "webpack": "^4.41.5", "webpack-cli": "^3.3.10", "webpack-dev-server": "^3.10.1" }, "name": "webpack_learn", "version": "1.0.0", "main": "index.js", "devDependencies": { "@babel/core": "^7.7.7", "@babel/preset-env": "^7.7.7", "babel-core": "^6.26.3", "babel-preset-env": "^1.7.0" }, "scripts": { "build": "webpack", "watch": "webpack --watch", "serve": "webpack-dev-server --open", "dev": "webpack --mode development", "product": "webpack --mode production", "testParams": "webpack --mode production --env.production product --param1 1 --param2 2 --explane 这是一个说明", "showColorAndProgress": "webpack --progress --colors", "test": "echo \"Error: no test specified\" && exit 1" }, "author": "", + "sideEffects": false, "license": "ISC", "description": "" }
然后执行打包指令1 npm run build #也可以yarn build
然后我们发现,打包指令中,依然包含math.js
导出的四个方法
修改index.js
文件
1 2 3 4 5 6 7 8 9 10 let name = require('./let.js'); let sayName = require('./get.js'); - let math = require('./math.js'); + import {add} from './math.js' sayName('大家好,我的名字是'+name) - console.log(math.add(2,3)) - console.log(math.add(9,18)) + console.log(add(2,3)) + console.log(add(9,18))
修改webpack.config.js
文件增加mode:"production"
再次打包
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 !function(e) { var t = {}; function n(r) { if (t[r]) return t[r].exports; var o = t[r] = { i: r, l: !1, exports: {} }; return e[r].call(o.exports, o, o.exports, n), o.l = !0, o.exports } n.m = e, n.c = t, n.d = function(e, t, r) { n.o(e, t) || Object.defineProperty(e, t, { enumerable: !0, get: r }) } , n.r = function(e) { "undefined" != typeof Symbol && Symbol.toStringTag && Object.defineProperty(e, Symbol.toStringTag, { value: "Module" }), Object.defineProperty(e, "__esModule", { value: !0 }) } , n.t = function(e, t) { if (1 & t && (e = n(e)), 8 & t) return e; if (4 & t && "object" == typeof e && e && e.__esModule) return e; var r = Object.create(null); if (n.r(r), Object.defineProperty(r, "default", { enumerable: !0, value: e }), 2 & t && "string" != typeof e) for (var o in e) n.d(r, o, function(t) { return e[t] } .bind(null, o)); return r } , n.n = function(e) { var t = e && e.__esModule ? function() { return e.default } : function() { return e } ; return n.d(t, "a", t), t } , n.o = function(e, t) { return Object.prototype.hasOwnProperty.call(e, t) } , n.p = "", n(n.s = 2) }([function(e, t) { e.exports = "小明" } , function(e, t) { e.exports = function(e) { console.log(e) } } , function(e, t, n) { "use strict"; function r(e, t) { return e + t } n.r(t); var o = n(0); n(1)("大家好,我的名字是" + o), console.log(r(2, 3)), console.log(r(9, 18)) } ]);
最后的结果,可以看出,add方法被打包成了
1 2 3 4 function r(e, t) { return e + t } n.r(t);
而其他的方法并没有被打包进来,实现了代码的裁剪,根据表现来看,如果你希望使用webpack
的tree-shaking
的话,需要如下使用
js文件中,每一个方法,都需要使用exports
导出,使用方法的地方,使用impoet {xxx} from 'xx/xx'
来按需导入,使用require
是无法完成按需导入的
package.json
中,增加"sideEffects": false
声明文档安全性是否拥有副作用,
config.webpack.js
中,增加mode:production
或者使用webpack
的UglifyJSPlugin
插件