web-dev-qa-db-ja.com

複数のgrunt-browserifyバンドルで相対パスエイリアシングを管理するにはどうすればよいですか?

これは少し長いですが、混乱を説明するためにコード例を必要とします。その後、私は次の答えに興味があります:

  1. require('module')またはrequire('../../src/module')の代わりにrequire('./module')を使用するにはどうすればよいですか?
  2. 作業を複製せずに_./index.js_を_spec/specs.js_で再利用するにはどうすればよいですか? (および_src/app.js_がエントリモジュールであるため実行されないようにします)。

私はすでにいくつかのブラウザベースのプロジェクトを始めており、 browserify とうなり声が大好きです。しかし、各プロジェクトは、私の開発/学習曲線の同じ時点で死にます。ミックスにテストを追加し、2つの browserify バンドル(_app.js_および_spec/specs.js_)を管理する必要があると、システム全体がバラバラになります。私が説明します:

grunt-browserify を使用して、初期ディレクトリを設定します。

_.
├── Gruntfile.js
├── index.js  (generated via grunt-browserify)      [1]
├── lib
│   ├── jquery
│   │   └── jquery.js                               [2]
│   └── jquery-ui
│       └── jquery-ui.js                            [3]
├── spec
│   ├── specs.js  (generated via grunt-browserify)  [4]
│   └── src
│       ├── spec_helper.js  (entry)
│       └── module_spec.js  (entry)
└── src
    ├── app.js  (entry)
    └── module.js
_
  1. 1つのエントリファイル(_src/app.js_)を使用し、すべてのrequiredモジュールをバンドルするコードウォークを実行します。
  2. Browserify-shimを使用して、jqueryをエイリアスします。
  3. シムなしで_jquery-ui_にエイリアスされているだけです(var $ = require('jquery')の後に必要です)。
  4. _spec/src_内のすべてのヘルパーファイルと仕様ファイルをエントリモジュールとして使用します。

設定をステップスルーします:

_browserify: {
  dist: {
    files: {
      'index.js': ['src/app.js']
    }
  }
}

// in app.js
var MyModule = require('./module'); // <-- relative path required?!
_

幸せ

次にjqueryを追加します。

_browserify: {
  options: {
    shim: {
      jquery: {
        path: 'lib/jquery/jquery.js',
        exports: '$'
      }
    },
    noParse: ['lib/**/*.js'],
    alias: [
      'lib/jquery-ui/jquery-ui.js:jquery-ui'
    ]
  },
  dist: {
    files: {
      'index.js': ['src/app.js']
    }
  }
}

// in app.js
var $ = require('jquery');
require('jquery-ui');
var MyModule = require('./module');
_

幸せ

仕様を追加します。

_options: {
  shim: {
    jquery: {
      path: 'lib/jquery/jquery.js',
      exports: '$'
    }
  },
  noParse: ['lib/**/*.js'],
  alias: [
    'lib/jquery-ui/jquery-ui.js:jquery-ui'
  ]
},
dist: {
  files: {
    'app.js': 'src/app.js'
  }
},
spec: {
  files: {
    'spec/specs.js': ['spec/src/**/*helper.js', 'spec/src/**/*spec.js']
  }
}

// in app.js
var $ = require('jquery');
require('jquery-ui');
var MyModule = require('./module');

// in spec/src/module_spec.js
describe("MyModule", function() {
  var MyModule = require('../../src/module'); // <-- This looks like butt!!!
});
_

悲しい

まとめると:どうすれば...

  1. require('module')またはrequire('../../src/module')?の代わりにrequire('./module')を使用しますか?
  2. 作業を複製せずに_./index.js_を_spec/specs.js_で再利用しますか? (および_src/app.js_がエントリモジュールであるため実行されないようにします)。
45
Sukima

これらの答えは、プロジェクトの残りの部分がどのように設定されているかによって異なりますが、おそらく良い出発点です。また、これを実際に機能させるには、grunt-browserifyの現在のv2ベータ版を使用する必要があります(npm install grunt-browserify@2)。

1。

aliasMapping を使用して、モジュールの動的エイリアスを作成できます。わかりやすくするために、すべてのモジュールをsrc/modules/に移動します。次に、aliasMapping構成は次のようになります。

options: {
  aliasMappings: {
    cwd: 'src',
    src: ['modules/**/*.js']
  }
}

src/modules/magic/stuff.jsにモジュールがあるとします。必要な.jsファイルの場所に関係なく、次のようにモジュールを要求できます。

var magicStuff = require('modules/magic/stuff.js');

2。

これについてはわかりません。プロジェクト構造にはspec/index.jsが表示されますが、spec/specs.jsに言及しています。それらは同じファイルであるはずですか?

とにかく、あなたはどんな重複した仕事について話しているのですか? ./index.jsにはspec/index.jsとは異なるエントリファイルがあるためです。 ./index.jsspecs/を含める方法を探している場合は、テストを最初からビルドする代わりに、テストを実行する前にコピーすることができます。

