lishengzxc / bblog

My Blog
https://github.com/lishengzxc/bblog/issues
178 stars 8 forks source link

Webpack 3 更新了啥? #34

Open lishengzxc opened 7 years ago

lishengzxc commented 7 years ago

参考:https://medium.com/webpack/webpack-3-official-release-15fd2dd8f07b

Scope Hoisting

Scope Hoisting 译为 作用域提升,它是 Webpack 3 最大的一个新功能。曾经的 Webpack 是将每一个模块(每一个被 import 或者 require 的那个东西)bundle 到每一个一个独立的闭包函数里。这会导致 bundle 的文件里,每一个模块最外层都会有一些其特殊的闭包包装,导致文件体积增大,同时它也会让 JS 在浏览器执行变慢(因为多了一层函数的包装)。

Webpack 3 可以如此开启 Scope Hoisting

module.exports = {  
  plugins: [
    new webpack.optimize.ModuleConcatenationPlugin()
  ]
};

上面图片是他人的结果,让我们自己实验下。

看看真实结果

实验文件

// app.js
import bar from './bar';

bar();
// bar.js
export default function bar() {
  console.log(1);
}
// webpack.config.js for webpack2
module.exports = {
  entry: './app.js',
  output: {
    filename: 'bundle.js'
  }
}
// webpack.config.js for webpack3
var webpack = require('webpack')

module.exports = {
  entry: './app.js',
  output: {
    filename: 'bundle.js'
  },
  plugins: [
    new webpack.optimize.ModuleConcatenationPlugin()
  ]
}

构建结果

// webpack2
Hash: 60bba0d666fdbba6aacb
Version: webpack 2.6.1
Time: 96ms
    Asset     Size  Chunks             Chunk Names
bundle.js  3.13 kB       0  [emitted]  main
   [0] ./bar.js 51 bytes {0} [built]
   [1] ./app.js 32 bytes {0} [built]
// webpack3
Hash: d974d2a55c9d519d75fd
Version: webpack 3.0.0
Time: 119ms
    Asset     Size  Chunks             Chunk Names
bundle.js  2.71 kB       0  [emitted]  main
   [0] ./app.js + 1 modules 83 bytes {0} [built]

首先,我们可以看到 bundle.js 文件的体积有了明显的变化,从 3.13kb 缩小到了 2.71kb(我并没有开启丑化和压缩),我们在看看构建后的文件的具体差别:

这个 Webpack 2 构建后的结果,我们可以看到 Webpack 2 为两个模块(app.js 和 bar.js)分别为他们增加了两个闭包:

(function(module, __webpack_exports__, __webpack_require__) {
    ...
})

我们再来看看 Webpack 3 的构建结果:

我们看到 Webpack 3 + ModuleConcatenationPlugin() 所构建出的文件,只为两个模块包装了一个闭包,少了一坨这么一个东西:

(function(module, __webpack_exports__, __webpack_require__) {
    ...
})

十个模块就是十坨这些字符,Webpack 3 + ModuleConcatenationPlugin() 确实减少了这些东西,确实能够使得最后构建出的文件从体积上有比较明显的减少!

但是,那如果我们在某个模块里直接声明了一个变量,但是同时我又没有 export 出来,没有闭包的存在,似乎也许在其他模块(构建后的文件里)好像可以访问到其他模块中直接声明的变量?我们试试?

修改实验文件

// app.js
import bar from './bar';

bar();
console.log(a);
// bar.js
var a = 'a';
export default function bar() {
  console.log(1);
}

再次构建再看下构建后的结果:

Webpack 2 是通过闭包的方式,让 a 在其他模块下无法访问到的。那 Webpack 3 呢?

在 Webpack 3 + ModuleConcatenationPlugin(),虽然是一个闭包,但是它会自己根据模块的文件名从而唯一标识那个不可再其他模块中访问的变量,来避免在其他模块中访问到别的模块没有 export 出来的变量。具体查看这里https://github.com/webpack/webpack/blob/master/lib/optimize/ModuleConcatenationPlugin.js

有的时候可能因为某种原因会降级该功能,你可以在命令行中增加 --display-optimization-bailout 查看被降级的原因。

结论

Webpack 3 + ModuleConcatenationPlugin() 确实可以优化你 JS 代码的性能,至于生成环境中的使用,我可能还需要观望一阵(其实也是业务太紧,空下来就升一波~),我会时刻关注它的进展(官方声称 Webpack 2 可以直接升级 Webpack 3)

Magic Comments

Magic Comments 译为魔法注释(其实不想说这个的,看到魔法两个字,我就不喜欢,但是它是 Webpack 3 的重要功能还是说下吧)。Webpack 2 的时候大家都知道了动态引入语法 import(),有些用户就关心说它能否下过去的 require.ensure 那样给动态模块创建一个自有的名称。

Magic Comments 可以让你传入一个模块名给你的 import(),就像一个行内注释一样。

详细使用可以看这篇文章

通过使用注释,我们可以保存真实的加载信息,并且这也带来了你们喜爱的一个强大的模块命名功能。

import(/* webpackChunkName: "my-chunk-name" */ 'module');

可以查看最新代码拆分指南文档,获得更加详细的关于该功能的详细信息。

最后

从 Webpack 3 开始,他们开发者发起了这么一个投票 https://webpack.js.org/vote/,由社区的开发者们决定未来的新功能会优先开发哪个。

Webpack 3 接下来可能会带来:

因此,Webpack 1 的老铁们如果时间允许,有空的时间,我觉得可以升~

参考:https://medium.com/webpack/webpack-3-official-release-15fd2dd8f07b

rccoder commented 7 years ago

升的真是快,我就属于 Webpack 1 时代的老铁

YuriTu commented 7 years ago

我尝试了你的试验,但是表现不太一样

我的环境: 我的项目使用的是 webpack1.13,我使用它与webpack3.2版本的生成文件进行了对比 webpack3 + ModuleConcatenationPlugin() 反而在小文件的时候更大了 比如只有一句console的模块

差异: 3.2 增加了getter function 依旧把每个依赖做成了一个闭包,而不是合成了一个 (我确定我开启了 ModuleConcatenationPlugin,webpack版本为3.2)

其他: 在大文件的情况下,我尝试用我自己的真实工程文件进行对比,文件有一定的减少,但也很少,2k-20k之间... 我希望能有30%左右的文件体积减少,看来效果并不是很好...不知道是不是配置有问题 sad :(


我找到原因了,因为项目的兼容性要求,我采用了module.export + require的方式来引入依赖,而是不是ES6的export default + import from,看来ModuleConcatenationPlugin只能在ES6的语法下发挥威力

感谢你的文章

lishengzxc commented 7 years ago

@YuriTu 恩 从 2 开始,似乎默认只允许 ES6 Module 了