代码改变世界
[登录 · 注册]
  • 【转载】详解webpack的out.libraryTarget属性
  • 转载:https://blog.csdn.net/frank_yll/article/details/78992778

    Webpack 作为目前前端最热门的打包工具,相信很多人都在项目中使用过,其繁杂的配置项也确实“配”得上他老大的身份 o(╯□╰)o。output.libraryoutput.libraryTarget属性可能大家都会比较陌生,因为一般如果只在项目中使用 webpack 不需要关注这两个属性,但是如果是开发类库,那么这两个属性就是必须了解的。

    简介

    回想一下,当我们引入别人开发的类库时有几种方式?下面假设我们引入一个demo方法:

    • 传统方式:script标签

      1 <script src="demo.js"></script>
      2 <script>demo();</script>
    • AMD

      1 define(['demo'], function(demo) {
      2 demo();
      3 });
    • commonjs 方式

      1 const demo = require('demo');
      2 
      3 demo();
    • ES6 module

      1 import demo from 'demo';
      2 
      3 demo();

    大家思考一下,为什么这个类库能支持不同方式的引入?如何实现的?这就是 webpack 配置output.libraryoutput.libraryTarget提供的功能。

    output.library

    支持输入string或者object(从 webpack 3.1.0 版本开始支持; 限于 libraryTarget: “umd” 时使用)类型的值。

    output.library的值被如何使用会根据output.libraryTarget的取值不同而不同。而默认output.libraryTarget的取值是var,如果如下配置:

    1 output: {
    2   library: "myDemo"
    3 }

    如果在 HTML 页面中使用script标签引入打包结果文件,那么变量myDemo对应的值将会是入口文件(entry file)的返回值。

    output.libraryTarget

    支持输入string类型的值。默认值:var

    此配置的作用是控制 webpack 打包的内容是如何暴露的。请注意这个选项需要和output.library所绑定的值一起产生作用。在以下的 demo 中,假设output.library值是myDemo_entry_return_表示入口点返回的值。在bundle中,它是webpack从入口点生成的函数的输出。

    暴露一个变量

    以下选项会把打包返回的值(无论暴露的是什么)绑定到一个由output.library指定的变量上,无论包是被如何引用。

    • libraryTarget: "var"- (default)

      使用这个配置,当库被加载时,那么库的返回值会被分配到使用用var申明的变量上。

      1 var myDemo = _entry_return_;
      2 
      3 // In a separate script...
      4 myDemo();

      如果没有设置output.library值,那么将不会发生赋值行为。

    • libraryTarget: "assign"

      使用这个设置,会把库返回值分配给一个没使用var申明的变量中,如果这个变量没有在引入作用域中提前申明过,那么将会挂载在全局作用域中。(注意,这个行为有可能会覆盖全局作用域中的已有变量

       myDemo = _entry_return_; 

    通过对象属性暴露

    以下选项将库的返回值(无论返回值是什么)分配给特定对象的指定属性,属性由output.library指定,对象由output.libraryTarget指定。

    output.library没有指定为非空字符串,那么默认行为是将库返回值的所有属性(properties)都分配到对象中,代码如下:

     (function(e, a) { for(var i in a) e[i] = a[i]; }(${output.libraryTarget}, _entry_return_) 

    注意,发生这个行为的时候 webpack 并不会检查对象中是否已经存在这些属性值,也就是会发生覆盖行为。

    • libraryTarget: "this" - 将库的返回值分配给this对象的由output.library指定的属性。其中this的意义由用户决定。

      1 this["myDemo"] = _entry_return_;
      2 
      3 this.myDemo();
      4 myDemo(); // if this is window
    • libraryTarget: "window" - 将库的返回值分配给window对象的由output.library指定的属性。

      1 window["myDemo"] = _entry_return_;
      2 
      3 window.myDemo.doSomething();
    • libraryTarget: "global" - 将库的返回值分配给global对象的由output.library指定的属性。

      1 global["myDemo"] = _entry_return_;
      2 
      3 global.myDemo();
    • libraryTarget: "commonjs" - 将库的返回值分配给exports对象的由output.library指定的属性。正如名字所指,这个选项可以使用在 CommonJS 环境。

      exports["myDemo"] = _entry_return_;
      
      require("myDemo").doSomething();

    模块定义系统

    以下选项将产生一个包含更完整兼容代码的包,以确保与各种模块系统的兼容性。 此时output.library选项在不同的output.libraryTarget选项下具有不同的含义。

    • libraryTarget: "commonjs2" - 将库的返回值分配给module.exports。正如名字所指,这个选项可以使用在 CommonJS 环境。

      1 module.exports = _entry_return_;
      2 
      3 const myDemo = require("myDemo");
      4 myDemo();

      注意,在这个情况下output.library不是必须的,因为此时output.library选项将会被忽略。

      有没有注意到 CommonJS 和 CommonJS2 长的非常像?他们确实很相似,但是其中有微妙的区别,想了解更多可以参考这个issue

    • libraryTarget: "amd" - 这个选项会把库作为 AMD 模块导出。
      AMD模块要求输入脚本(例如由<script>标签加载的第一个脚本)被定义为具有特定属性,例如通常由 RequireJS 或任何兼容的加载器(诸如almond)提供的requiredefine属性。否则,直接加载生成的 AMD 捆绑包将导致类似define is not defined的错误。
      由此定义生成的代码会如下:

      1 define("myDemo", [], function() {
      2 return _entry_return_;
      3 });

      以上的代码可以作为script标签引入代码的一部分被包含,然后在通过以下代码调用:

      1 require(['myDemo'], function(myDemo) {
      2 // Do something with the library...
      3 myDemo();
      4 });

      如果output.library没有定义有效值,那么生成的代码将如下:

      1 define([], function() {
      2 return _entry_return_;
      3 });

      如果直接使用<script>标签加载,该库将无法按预期生效,或者根本无法生效(在 almond 加载器的情况下)。它只能通过与 RequireJS 兼容的异步模块加载器通过该文件的实际路径进行引入,因此在这种情况下,如果这些由服务器直接提供,那么output.pathoutput.filename配置可能变得非常重要。

    • libraryTarget: "umd" - 这个选项会尝试把库暴露给前使用的模块定义系统,这使其和CommonJSAMD兼容或者暴露为全局变量。
      output.library 选项在这里是必须的。最终代码输出如下:

       1 (function webpackUniversalModuleDefinition(root, factory) {
       2 if(typeof exports === 'object' && typeof module === 'object')
       3   module.exports = factory();
       4 else if(typeof define === 'function' && define.amd)
       5   define([], factory);
       6 else if(typeof exports === 'object')
       7   exports["MyLibrary"] = factory();
       8 else
       9   root["MyLibrary"] = factory();
      10 })(typeof self !== 'undefined' ? self : this, function() {
      11 return _entry_return_;
      12 });

      如果 output.library 没有输入有效值,那么对于全局变量的处理会和上面提到的 暴露一个变量 一致。代码输出如下:

       1 (function webpackUniversalModuleDefinition(root, factory) {
       2 if(typeof exports === 'object' && typeof module === 'object')
       3   module.exports = factory();
       4 else if(typeof define === 'function' && define.amd)
       5   define([], factory);
       6 else {
       7   var a = factory();
       8   for(var i in a) (typeof exports === 'object' ? exports : root)[i] = a[i];
       9 }
      10 })(this, function() {
      11 return _entry_return_;
      12 });

      从 webpack 3.10.0 版本开始,我们可以通过把 output.library 定义为对象来控制不同目标环境的输出值。详情可参考这个Demo

      1 output: {
      2 library: {
      3   root: "myDemo",
      4   amd: "my-demo",
      5   commonjs: "my-common-demo"
      6 },
      7 libraryTarget: "umd"
      8 }

    其他类型

    • libraryTarget: "jsonp" - 这个方法会使用 jsonp 的方式把结果包裹起来。
      js
      myDemo(_entry_return_);

      库的依赖由 externals 定义。

    总结

    以上所有栗子可以下载 webpack-libraryTarget-demo 项目,运行 npm i 安装依赖,接着 npm run build-all 命令执行打包,最后在 dist 目录下查看不同打包方式生成的代码。

    • 主要看第一行
    • (function(modules) { // webpackBootstrap 这一行开始,指代上述的 _entry_return_ 部分

    output.libraryTarget一共支持的值:

    1. var - 默认值
    2. assign
    3. this
    4. window
    5. global
    6. commonjs
    7. commonjs2
    8. amd
    9. umd
    10. jsonp
  • 【推广】 阿里云小站-上云优惠聚集地(新老客户同享)更有每天限时秒杀!
    【推广】 云服务器低至0.95折 1核2G ECS云服务器8.1元/月
    【推广】 阿里云老用户升级四重礼遇享6.5折限时折扣!
  • 原文:https://www.cnblogs.com/h2zZhou/p/12986221.html
走看看 - 开发者的网上家园