4
Joni Bekenstein

簡単な答え:

最も簡単なのはbrowserifyのpathsオプションを使用することです。私はこれを数ヶ月間使用して大成功を収めました。この機能を使用するスターターキットを作成しました: https://github.com/stample/gulp-browserify-react-phonegap-starter

_var b = browserify('./app', {paths: ['./node_modules','./src/js']});
_

パス-通常のnode_modules再帰ウォークで何も見つからない場合に使用するrequire.paths配列

_src/js/modulePath/myModule.js_にファイルがある場合、どこにでもrequire("myModule")を書くことはできませんが、他のソースファイルからrequire("modulePath/myModule")を書くことができます。

廃止されたオプション?

そうではないようです!

Browserifyモジュール解決アルゴリズムは、 NodeJSの解決アルゴリズム を反映しています。したがって、Browserifyのpathsオプションは、NodeJSの_NODE_PATH_ env変数の動作のミラーです。 Browserifyの作成者(サブスタック)は、このSOトピックで、_NODE_PATH_オプションはNodeJSで非推奨であり、Browserifyでも非推奨であり、次のバージョンで削除できると主張しています。

私はこの主張に同意しません。

NODE_PATH のドキュメントを参照してください。このオプションが非推奨であることは言及されていません。しかし、サブスタックの主張の方向にある興味深い言及がまだあります:

Node_modulesフォルダーに依存関係をローカルに配置することを強くお勧めします。それらはより速く、より確実にロードされます。

この質問 は2012年にメーリングリストに投稿されました。

_Oliver Leics: is NODE_PATH deprecated? 
Ben Noordhuis (ex core NodeJS contributor): No. Why do you ask? 
_

NodeJS解決アルゴリズムで何かが削除されない場合、Browserifyからすぐに削除されるとは思わない:)

結論

pathsオプションを使用するか、公式ドキュメントおよび Browserify authorが推奨する のように_node_modules_にコードを配置できます。

個人的には、_node_modules_に独自のコードを配置するという考えは好きではありません。このフォルダー全体をソース管理の対象から外すだけだからです。私は数か月間pathsオプションを使用していますが、まったく問題はありませんでした。ビルド速度はかなり良いです。

_node_modules_内にシンボリックリンクを配置するサブスタックのソリューションは便利かもしれませんが、残念ながらここでWindowsを使用する開発者がいます...

ただし、pathsオプションを使用したくない場合があると思います:公開されているライブラリを開発する場合他のアプリに必要なNPMリポジトリ。ライブラリで相対パスの地獄を避けたいという理由だけで、これらのライブラリクライアントが特別なビルド構成をセットアップする必要は本当にありません。

別の可能なオプションは remapify を使用することです

30

エイリアスと_opts.paths_/_$NODE_PATH_についてのここでのすべての回答は、そのアプローチがnodeおよびbrowserifyのモジュールシステムの非推奨部分であり、いつでも動作を停止する可能性があるため、大きくありません。

node_modulesアルゴリズムの仕組み を学習する必要があります。これにより、ネストされた_node_modules_ディレクトリとうまく機能するようにコードを効果的に編成できます。

Browserifyハンドブックには、 ../../../../../../ .. 相対パスの問題を回避するセクションがあります。次のように要約できます。

  • 必要に応じてrequire('yourmodule')またはrequire('app/yourmodule')できるように、内部モジュラーコードを_node_modules/_または_node_modules/app_に配置します。
  • Windows以外のプラットフォーム用に開発している場合は、シンボリックリンクを使用できます。

_opts.path_/_$NODE_PATH_を使用しないでください。それはあなたのプロジェクトを作ります:

  • 暗黙の構成または環境設定に暗黙的に依存する
  • ノードとブラウザの両方で動作するのが難しい
  • nodeおよびbrowserifyでは配列パスが非推奨であるため、モジュールシステムの変更に対して脆弱です
7
substack

Sebastien Lorberが指摘しているように、絶対的な最善の方法は、browserifyの呼び出しでパイプを介してパスを設定することだと思います。

しかし、最新バージョンのbrowserifyでは(現時点では[email protected])、path変数はBrowserifyがプロセスに使用するonlyパスを格納します。そのため、paths変数を設定すると、言うまでもなく、ノードのグローバルフォルダーは除外されます。その結果、次のようなGulpタスクが必要になります。

gulp.task('reactBuild', function() {
  return gulp.src(newThemeJSX)
    .pipe(browserify({
        debug: true,
        extensions: ['.jsx', '.js', '.json'],
        transform: [reactify],
        paths: ['../base_folder/node_modules', '/usr/lib/node_modules']
    }))
    .pipe(gulp.dest(newThemeBuilt))
    .on('error', function(error) {
        console.log(error);
    });
});
1
Chronotope