背景
有一次在使用webpack
构建组件项目时,需要动态指定publicpath
,类似如下的代码:
构建后,在运行态下,发现模块A中,并没有应用动态指定的publicPath。查看了构建后的资源:
可以明显看到,模块A被提升到了 指定publicPath的前面,这就导致了A中的path并没有生效。查阅了webpack的官方文档,也验证了这一点:
就是说,如果你使用了ES6 Module
导入了你的入口文件,那么 __webpack_public_path__
的声明将会在import
之后。所以为了避免出现问题,可以将__webpack_public_path__
的声明放在单独的文件中,然后导入到程序入口。
为了验证这个问题,尝试了下使用AMD
来引入模块A
:
构建之后:
可以发现,在使用AMD模块化的时候,模块A并没有被提升。
那为什么在使用ES6 module的时候,会被提升呢?
scope hoisting
这其实涉及到webpack中的一个概念,就是scope hoisting
,即 作用域提升。就是说在构建过程中,webpack会借助ES6 module
的静态特性,确定模块的依赖关系,将一个bundle中的静态依赖提升到顶部。
基于此,webpack就可以将零散的模块合并到一个函数中去(但前提是不能造成代码冗余。 因此只有那些被引用了一次的模块才能被合并)。这样做的好处有:
- 代码体积减少
- 代码在运行时因为创建的函数作用域更少了,内存开销也随之变小
wepack4中的一个插件ModuleConcatenationPlugin
便是实现此功能的。webpack4 在生产环境构建中内置了该插件,其他模式下并没有开启。
为了方便对比差异,我们在开发环境下,对比开启/关闭该插件后的构建结果:
开启 ModuleConcatenationPlugin
关闭 ModuleConcatenationPlugin
webpack对scope hosting 与code spliting 的解释https://github.com/webpack/webpack/tree/master/examples/scope-hoisting
引申的思考?:
- 何为静态模块
参考文章:
- https://imweb.io/topic/5a43064fa192c3b460fce360
- https://webpack.js.org/plugins/module-concatenation-plugin/
- https://zhuanlan.zhihu.com/p/27980441
- https://github.com/wangning0/Autumn_Ning_Blog/issues/28