Webpack打包UMD的export问题

Webpack打包UMD的export问题_第1张图片

最近在写一个组件时候遇到一个问题,用webpack将组件打包成一个符合UMD规范的组件时出现一个比较奇怪的现象:使用export default导出的全局变量会多一个default属性:

如:
– index.js

let webpackDemo = {
    val: 'hello webpack'
}
export default webpackDemo;

打包之后发现在全局下只能这么访问val值:

webpackDemo.default.val;

修改index.js代码

let webpackDemo = {
    val: 'hello webpack'
}
export { webpackDemo };

则访问val属性变成了

webpackDemo.webpackDemo.val;

为了弄明白怎么回事,准备了一个简单的webpack-umd项目,项目结构如下:

Webpack打包UMD的export问题_第2张图片

– package.json

{
  "name": "webpack-umd",
  "version": "1.0.0",
  "description": "",
  "main": "./dist/index.js",
  "scripts": {
    "build": "webpack"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "babel-cli": "^6.26.0",
    "babel-core": "^6.26.0",
    "babel-loader": "^7.1.2",
    "babel-plugin-transform-runtime": "^6.22.0",
    "babel-preset-env": "^1.3.2",
    "babel-preset-stage-2": "^6.22.0",
    "webpack": "^4.29.6",
    "webpack-cli": "^3.2.3"
  }
}

– src/index.js

let webpackDemo = {
    val: 'hello webpack'
}
export default webpackDemo;

运行npm run build后查看源码,注意webpack配置mode: 'development':
Webpack打包UMD的export问题_第3张图片

简化打包后的结构为:

(function webpackUniversalModuleDefinition(root, factory){
    // 这里是支持umd规范的写法
})(window, function(){
    // 这里是index.js源码
    //
    ...val: 'hello webpack'\n};\n\nexports.default = webpackDemo;...
})

我们知道export exportsES6中新增的,而exportsCMD规范定义的,不难发现webpack编译的结果是将es6export default语法转成CMDexports.default, 这个时候可以想到CMD规范改写代码,如下:

–index.js

let webpackDemo = {
    val: 'hello webpack'
}
module.exports = webpackDemo;

Webpack打包UMD的export问题_第4张图片

重新打包之后发现在全局作用域下可以正常访问属性了:webpackDemo.val,但是从优雅角度考虑,同一个module下混用es6cmd规范实为不妥,如:

import a from './a';
let webpackDemo = {
    val: 'hello webpack'
}
module.exports = webpackDemo; // 强迫症促使我想用 export default webpackDemo;

换个角度考虑,既然打包出来的是exports.default = webpackDemo,那么理论上只要将default干掉即可。而怎么干掉呢?答案只能从webpack本身着手,毕竟是webpack编译后的结果未能达到预期。查看webpack文档 发现了一个libraryExport属性,尝试了一下,完美解决~,修改webpack.config.js文件:

module.exports = {
    mode: 'development',
    entry: './src/index.js',
    output: {
        library: 'webpackDemo',
        libraryTarget: 'umd',
        libraryExport: 'default', // 增加这个属性
        path: path.resolve(__dirname, 'dist'),
        filename: 'index.js'
    }
    // ....
}

Webpack打包UMD的export问题_第5张图片

重新编译后,可看到多了一个default属性访问

()()['default']

也就可以知道libraryExport属性作用是取export下的default对象。再换个角度,如果是将export default webpackDemo; 换成export {webpackDemo};,那么按照刚才的思路只需要将libraryExport的值设置为webpackDemo即可。

// index.js
let webpackDemo = {
    val: 'hello webpack'
}
export {webpackDemo};

// webpack.config.js
module.exports = {
    mode: 'development',
    entry: './src/index.js',
    output: {
        library: 'webpackDemo',
        libraryTarget: 'umd',
        libraryExport: 'webpackDemo', // libraryExport改为webpackDemo
        path: path.resolve(__dirname, 'dist'),
        filename: 'index.js'
    }
    // ....
}

到这里,再熟悉了一下webpack output的几个属性:

output.library
  • stringobject(从 webpack 3.1.0 开始;用于 libraryTarget: umd
  • output.library 的值的作用,取决于output.libraryTarget 选项的值
  • 如果生成的输出文件,是在HTML 页面中作为一个script 标签引入,则变量MyLibrary 将与入口文件的返回值绑定。
output.libraryExport

这个属性的用法再上面已经体现了。注意默认值为undefined

output.libraryTarget

配置如何暴露library,可选的值为:varthiswindowglobalcommonjscommonjs2amdamd-requireumd等。通常使用umd即可,umd是一种混合规范,可以将library暴露为所有的模块定义下都可运行的方式,可以在CommonJS, AMD环境下运行,兼容性最好。

ok~ 使用webpack打包模块化组件总结:

  • 1、导出变量可以使用module.exports = webpackDemo,简单省事,但不够优雅
  • 2、若要使用ES6exportexport default导出,需配合wenpackoutput.libraryExport属性
  • 3、webpackoutput.libraryTarget建议采用umd方式,兼容性好。

参考链接:

  • https://webpack.docschina.org/configuration/output/
  • https://segmentfault.com/a/1190000010426778
  • http://www.hacksparrow.com/node-js-exports-vs-module-exports.html

你可能感兴趣的:(WEB前端)