Webpack組織モジュールの原理-externalモジュール

5088 ワード

この記事では、Webpackがlibraryをパッケージ化する際によく使用するオプションexternalについて説明します.これは、一般的なモジュールをパブリッシュしたlibraryにパッケージ化するのを避けるために使用されます.externalと宣言するモジュールを選択します.libraryが上位層で使用された後、最後段でWebpackがこのexternalの依存モジュールを統一的にパッケージ化します.externalオプションは一般的にlibraryのパッケージに使用されますが、libraryではなく最終的なappのパブリケーションJSファイルであれば、externalも意味がありません.Webpackパッケージlibraryの分析といくつかのオプションの役割について、前の文章で議論しました.

externalオプション


前の記事の例を使用して、ライブラリutil.jsを定義します.
import $ from 'jquery'

function hideImages() {
  $('img').hide();
}

export default {
  "hideImages": hideImages
}

Webpackパッケージを使用してこのライブラリを公開します.
//  
entry: {
  util: './util.js',
}

//  
output: {
  path: './dist',
  filename: '[name].dist.js'

  library: 'util',
  libraryTarget: commonjs2,
  targetExport: 'default'
}

このようにパッケージされたutil.dist.jsファイルは、ソースコードが使用されているため、jqueryのコードを完全に注入します.しかし、これは往々にして私たちが望んでいないため、jqueryは汎用的なモジュールであり、1つのappでは、他のライブラリもそれを使用する可能性が高い.最上位のエントリファイルappもそれを使用する可能性がある.各ライブラリモジュールのリリースバージョンがjqueryをそのまま自分のbundleにパッケージし、最後につづると、最終的なappリリースコードにはjqueryのコピーがたくさんある.もちろん、通常の機能には影響しませんが、コードボリュームが大きくなります.
したがって、通常、ライブラリがjquerybootstrapのような汎用JSモジュールに依存する必要がある場合、bundleにパッケージ化するのではなく、Webpackの構成でexternalを宣言することができます.
externals: {
  jquery: {
    root: 'jquery',
    commonjs: 'jquery',
    commonjs2: 'jquery',
    amd: 'jquery',
  },
},

これはWebpackに教えています:このモジュールをコンパイルしたJSファイルに注入しないでください.私のソースコードに現れたimport/requireというモジュールの文に対して、それを残してください.
コンパイルされたbundleファイルの構造を見てみましょう.
module.exports = (function(modules) {
  var installedModules = {};
  function webpack_require(moduleId) {
     // ...
  }
  return webpack_require('./util.js');
}) ({
  './util.js': generated_util,
  // '/path/to/jquery.js': generated_jquery  , 。
});
jqueryモジュールはbundleファイルにパッケージ化されていないが、utilの場合、その生成コードであるgenerated_util関数のimport jqueryに関連する文も元の意味を保持していることがわかる.
function generated_util(module, exports, webpack_require) {
  var $ = require('jquery');
  // util 
  // ...
}

もちろん、完全に修正されていないわけではありません.例えば、importを伝統的なrequireキーワードに戻しました.ここではCommonJSスタイルのパッケージ方式を使っていますから.しかし、これらは二次的であり、重要なのはrequireというキーワードを保持し、webpack_requireを使用してjqueryを本当に導入しないことです.つまり、現在のJSファイルのモジュール管理システムにはjqueryはありません.これはexternalのモジュールであり、このJSファイルが他の人に引用され、上層部でコンパイルされる必要がある場合、jqueryが本当に導入される可能性があります.そのとき、ここのrequireキーワードはwebpack_requireに置き換えられます.
externalの依存モジュールでは、npmを使用してライブラリをパブリッシュするなど、通常はこのようにすることができます.jqueryをpackage.jsonファイルにdependencies追加することができます.これにより、他の人のnpm installがパブリッシュしたライブラリの場合、jqueryはnode_に自動的にダウンロードされます.modulesは他の人にパッケージして使用されます.
umd形式でのパッケージumd形式でパッケージ化すると、externalモジュールがどのように機能しているかがわかります.
(function webpackUniversalModuleDefinition(root, factory) {
  if(typeof exports === 'object' && typeof module === 'object')  // commonjs2
    module.exports = factory(require('jquery'));
  else if(typeof define === 'function' && define.amd)
    define("util", ['jquery'], factory);  // amd
  else if(typeof exports === 'object')
    exports["util"] = factory(require('jquery'));  // commonjs
  else
    root["util"] = factory(root['jquery']);  // var
}) (window, function(__webpack_external_module_jquery__) {
  return (function(modules) {
    var installedModules = {};
    function webpack_require(moduleId) {
       // ...
    }
    return webpack_require('./util.js');
  }) ({
    './util.js': generated_util,
  });
}
generated_utilもそれに応じてパラメータ__webpack_external_module_jquery__を追加する.
function generated_util(module, exports, webpack_require,
                        __webpack_external_module_jquery__) {
  var $ = __webpack_external_module_jquery__;
  // util 
  // ...
}

このような書き方は、上記のCommonJSのコンパイルバージョンとは構造が異なるようですが、実際には本質は同じです.現在umdは異なる運転環境に配慮しているため、require('jquery')をfactoryのパラメータとして早める.実行環境ごとに、それぞれの方法があります.
  • CommonJS:require('jquery')文を保持します.
  • AMD:defineにおいてjqueryを依存モジュールとして定義する.
  • Var:jquery変数を全ローカルドメインから取り出します.これには、jqueryがモジュールの前にロードされている必要があります.

  • いずれの場合も、ロードされたjqueryモジュールをパラメータとしてfactory関数に入力し、utilモジュールを正しくロードすることができます.
    Webpackがコードを生成する部分については、少し迂回しているかもしれませんが、Webpackパッケージモジュールのメカニズムと原理を比較する必要があります.この部分については、この文章で詳しく議論しました.

    まとめ


    以上,Webpackのexternalオプションの使用について述べ,コンパイル後のJSコードからどのように機能しているのかを解析した.Webpack関連の生成コードを読むことが大切だと思います.そうすれば、externalのメカニズムを本当に理解し、いくつかの穴にぶつかったときにdebugに行く方法を知ることができます.